And*_*rew 77 sorting null activerecord ruby-on-rails ruby-on-rails-3
在我的Rails应用程序中,我遇到了几次问题,我想知道其他人如何解决:
我有一些值是可选的记录,所以有些记录有一个值,有些记录的值为null.
如果我在某些数据库上按该列排序,则首先对空值进行排序,在某些数据库上对空值进行排序.
例如,我有照片可能属于或可能不属于集合,即有一些照片在哪里collection_id=nil
和一些在哪里collection_id=1
等.
如果我Photo.order('collection_id desc)
在SQLite上做的话我最后得到空值但是在PostgreSQL上我先得到空值.
是否有一个很好的标准Rails方法来处理这个并在任何数据库中获得一致的性能?
Int*_*tss 247
我不是SQL的专家,但为什么不先排序,如果某事先是null,那么按你想要的排序方式排序.
Photo.order('collection_id IS NULL, collection_id DESC') # Null's last
Photo.order('collection_id IS NOT NULL, collection_id DESC') # Null's first
Run Code Online (Sandbox Code Playgroud)
如果您只使用PostgreSQL,您也可以这样做
Photo.order('collection_id DESC NULLS LAST') #Null's Last
Photo.order('collection_id DESC NULLS FIRST') #Null's First
Run Code Online (Sandbox Code Playgroud)
如果你想要一些通用的东西(比如你在几个数据库中使用相同的查询,你可以使用(由@philT提供)
Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')
Run Code Online (Sandbox Code Playgroud)
Ada*_*bik 31
即使现在是2017年,关于NULL
s 是否应该优先,仍然尚未达成共识.如果没有明确说明,您的结果将根据DBMS而有所不同.
该标准没有指定与非NULL值相比应该如何排序NULL,除了要将任何两个NULL视为等同排序,并且NULL应该在所有非NULL值之上或之下排序.
为了说明这个问题,我在Rails开发时编制了一些最常见的案例列表:
NULL
s具有最高价值.
默认情况下,null值排序为大于任何非null值.
NULL
s的价值最低.
在执行ORDER BY时,如果您执行ORDER BY ... ASC,则首先显示NULL值,如果执行ORDER BY ... DESC,则返回最后一个值.
NULL
s的价值最低.
具有NULL值的行高于具有常规值的行按升序排列,并且按降序顺序颠倒.
不幸的是,Rails本身并没有为它提供解决方案.
对于PostgreSQL,您可以非常直观地使用:
Photo.order('collection_id DESC NULLS LAST') # NULLs come last
对于MySQL,您可以预先设置减号,但此功能似乎没有记录.似乎不仅可以使用数值,还可以使用日期.
Photo.order('-collection_id DESC') # NULLs come last
为了覆盖它们,这似乎有效:
Photo.order('collection_id IS NULL, collection_id DESC') # NULLs come last
不过,这个在SQLite中不起作用.
要为所有DBMS提供交叉支持,您必须使用CASE
@PhilIT建议的查询:
Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')
这意味着首先按CASE
结果对每个记录进行排序(默认为升序,这意味着NULL
值将是最后一个),其次是calculation_id
.
ray*_*ibi 12
在column_name前放置减号并反转订单方向.它适用于mysql.更多细节
Product.order('something_date ASC') # NULLS came first
Product.order('-something_date DESC') # NULLS came last
Run Code Online (Sandbox Code Playgroud)
Tho*_*cey 12
Photo.order('collection_id DESC NULLS LAST')
Run Code Online (Sandbox Code Playgroud)
我知道这是一个旧的,但我刚刚找到这个片段,它对我有用.
Rails 6.1向 Arel for PostgreSQL添加了nulls_first和nulls_last方法。
例子:
User.order(User.arel_table[:login_count].desc.nulls_last)
Run Code Online (Sandbox Code Playgroud)
来源:https://www.bigbinary.com/blog/rails-6-1-adds-nulls-first-and-nulls-last-to-arel
在节目的后期,但有一个通用的SQL方法来做到这一点.像往常一样,CASE
去救援.
Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')
Run Code Online (Sandbox Code Playgroud)
为了后人的缘故,我想突出显示与ActiveRecord相关的错误NULLS FIRST
.
如果你试着打电话:
Model.scope_with_nulls_first.last
Run Code Online (Sandbox Code Playgroud)
Rails尝试生成无效的SQL时会尝试调用reverse_order.first
,但reverse_order
不兼容NULLS LAST
:
PG::SyntaxError: ERROR: syntax error at or near "DESC"
LINE 1: ...dents" ORDER BY table_column DESC NULLS LAST DESC LIMIT...
Run Code Online (Sandbox Code Playgroud)
这是几年前在一些仍然开放的Rails问题(一,二,三)中引用的.通过执行以下操作,我能够解决它:
scope :nulls_first, -> { order("table_column IS NOT NULL") }
scope :meaningfully_ordered, -> { nulls_first.order("table_column ASC") }
Run Code Online (Sandbox Code Playgroud)
似乎通过将两个订单链接在一起,生成了有效的SQL:
Model Load (12.0ms) SELECT "models".* FROM "models" ORDER BY table_column IS NULL DESC, table_column ASC LIMIT 1
Run Code Online (Sandbox Code Playgroud)
唯一的缺点是必须为每个范围进行链接.
Eri*_*ric -4
将数组添加在一起将保持顺序:
@nonull = Photo.where("collection_id is not null").order("collection_id desc")
@yesnull = Photo.where("collection_id is null")
@wanted = @nonull+@yesnull
Run Code Online (Sandbox Code Playgroud)
http://www.ruby-doc.org/core/classes/Array.html#M000271