Mysql 在相关模型| Ruby on Rails中查找日期范围内的差距
鉴于以下模型:Mysql 在相关模型| Ruby on Rails中查找日期范围内的差距,mysql,ruby-on-rails,activerecord,Mysql,Ruby On Rails,Activerecord,鉴于以下模型: class Room < ActiveRecord::Base has_many :contracts end class Contracts < ActiveRecord::Base # columns # start_date Date # end_date Date belongs_to :room end 额外的一轮是可以搜索具有特定日期范围的间隙,或者更好地将所有间隙提取为哈希或数组中的日期范围 gaps = Room.cont
class Room < ActiveRecord::Base
has_many :contracts
end
class Contracts < ActiveRecord::Base
# columns
# start_date Date
# end_date Date
belongs_to :room
end
额外的一轮是可以搜索具有特定日期范围的间隙,或者更好地将所有间隙提取为哈希或数组中的日期范围
gaps = Room.contract_gaps
gaps # {1 => [((1month.since+1.day)..(2.months.since-1.day))]}
我已经通过谷歌搜索并找到了。但老实说,我没有一个真正的想法,如何在这个具体的案例中使用它
如果有人能找到解决这个问题的方法或一些有用的提示,那就太好了。我认为您希望将此作为一种实例方法,找出给定房间的第一份合同开始与最后一份合同结束之间的差距。作为对“奖金”的回应,是一个类方法,它将所有的奖金都收集起来。以下是它们,以及用于获取一组合同的日期范围的助手方法:
class Room < ActiveRecord::Base
has_many :contracts
# This method gets our date range
def date_range contract_list=[]
sorted = contract_list.sort{|a,b| a.start_date <=> b.start_date}
Array(sorted.first.start_date..sorted.last.end_date
end
# This version runs when called on the class itself
def contract_gaps
room_hash = {}
Room.all.each{|room| room_hash[room] = room.contract_gaps}
room_hash
end
# This version runs when called on a single room
def contract_gaps(start=nil, end=nil)
all_dates = self.class.date_range self.contracts
on_dates = []
sorted_contracts.each{|c| on_dates << Array(c.start_date..c.end_date)}
all_dates - on_dates
end
end
这将返回一个数组,其中包含合同未涵盖的所有日期。或者调用class方法来获取房间和范围的哈希值。如果您只需要有合同间隙的房间,您可以进行如下选择(未测试): 基本上,我们正在寻找具有多个合同的房间,这些合同的开始日期与该房间另一个合同的结束日期不相同(假设开始日期-结束日期范围为包含-排除) 要选择间隙,我可能会这样做(同样,未测试):
contracts=room.contracts.all(:order=>'start\u date ASC')
差距=[]
合约[0..-2]。每个带有_索引的|合约,idx|
开始日期=合同。结束日期
结束日期=合同[idx+1]。开始日期
差距最快的方法是使用SQL查询查找差距。然而,这将很复杂,并且不能很好地映射到ActiveRecord模型,因此我能想到的下一个最快的方法是在数据库中按时间顺序排序合同,并在Ruby中查找差距,迭代每个结果,并在遇到房间和日期时将它们附加到数组中
然而,如果您需要更快地访问间隙,或者您正在进行大量间隙操纵,或者如果这些间隙在某种意义上是正在销售的“产品”,那么您最好使用不同的模型。一个时段
,即最短可能的合同期限(例如,一个月)怎么样?在接下来的几年里,你会为每个房间和每个月都创建插槽。每一个都有slot.available==true
开始,并且after\u save
调用Contract
模型集available=false
(如有必要)。通过此设置,您可以更轻松地定义间隙查找器(Room.With\u available\u slot
):
class Contract < ActiveRecord::Base
has_many :slots
end
class Slot < ActiveRecord::Base
belongs_to :room
belongs_to :contract
end
class Room < ActiveRecord::Base
has_many :slots
has_many :contracts, :through => :slots
named_scope :with_available_slots,
:joins => :slots,
:conditions => {:slots => {:contract_id => nil}},
:select => "*, COUNT(*) AS num_slots",
:group => "room_id",
:having => "num_slots > 0"
end
classcontract:插槽
命名的\u作用域:具有可用的\u插槽,
:joins=>:插槽,
:conditions=>{:slots=>{:contract_id=>nil},
:select=>“*,将(*)计数为num_插槽”,
:group=>“房间id”,
:having=>“num_slots>0”
结束
此设计还具有其他有用的功能,如防止预订某些日期、对某些时段应用不同的定价等。它不像您的设计那样干净,但根据我的经验,它在处理真实数据时效果更好,因为异常更容易处理。嗨,Alex,谢谢您的回复。我喜欢你的吃角子老虎机的主意。您是否有一个快速示例,说明如何在不迭代所有结果的情况下找到例如3个连续的可用插槽?
room = Room.find(1)
room.contract_gaps
SELECT rooms.*, count(*) AS count_contracts FROM rooms
INNER JOIN contracts as c1 ON c1.room_id = rooms.id
OUTER JOIN contracts as c2 ON c1.start_date = c2.end_date AND c2.room_id = rooms.id
WHERE c2.id IS NULL
GROUP BY rooms.id HAVING count_contracts > 1
contracts = room.contracts.all(:order => 'start_date ASC')
gaps = []
contracts[0..-2].each_with_index do |contract, idx|
start_date = contract.end_date
end_date = contracts[idx+1].start_date
gaps << (start_date..end_date) if start_date != end_date
end
class Contract < ActiveRecord::Base
has_many :slots
end
class Slot < ActiveRecord::Base
belongs_to :room
belongs_to :contract
end
class Room < ActiveRecord::Base
has_many :slots
has_many :contracts, :through => :slots
named_scope :with_available_slots,
:joins => :slots,
:conditions => {:slots => {:contract_id => nil}},
:select => "*, COUNT(*) AS num_slots",
:group => "room_id",
:having => "num_slots > 0"
end