【问题标题】:Correcting different behaviour when ordering dates with nil value in Postgres and SQLite3 with AR在 Postgres 和带有 AR 的 SQLite3 中使用 nil 值排序日期时更正不同的行为
【发布时间】:2014-01-14 14:57:32
【问题描述】:

我在 Rails 4 上并且在 Project 模型上有一个 begin_date:date 属性。我正在使用 ActiveRecord,当有 nil 值时,以下请求在 Postgres 与 SQLite 上返回不同的结果:

User.first.projects.order(begin_date: :desc, end_date: :desc)

在 Postgres 中,nil 的值被视为比现有值更高的值(因此排在第一位),而在 SQLite 记录中,nil 的值排在最后。

  1. 我做错了什么还是这是预期的行为?

  2. 如何重构上述查询,使其在 Postgres 和 SQLite 上呈现相同的结果(关于 nil 值)?

PS。请,如果您强烈认为我应该在所有环境中使用相同的数据库技术:我感谢您的考虑,但我知道这一点,这个问题与那个主题无关。

【问题讨论】:

  • 你希望你的nulls 在哪一端?
  • 我希望它们的排名低于具有现有值的记录。

标签: ruby-on-rails sqlite postgresql activerecord ruby-on-rails-4


【解决方案1】:

由于不同数据库的默认行为不同,您需要明确指定NULL 的处理方式。

有几种方法可以做到这一点,但最可移植的似乎在ORDER BY DATE showing NULLS first then most recent datesSQL how to make null values come last when sorting ascending 中进行了描述,它们使用CASE 语句来显式处理空值的处理。

在你的情况下,它会是这样的:

order('case when begin_date is null then 1 else 0 end,
     begin_date desc, case when end_date is null then 1 else 0 end, end_date desc')

取决于您希望对空值进行排序的位置。如果您希望首先对空值进行排序,则可以交换 1 和 0。

另一种方法是通过将空值转换为非空值的表达式进行排序。我不确定在这方面的 SQL 标准是什么ISNULLNVLIFNULLCOALESCE,甚至这对于 sqllite 和 postgres 都是通用的。

This recent thread 通过order 讨论 Rails 中缺乏(并且需要)一种机制来支持这一点。

【讨论】:

  • 嗯,很有趣。而且有点难过。当涉及到按两列排序时(即如果第一个相等,则按第二个排序),您可能对我的案例有任何明确的代码建议吗?
  • 您也可以使用COALESCE(begin_date, X) 将NULL 转换为更可预测的值(当然假设存在合适的Xs)。
  • 是的,AFAIK 其他所有人都开始跟踪这件小事的标准。最后。因此,您可以在 SQLite 和 PostgreSQL(甚至 MySQL)中进行 COALESCE。
  • @muistooshort 您是否愿意详细说明在上述场景中使用COALESCE 的实现会是什么样子?
  • 它看起来像Gratzy's answer to one of the linked questions。 COALESCE 的问题在那边也注意到了。
猜你喜欢
  • 2022-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-11
  • 2018-02-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多