Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Rails:最后为空的顺序_Ruby On Rails_Ruby On Rails 3_Sorting_Activerecord_Null - Fatal编程技术网

Ruby on rails Rails:最后为空的顺序

Ruby on rails Rails:最后为空的顺序,ruby-on-rails,ruby-on-rails-3,sorting,activerecord,null,Ruby On Rails,Ruby On Rails 3,Sorting,Activerecord,Null,在我的Rails应用程序中,我曾多次遇到一个问题,我想知道其他人是如何解决的: 我有一些记录,其中值是可选的,所以有些记录有值,有些记录为空 如果我在某些数据库上按该列排序,空值将首先排序,在某些数据库上,空值将最后排序 例如,我有一些照片可能属于或不属于某个集合,即有些照片Collection\u id=nil,有些照片Collection\u id=1等等 如果我做了Photo.order('collection\u id desc),那么在SQLite上我最后得到空值,但在PostgreS

在我的Rails应用程序中,我曾多次遇到一个问题,我想知道其他人是如何解决的:

我有一些记录,其中值是可选的,所以有些记录有值,有些记录为空

如果我在某些数据库上按该列排序,空值将首先排序,在某些数据库上,空值将最后排序

例如,我有一些照片可能属于或不属于某个集合,即有些照片
Collection\u id=nil
,有些照片
Collection\u id=1
等等

如果我做了
Photo.order('collection\u id desc)
,那么在SQLite上我最后得到空值,但在PostgreSQL上我首先得到空值


有没有一种好的、标准的Rails方法来处理这个问题并在任何数据库中获得一致的性能?

如果您想要在数据库类型中获得一致的结果,那么您似乎必须在Ruby中这样做,因为数据库本身会解释null是否位于列表的前端或末尾

Photo.all.sort {|a, b| a.collection_id.to_i <=> b.collection_id.to_i}
Photo.all.sort{a,b|a.collection_id.to|i b.collection_id.to|i}

但这不是很有效。

将数组添加到一起将保持顺序:

@nonull = Photo.where("collection_id is not null").order("collection_id desc")
@yesnull = Photo.where("collection_id is null")
@wanted = @nonull+@yesnull

我不是SQL方面的专家,但为什么不先按空值排序,然后按您希望的排序方式排序呢

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
如果您只使用PostgreSQL,也可以这样做

Photo.order('collection_id DESC NULLS LAST')  #Null's Last
Photo.order('collection_id DESC NULLS FIRST') #Null's First
如果您想要通用的东西(比如您在多个数据库中使用相同的查询),您可以使用(由@philT提供)


最简单的方法是使用:


.order('name nulls first')

减号放在列名称前面,并反转顺序方向。它在mysql上工作


虽然演出有点晚,但有一种通用的SQL方法可以做到。像往常一样,
CASE
来拯救观众

Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')

为了子孙后代的利益,我想首先强调一个与
null相关的ActiveRecord错误

如果您尝试拨打:

Model.scope_with_nulls_first.last
Rails将尝试调用
反向顺序。first
反向顺序
NULLS LAST
不兼容,因为它试图生成无效的SQL:

PG::SyntaxError: ERROR:  syntax error at or near "DESC"
LINE 1: ...dents"  ORDER BY table_column DESC NULLS LAST DESC LIMIT...
几年前,在一些仍然开放的Rails问题(,)中提到了这一点。我可以通过执行以下操作来解决这一问题:

  scope :nulls_first, -> { order("table_column IS NOT NULL") }
  scope :meaningfully_ordered, -> { nulls_first.order("table_column ASC") }
通过将两个订单链接在一起,似乎可以生成有效的SQL:

Model Load (12.0ms)  SELECT  "models".* FROM "models"  ORDER BY table_column IS NULL DESC, table_column ASC LIMIT 1
唯一的缺点是必须对每个范围进行链接


我知道这是一个旧的,但我刚刚找到了这个片段,它对我很有用。

在我的例子中,我需要按ASC按开始日期和结束日期对行进行排序,但在少数情况下,结束日期为空,并且行应该在上面,我使用


@invoice.invoice\u line.order('start\u date ASC,end\u date ASC NULLS FIRST')

即使现在是2017年,对于是否应优先使用
NULL
s仍然没有达成一致意见。如果不明确说明,结果将根据DBMS而有所不同

该标准没有规定空值与非空值相比应如何排序,除非任何两个空值被视为具有相同的顺序,并且空值的排序应高于或低于所有非空值

为了说明这个问题,我列出了几个最流行的Rails开发案例:

PostgreSQL
NULL
s的值最高

默认情况下,空值排序时好像大于任何非空值

MySQL
NULL
s的值最低

在执行“订购方式”时,如果执行“订购方式…”ASC,则首先显示空值,如果执行“订购方式…”DESC,则最后显示空值

数据库
NULL
s的值最低

具有空值的行按升序高于具有常规值的行,降序则相反

解决方案 不幸的是,Rails本身还没有提供解决方案

特定于PostgreSQL的 对于PostgreSQL,您可以非常直观地使用:

Photo.order('collection_id DESC NULLS LAST')#NULLS LAST

特定于MySQL的 对于MySQL,你可以在前面加上负号,但是这个功能似乎没有文档记录。它不仅适用于数值,也适用于日期

Photo.order('-collection_id DESC')#空值排在最后

特定于PostgreSQL和MySQL的 为了涵盖这两个方面,这似乎是可行的:

Photo.order('collection_id为NULL,collection_id DESC')#NULL最后出现

不过,这个在SQLite中不起作用

普遍解 要为所有DBMS提供交叉支持,您必须使用@PhilIT建议的
CASE
编写查询:

Photo.order('collection\u id为NULL时为1,否则为0,collection\u id')


这转换为首先按
大小写
结果对每个记录进行排序(默认情况下,升序表示
NULL
值将是最后一个值)我不喜欢这个主意,但我认为这个主意行得通。很抱歉让它开了这么久,我希望会出现一些其他答案。不过,我花了更多的时间思考这个问题,我认为这可以成为照片模型上的一种方法,这样就不会感觉太糟糕了。我很容易找到答案如果您使用的是mysql。请参阅我的解决方案。好的,我应该提到我的方法是我能找到的唯一最不可知的方法。这是一个坏主意,因为
不返回数组的地方,它返回一个ActiveRecord::Relation,将结果强制放入数组将导致所有期望标准ActiveRecord::Relation的操作失败(比如分页)。没错,尽管可用的方法不是脱离AR就是(不完全)可移植。+1,比公认的答案好得多,可以通过Arelow表达,这是一个古老的评论!所以我猜我在尝试什么
  scope :nulls_first, -> { order("table_column IS NOT NULL") }
  scope :meaningfully_ordered, -> { nulls_first.order("table_column ASC") }
Model Load (12.0ms)  SELECT  "models".* FROM "models"  ORDER BY table_column IS NULL DESC, table_column ASC LIMIT 1
Photo.order('collection_id DESC NULLS LAST')