聚合条件 has_many Rails 关联

发布于 2024-08-22 21:42:09 字数 1705 浏览 7 评论 0原文

我不确定这是否可行,甚至更可取,

但我想构建一个 has_many 关系或一个条件named_scope 类型关系,以将我的痛苦减轻为一个简单的关系而不是两个。

目前我有两个模型,它们基本上包含相同的信息,并且通过相同的 key room_id 属于相同的模型房间,但以两种不同的方式保存数据。第一个包含特定日期的具体信息,第二个包含一周中几天的通用费率。主要障碍是,Availables 可能根本不包含特定记录的信息,在这种情况下,它需要遵循 room_rates 的平均价格,而不是给定日期的具体价格。

有什么指示或建议吗?谢谢

可用的

+--------+-------+-------+------------+---------+-----+
| id     | price | spots | bookdate   | room_id | min |
+--------+-------+-------+------------+---------+-----+
| 180315 | 14.4  | 1     | 2010-02-27 | 2517    | 1   |
| 231726 | 15.84 | 1     | 2010-03-24 | 2517    | 1   |
| 180311 | 14.4  | 1     | 2010-02-23 | 2517    | 1   |
| 180313 | 14.4  | 1     | 2010-02-25 | 2517    | 1   |
+--------+-------+-------+------------+---------+-----+

Room_rates

+-------+---------+-----------+-------+-----+
| id    | room_id | dayofweek | price | min |
+-------+---------+-----------+-------+-----+
| 87936 | 2517    | 0         | 14.58 | 1   |
| 87937 | 2517    | 1         | 14.58 | 1   |
| 87938 | 2517    | 2         | 14.52 | 1   |
| 87939 | 2517    | 3         | 14.52 | 1   |
| 87940 | 2517    | 4         | 14.52 | 1   |
| 87941 | 2517    | 5         | 14.4  | 1   |
| 87942 | 2517    | 6         | 14.63 | 1   |
+-------+---------+-----------+-------+-----+

或者可能是 finder_sql 方法?如:

  has_many :aggregates,
           :class_name => 'Available',
           :finder_sql => 'SELECT room_id, price, spots, bookdate, MIN(source) 
           FROM availables
           WHERE room_id = #{id}
           GROUP BY room_id, price, spots, bookdate'

但还需要通过加入room_rates来填写不存在的bookdates的缺失记录

I'm not sure if this is feasible or even preferable

But I'd like to build a has_many relationship or a conditional named_scope type relationship to ease my pain into one simple relationship instead of two.

Currently I have two models which basically contain the same information and belong to the same Model rooms thru the same key room_id, but hold data in two different ways. One contains specific information for a particular date and the second generic rates for days of the week. The main obstacle is that Availables may contain no information for a particular record at all, in which case it needs to defer to room_rates for average rather than specific prices for a given date.

Any pointers or suggestions? Thanks

Availables

+--------+-------+-------+------------+---------+-----+
| id     | price | spots | bookdate   | room_id | min |
+--------+-------+-------+------------+---------+-----+
| 180315 | 14.4  | 1     | 2010-02-27 | 2517    | 1   |
| 231726 | 15.84 | 1     | 2010-03-24 | 2517    | 1   |
| 180311 | 14.4  | 1     | 2010-02-23 | 2517    | 1   |
| 180313 | 14.4  | 1     | 2010-02-25 | 2517    | 1   |
+--------+-------+-------+------------+---------+-----+

Room_rates

+-------+---------+-----------+-------+-----+
| id    | room_id | dayofweek | price | min |
+-------+---------+-----------+-------+-----+
| 87936 | 2517    | 0         | 14.58 | 1   |
| 87937 | 2517    | 1         | 14.58 | 1   |
| 87938 | 2517    | 2         | 14.52 | 1   |
| 87939 | 2517    | 3         | 14.52 | 1   |
| 87940 | 2517    | 4         | 14.52 | 1   |
| 87941 | 2517    | 5         | 14.4  | 1   |
| 87942 | 2517    | 6         | 14.63 | 1   |
+-------+---------+-----------+-------+-----+

Or possibly a finder_sql method? Such as:

  has_many :aggregates,
           :class_name => 'Available',
           :finder_sql => 'SELECT room_id, price, spots, bookdate, MIN(source) 
           FROM availables
           WHERE room_id = #{id}
           GROUP BY room_id, price, spots, bookdate'

But it also needs to fill in missing records for bookdates that don't exist by joining room_rates

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

春夜浅 2024-08-29 21:42:09

您可以在一个 sql 中完成此操作。但它需要你执行相当大的 SQL。另一方面,您可以通过排序和其他好处在一个语句中获得结果。

免责声明 1:此代码是农场新鲜的、空气编码的,未经过任何有害测试。

