11

所以,我的照片模型中有以下范围:

scope :best, order(:average_rating.desc)

唯一的问题是,评分是事后添加到模型中的,所以生产应用程序有很多记录,其中average_rating为 nil。当我调用这个范围时,它首先返回所有的 nil——事实上它应该是相反的,nil 应该是最后的(它们是尚未评级的照片)。

如何将 nil 排序到此范围的末尾?

4

5 回答 5

17

我玩游戏有点晚了,但这又出现了,解决方案真的没那么难。

一种可移植的解决方案是使用 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 情况,最好还是明确说明。

于 2012-01-21T00:42:31.103 回答
10

尝试这个 :)

scope :best, order("average_rating DESC NULLS LAST")
于 2011-04-02T04:22:38.583 回答
2

我知道这是不久前的事了,但这对几个人来说不起作用

order("ISNULL(average_rating) DESC")
于 2012-01-20T22:13:53.110 回答
2

虽然coalesceSQL 方法很棒,但如果您的数据库不支持此方法,这里有一个所有数据库都应支持的方法:

order("-average_rating DESC")

这将对您的记录进行排序并将其放在NULL最后。

于 2014-02-03T15:59:47.547 回答
0

好吧,我从来没有找到一种可以跨数据库驱动程序工作的方法,所以我只是强制所有以前为零的记录的值为零。这为我解决了这个问题,虽然它有点野蛮。当计时器用完时,我会接受这个,因为它是我使用的解决方案,但如果有人重新审视这个并希望在未来提供替代答案,我将很乐意稍后接受不同的答案。

于 2011-04-03T17:41:27.297 回答