我有一个带有日期列的Rails模型DailyAssignment
,并希望找到今天之后没有与DailyAssignment
相关联的第一个日期。
例如,如果我今天有一个实例,明天没有实例,后天有实例,那么这个方法明天就会返回。
如果我在Ruby中这样做,那就像是:
(Date.today..1.year.since.to_date).find do |date|
DailyAssignment.where(date: date).empty?
end
这是中等的,因为它会在找到记录后终止迭代,但有两个问题:
while
构造,我需要指定一个'结束'日期。在PostgreSQL中有一个很好的,有效的方法吗?
答案 0 :(得分:1)
如果可以,您应该使用自定义查询来搜索数据库(这些搜索在数据库中的速度要快得多)。
如果您搜索某个时间范围内的日期,则可以使用
generate_series(timestamp, timestamp, interval)
功能:
select s
from generate_series(?, ? + interval '1 year'), interval '1 day') s
left join daily_assignment on s = "date"
where "date" is null
limit 1
如果您没有真正的上限,则可以使用自联接来获取下一个免费日期:
select coalesce(
(select c."date" + interval '1 day'
from daily_assignment c
left join daily_assignment n on n."date" = c."date" + interval '1 day'
where c."date" > ? - interval '1 day'
and n."date" is null
order by c."date"
limit 1),
? + interval '1 day'
)
?标记表示今天的参数(您可能需要强制转换,具体取决于您的输入);如果您愿意,可以使用now()
代替。
P.S。:请不要使用date
作为列名,它是SQL中的保留字,并且不会告诉列本身。相反,您可以使用created_at
,updated_at
,happens_at
等甚至at_date
等名称。
答案 1 :(得分:0)
我建议在日期之间进行1次选择查询,然后循环搜索结果并将其与所选结果进行比较。
# select all dailyassignments
results = DailyAssignment.where("date >= from_date AND date <= to_date")
not_found_dates = []
(Date.today..1.year.since).find do |date|
found_assignment = results.detect {|instance| instance.date == date }
not_found_dates << date if found_assignment.nil?
end
答案 2 :(得分:0)
你可以这样试试:
def first_date_without_assignment
assignments = DailyAssignment.select('date').where('date > ?', Date.today)
return Date.tomorrow if assignments.empty?
assignment_dates = assignments.map(&:date)
date_range = (Date.tomorrow..(assignment_dates.last.advance(days: 1)).to_a
(date_range - assignment_dates).first
end
我没有对它进行测试,所以我可以输入错误的内容,但它可以正常工作。我也发现了这一点,它应该适用于postgres http://www.postgresql.org/message-id/4F96EC90.6070600@encs.concordia.ca,但是在rails中编写或者至少看起来很糟糕可能很难。