当前日期之后的最早日期,没有相关记录

时间:2015-02-03 21:28:52

标签: ruby-on-rails ruby postgresql

我有一个带有日期列的Rails模型DailyAssignment,并希望找到今天之后没有与DailyAssignment相关联的第一个日期。

例如,如果我今天有一个实例,明天没有实例,后天有实例,那么这个方法明天就会返回。

如果我在Ruby中这样做,那就像是:

(Date.today..1.year.since.to_date).find do |date|
  DailyAssignment.where(date: date).empty?
end

这是中等的,因为它会在找到记录后终止迭代,但有两个问题:

  1. 在Ruby中迭代一个集合很慢。
  2. 除非某种while构造,我需要指定一个'结束'日期。
  3. 在PostgreSQL中有一个很好的,有效的方法吗?

3 个答案:

答案 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_atupdated_athappens_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中编写或者至少看起来很糟糕可能很难。