我想我可能已经发现ActiveRecord_AssociationRelation#limit
的错误,但我不确定并想知道是否有更简单的解释。我正在运行Rails 5.0.2。
假设以下型号:
class Company < ApplicationRecord
has_many :contacts
end
class Contact < ApplicationRecord
belongs_to :company
attr_accessor :engagement
end
我将首先使用此查询选择所有联系人:
contacts = Company.last.contacts.order(engagement: :desc)
这将输出以下SQL:
Company Load (1.4ms) SELECT "companies".* FROM "companies" ORDER BY "companies"."id" DESC LIMIT 1
Contact Load (36.9ms) SELECT "contacts".* FROM "contacts" WHERE "contacts"."company_id" = 94 ORDER BY "contacts"."engagement" DESC
到目前为止一切顺利。现在假设我想从关系中的前20个联系人中获取一组id。我希望返回数组中的id的顺序与它们在关系中出现的顺序相匹配。
首先我将使用pluck(:id)[0..19]
。这将返回以下内容:
contacts.pluck(:id)[0..19]
#=> [861, 862, 802, 868, 794, 1583, 1267, 1857, 1081, 1686, 1041, 1535, 1560, 1707, 1770, 1600, 1205, 2027, 1179, 1184]
接下来我尝试map(&:id)[0..19]
,毫不奇怪地返回相同的结果:
contacts.map(&:id)[0..19]
#=> [861, 862, 802, 868, 794, 1583, 1267, 1857, 1081, 1686, 1041, 1535, 1560, 1707, 1770, 1600, 1205, 2027, 1179, 1184]
最后我尝试limit(20).pluck(:id)
,它会返回意外的结果:
contacts.limit(20).pluck(:id)
(4.5ms) SELECT "contacts"."id" FROM "contacts" WHERE "contacts"."company_id" = 94 ORDER BY "contacts"."engagement" DESC LIMIT 20
#=> [861, 862, 802, 868, 794, 1686, 1081, 1857, 1267, 1600, 1583, 1357, 1560, 1041, 1535, 1201, 1707, 1770, 2075, 1937]
请注意,在前两个数组中,id的顺序相同,但是当我使用limit
时,它们会出现乱序,即使生成的SQL显然包含ORDER BY
子句。
值得注意的是,对于engagement > 0.0
的前几个联系人,ID的顺序始终是正确的。一旦engagement
的值变为0.0
,订单就会开始变化。例如,以下是这20个联系人的参与号码:
[56.0, 44.0, 3.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
有人能解释一下这里发生了什么吗?
答案 0 :(得分:1)
正如我们在评论中发现的那样,问题是当order
遇到两个具有相同engagement
值的对象时,它会排序&#34;排序&#34;它以某种特定的方式。
将附加参数传递给ORDER
子句(例如id
)会有什么帮助:
Company.last.contacts.order(engagement: :desc, id: :asc)
答案 1 :(得分:0)
这可能只是数据库选择返回结果的顺序。在SQL中,除非您指定order by
,否则无法保证订购。即使在指定的情况下,我相信在相同排序结果的块中(即在这种情况下为0.0
),也无法保证结果的排序 - 它可以是数据库认为最合适的任何顺序, /或对该特定查询有效。
如果您需要按特定顺序返回结果,那么最好将其添加为额外的order by
参数(在这种情况下为id
)
编辑:以下是关于该主题的更多讨论:How does order by clause works if two values are equal?
SELECT "contacts"."id"
和SELECT "contacts".*
使用不同的索引,这很有可能导致排序不同。