我在Rails 4上并且在begin_date:date
模型上拥有Project
属性。我使用ActiveRecord,当nil
值为User.first.projects.order(begin_date: :desc, end_date: :desc)
时,以下请求会在Postgres与SQLite上返回不同的结果:
nil
在Postgres nil
中,值被视为高于现有值(因此首先出现),而在SQLite中,nil
值的值最后。
我做错了什么或这是预期的行为?
我如何重构上述查询,以便在Postgres和SQLite上呈现相同的结果(关于{{1}}值)?
PS。如果您有强烈的意见,我应该在所有环境中使用相同的数据库技术:我感谢您的考虑,但我知道这一点,这个问题不是关于该主题。
答案 0 :(得分:3)
由于数据库的默认行为不同,因此您需要明确指定NULL
的处理。
有几种方法可以执行此操作,但最便携似乎在ORDER BY DATE showing NULLS first then most recent dates和SQL 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。
另一种方法是使用将null转换为非null的表达式进行排序。我不确定这方面的SQL标准在ISNULL
,NVL
,IFNULL
和COALESCE
方面是什么,或者甚至哪个都是sqllite和postgres的。
This recent thread讨论了Rails中缺少(和需要)一种机制来通过order
来支持这一点。