免责声明 2:在 2010 年 2 月 25 日,availables 表中的同一房间有 2 行。我假设这是一种畸变。否则,您需要向 select 语句传递一个附加参数以进一步过滤结果。

class Available < ActiveRecord::Base  
  def self.daily_rates room_id, from_date, to_date 
    date_table = (from_date..to_date).collect do |date| 
      "(SELECT  #{room_id} AS room_id, '#{date.to_formatted_s(:db)}' AS bookdate )"
    end.join(" UNION ")

    ActiveSupport::OrderedHash.new.tap do |hash|
      Available.find_by_sql( " 
         SELECT A.bookdate, IFNULL(B.price, C.price) AS price
         FROM   (#{date_table}) A
         LEFT OUTER JOIN availables B 
                ON A.room_id = B.room_id AND A.bookdate = B.bookdate
         JOIN room_rates C 
                ON A.room_id = C.room_id AND DAYOFWEEK(A.bookdate) = C.dayofweek + 1
         ORDER BY A.bookdate ASC"
      ).each do |rate_info |
        hash[rate_info.bookdate] = rate_info.price
      end
    end
  end  

end

现在您可以拨打以下电话:

rates = Available.daily_rates(1, '2010-02-23'.to_date, '2010-02-27'.to_date)

rates.keys[0]   # Tue, 23 Feb 2010
rates.values[0] # 14.3999996185303

让我们检查 availables 表中缺少的 26 日的费率。

rates.keys[3]   # Tue, 26 Feb 2010
rates.values[3] # 14.3999996185303

You can do this in one sql. But it requires you to execute a fairly big SQL. On the other hand you get the results in one statement with sorting and other goodies.

Disclaimer 1: This code is farm fresh, air coded and not subjected any harmful testing.

Disclaimer 2: You have 2 rows for same room on date 2010-02-25 in availables table. I am assuming that is an aberration. Otherwise you need to pass an additional parameter to the select statement to filter the results further.

class Available < ActiveRecord::Base  
  def self.daily_rates room_id, from_date, to_date 
    date_table = (from_date..to_date).collect do |date| 
      "(SELECT  #{room_id} AS room_id, '#{date.to_formatted_s(:db)}' AS bookdate )"
    end.join(" UNION ")

    ActiveSupport::OrderedHash.new.tap do |hash|
      Available.find_by_sql( " 
         SELECT A.bookdate, IFNULL(B.price, C.price) AS price
         FROM   (#{date_table}) A
         LEFT OUTER JOIN availables B 
                ON A.room_id = B.room_id AND A.bookdate = B.bookdate
         JOIN room_rates C 
                ON A.room_id = C.room_id AND DAYOFWEEK(A.bookdate) = C.dayofweek + 1
         ORDER BY A.bookdate ASC"
      ).each do |rate_info |
        hash[rate_info.bookdate] = rate_info.price
      end
    end
  end  

end

Now you can make calls such as:

rates = Available.daily_rates(1, '2010-02-23'.to_date, '2010-02-27'.to_date)

rates.keys[0]   # Tue, 23 Feb 2010
rates.values[0] # 14.3999996185303

Lets check the rate for the 26th which is missing from availables table.

rates.keys[3]   # Tue, 26 Feb 2010
rates.values[3] # 14.3999996185303
碍人泪离人颜 2024-08-29 21:42:09

我只是将方法添加到房间模型中。我想您想获得特定日期的价格。

def get_price(date)
  (self.availbles.find_by_bookdate(date) || self.room_rates.find_by_dayofweek(dayofweek(date)) ).price
end

您需要将 dayofweek(date) 替换为能够提供一周中特定日期的内容。这将从 availbles 返回 price,如果没有此类行,则从 room_rates 返回。如果两行都丢失,则会出现错误。我希望它能给您一些如何解决这个问题的想法。

如果是一系列日期,我会添加另一种方法:

def get_prices(start_date, end_date)
  dates = (start_date..end_date).to_a
  prices = {}
  dates.each do |d|
    prices[:d] = get_price(d)
  end
  prices
end

它将返回带有价格的哈希值,其中日期是关键

I would just add method to Room model. I supose you want to get price for a specific day.

def get_price(date)
  (self.availbles.find_by_bookdate(date) || self.room_rates.find_by_dayofweek(dayofweek(date)) ).price
end

You need to replace dayofweek(date) with something that will give you specific day of week. This will return price from availbles and if there is no such row, then from room_rates. If both rows are missing you will have error. I hope it will give you some idea how to solve this problem.

In case of a range of dates I would add another method:

def get_prices(start_date, end_date)
  dates = (start_date..end_date).to_a
  prices = {}
  dates.each do |d|
    prices[:d] = get_price(d)
  end
  prices
end

It will return hash with prices where date is a key

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文