您可以在 Rails 3 搜索中对日期进行比较吗?

Posted

技术标签:

【中文标题】您可以在 Rails 3 搜索中对日期进行比较吗?【英文标题】:Can you do greater than comparison on a date in a Rails 3 search? 【发布时间】:2011-05-12 14:17:48 【问题描述】:

我在 Rails 3 中有这个搜索:

Note.where(:user_id => current_user.id, :notetype => p[:note_type], :date => p[:date]).order('date ASC, created_at ASC')

但我需要 :date => p[:date] 条件等同于 :date > p[:date]。我怎样才能做到这一点?感谢阅读。

【问题讨论】:

【参考方案1】:
Note.
  where(:user_id => current_user.id, :notetype => p[:note_type]).
  where("date > ?", p[:date]).
  order('date ASC, created_at ASC')

或者您也可以将所有内容转换为 SQL 表示法

Note.
  where("user_id = ? AND notetype = ? AND date > ?", current_user.id, p[:note_type], p[:date]).
  order('date ASC, created_at ASC')

【讨论】:

安全吗?我的意思是如果 p[:date] 来自用户输入,它会导致 SQL 注入吗? 因为where()所以很安全。使用where() 会自动转义输入。 Simone 的评论并不完全正确; where() 以上面显示的格式使用输入时自动转义输入,用问号代替变量,然后在函数调用中列出它们。以这种方式使用它是不安全的:Note.where("date > #p[:date]") 另外值得注意的是,在合并具有user_id 字段的模型的情况下,使用where("user_id = ?",current_user.id)where(user_id: current_user.id) 风险更大。使用原始 SQL 表示法意味着您需要自己包含表格说明,例如:where("notes.user_id = ?",current_user.id) 你应该小心这个,因为时区。当你使用 where with "" Rails 直接进入数据库,并且在数据库中日期以 UTC 格式保存,但你应该以 UTC + 5 为例,这是不正确的。因此,请确保在执行之前将 p[date] 转换为您当前的 UTC【参考方案2】:

如果遇到列名不明确的问题,您可以这样做:

date_field = Note.arel_table[:date]
Note.where(user_id: current_user.id, notetype: p[:note_type]).
     where(date_field.gt(p[:date])).
     order(date_field.asc(), Note.arel_table[:created_at].asc())

【讨论】:

由于某种原因,我在 PostgreSQL 服务器上使用 Simone 的“where”方法找不到列时出现错误,但它在 SQLite 中有效。你的方法对两者都有效。【参考方案3】:

你可以尝试使用:

where(date: p[:date]..Float::INFINITY)

等价于sql

WHERE (`date` >= p[:date])

结果是:

Note.where(user_id: current_user.id, notetype: p[:note_type], date: p[:date]..Float::INFINITY).order(:fecha, :created_at)

我也变了

order('date ASC, created_at ASC')

对于

order(:fecha, :created_at)

【讨论】:

【参考方案4】:

如果您不喜欢传入字符串,我更喜欢@sesperanto 的做法,除了让它更简洁之外,您可以将Float::INFINITY 放在日期范围内,而只需使用created_at: p[:date]..

Note.where(
    user_id: current_user.id,
    notetype: p[:note_type],
    created_at: p[:date]..
).order(:date, :created_at)

请注意,这会将查询更改为 >= 而不是 >。如果这是一个问题,您总是可以通过运行 p[:date] + 1.day.. 之类的东西来为日期添加一个时间单位

【讨论】:

【参考方案5】:

更新

Rails 核心团队决定暂时恢复此更改,以便更详细地讨论它。请参阅this comment 和this PR 了解更多信息。

我仅出于教育目的而留下我的答案。


Rails 6.1 中用于比较的新“语法”(已还原)

Rails 6.1where 条件下的比较运算符添加了新的“语法”,例如:

Post.where('id >': 9)
Post.where('id >=': 9)
Post.where('id <': 3)
Post.where('id <=': 3)

所以你的查询可以改写如下:

Note
  .where(user_id: current_user.id, notetype: p[:note_type], 'date >', p[:date])
  .order(date: :asc, created_at: :asc)

这里是a link to PR,您可以在其中找到更多示例。

【讨论】:

PR 已恢复,因此这在 Rails 中暂时不起作用。 new PR 目前正在进行中。 谢谢,@PaulB。我已经更新了我的答案。

以上是关于您可以在 Rails 3 搜索中对日期进行比较吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Solr中对日期字段进行排序?

如果您可以在 7 次比较中对 5 个数字进行排序,那么如何在 10 次比较中对 6 个数字进行排序?

Ruby on Rails 3 发布日期 [关闭]

Drupal 6:在 tpl.php 中对多个值进行分组

如何在 C 中的日期字符串中对字符串日期进行二进制搜索?

您可以在渲染之前从 websocket 中对图像进行下采样吗