所以,我的照片模型中有以下范围:
scope :best, order(:average_rating.desc)
唯一的问题是,评分是事后添加到模型中的,所以生产应用程序有很多记录,其中average_rating
为 nil。当我调用这个范围时,它首先返回所有的 nil——事实上它应该是相反的,nil 应该是最后的(它们是尚未评级的照片)。
如何将 nil 排序到此范围的末尾?
所以,我的照片模型中有以下范围:
scope :best, order(:average_rating.desc)
唯一的问题是,评分是事后添加到模型中的,所以生产应用程序有很多记录,其中average_rating
为 nil。当我调用这个范围时,它首先返回所有的 nil——事实上它应该是相反的,nil 应该是最后的(它们是尚未评级的照片)。
如何将 nil 排序到此范围的末尾?
我玩游戏有点晚了,但这又出现了,解决方案真的没那么难。
一种可移植的解决方案是使用 CASE 将 NULL 转换为将结束的东西。如果您的评级是非负的,那么 -1 是一个不错的选择:
order('case when average_rating is null then -1 else average_rating end desc')
相反,使用 COALESCE 可以在许多数据库中工作,并且比 CASE 的噪音要小得多:
order('coalesce(average_rating, -1) desc')
如果您想要 ASC 排序,那么上述方法会将 NULL 放在开头。如果你最后想要它们,那么你会使用比你的最高评级更大的东西,而不是 -1。例如,如果您从 1 到 5 对事物进行评分,则可以使用 11 来替换 NULL:
order('case when average_rating is null then 11 else average_rating end asc')
order('coalesce(average_rating, 11) asc')
大多数人会使用 10,但有时您需要大声一点,所以我们使用 11。
您不能真正依赖数据库将 NULL 放在开头或结尾,因此即使您只是提醒未来的自己您已经处理了 NULL 情况,最好还是明确说明。
尝试这个 :)
scope :best, order("average_rating DESC NULLS LAST")
我知道这是不久前的事了,但这对几个人来说不起作用
order("ISNULL(average_rating) DESC")
虽然coalesce
SQL 方法很棒,但如果您的数据库不支持此方法,这里有一个所有数据库都应支持的方法:
order("-average_rating DESC")
这将对您的记录进行排序并将其放在NULL
最后。
好吧,我从来没有找到一种可以跨数据库驱动程序工作的方法,所以我只是强制所有以前为零的记录的值为零。这为我解决了这个问题,虽然它有点野蛮。当计时器用完时,我会接受这个,因为它是我使用的解决方案,但如果有人重新审视这个并希望在未来提供替代答案,我将很乐意稍后接受不同的答案。