为什么这两个查询以不同的顺序检索记录?

时间:2016-12-23 05:48:52

标签: ruby-on-rails postgresql activerecord ruby-on-rails-5

我的Profile可以是publishedprofile belongs_to :userhas_many :ratings

User has_one :profile

has_many :ratingsRating belongs_to :profile && belongs_to :user

A Profile.rb

这些是上述模型的模式:

# == Schema Information # # Table name: profiles # # id :integer not null, primary key # first_name :string # last_name :string # created_at :datetime not null # updated_at :datetime not null # user_id :integer

User.rb

# == Schema Information # # Table name: users # # id :integer not null, primary key # email :string default(""), not null # created_at :datetime not null # updated_at :datetime not null # first_name :string # last_name :string

Rating.rb

# == Schema Information # # Table name: ratings # # id :integer not null, primary key # speed :integer default(0) # passing :integer default(0) # tackling :integer default(0) # dribbling :integer default(0) # profile_id :integer # user_id :integer # created_at :datetime not null # updated_at :datetime not null #

coach = User.find(7)

请注意>p = Profile.published.where(id: coach.ratings.order(passing: :desc).pluck(:profile_id)) (0.4ms) SELECT "ratings"."profile_id" FROM "ratings" WHERE "ratings"."user_id" = $1 ORDER BY "ratings"."passing" DESC [["user_id", 7]] Profile Load (1.1ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."status" = $1 AND "profiles"."id" IN (52, 14, 24, 29) [["status", 1]] > p.ids => [24, 14, 52]

当我执行此查询时:

profile.ids

请注意p.ids生成的> coach.ratings.order(passing: :desc).limit(3).pluck(:profile_id) (0.8ms) SELECT "ratings"."profile_id" FROM "ratings" WHERE "ratings"."user_id" = $1 ORDER BY "ratings"."passing" DESC LIMIT $2 [["user_id", 7], ["LIMIT", 3]] => [52, 14, 24] 的顺序。

但是,当我只是自己运行内部查询时,我会得到一个不同的顺序:

[19] pry(main)> cids = coach.ratings.order(passing: :desc).limit(3).pluck(:profile_id)
   (0.7ms)  SELECT  "ratings"."profile_id" FROM "ratings" WHERE "ratings"."user_id" = $1 ORDER BY "ratings"."passing" DESC LIMIT $2  [["user_id", 7], ["LIMIT", 3]]
=> [52, 14, 24]
[21] pry(main)> q = Profile.published.where(id: cids)
  Profile Load (0.7ms)  SELECT "profiles".* FROM "profiles" WHERE "profiles"."status" = $1 AND "profiles"."id" IN (52, 14, 24)  [["status", 1]]
[22] pry(main)> q.ids
=> [24, 14, 52]

导致这种差异的原因是什么,为什么我不能得到第一个查询以始终产生我对后一个查询所期望的相同结果?

修改1

请注意,即使我在第一个查询中对ID的顺序进行硬编码,它仍然会按原始顺序返回结果:

joins

修改2

当我尝试以下profiles查询时,它会返回违反published状态的status: :unpublished(当它不应该返回时,会返回> a = Profile.joins(:ratings).where(status: :published, id: coach.ratings.pluck(:profile_id)).order('ratings.passing DESC') (0.4ms) SELECT "ratings"."profile_id" FROM "ratings" WHERE "ratings"."user_id" = $1 [["user_id", 7]] Profile Load (1.8ms) SELECT "profiles".* FROM "profiles" INNER JOIN "ratings" ON "ratings"."profile_id" = "profiles"."id" WHERE "profiles"."status" = $1 AND "profiles"."id" IN (24, 52, 29, 14) ORDER BY ratings.passing DESC [["status", 1]] > o = Profile.find(29) Profile Load (0.8ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."id" = $1 LIMIT $2 [["id", 29], ["LIMIT", 1]] [59] pry(main)> o.status => "unpublished" > a.ids => [52, 14, 24, 14, 24] 的个人资料):< / p>

PG::InvalidColumnReference: ERROR:  for SELECT DISTINCT, ORDER BY expressions must appear in select list
LINE 1: ... AND "profiles"."id" IN (24, 52, 29, 14) ORDER BY ratings.pa...
                                                             ^
: SELECT DISTINCT "profiles".* FROM "profiles" INNER JOIN "ratings" ON "ratings"."profile_id" = "profiles"."id" WHERE "profiles"."status" = $1 AND "profiles"."id" IN (24, 52, 29, 14) ORDER BY ratings.passing DESC

编辑3

来自上述查询的服务器出错:

@profiles

编辑3a

当我尝试从错误页面的REPL访问>> @profiles !! #<ActiveRecord::StatementInvalid: PG::InvalidColumnReference: ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list LINE 1: ... AND "profiles"."id" IN (24, 52, 29, 14) ORDER BY ratings.pa... ^ : SELECT DISTINCT "profiles".* FROM "profiles" INNER JOIN "ratings" ON "ratings"."profile_id" = "profiles"."id" WHERE "profiles"."status" = $1 AND "profiles"."id" IN (24, 52, 29, 14) ORDER BY ratings.passing DESC> >> 时,这就是我得到的:

application/x-www-form-urlencoded

2 个答案:

答案 0 :(得分:2)

原因是where查询不会根据输入的顺序返回记录。因此where内的ID排序不会影响结果。如果您想在p中订购记录,则应在order查询后链接where。试试这个:

Profile.published.joins(:ratings).where(id: coach.ratings.pluck(:profile_id)).order('ratings.speed')

按OP编辑

所以原因是正确的,但修复不正确。

我终于通过另一种方式问这个问题找到了解决方案,I got an answer。但为了完整起见,我在这里添加答案:

Profile.published
  .joins(:ratings)
  .where(ratings: { user_id: coach.id } )
  .order('ratings.passing')

答案 1 :(得分:2)

第一个查询的顺序不确定将第一个查询的结果用作选择器的第二个查询的顺序。选择并不意味着订购。

用你的例子来解释:

coach_rating_profile_ids = coach.ratings.pluck(:profile_id)
profiles = Profile.where(id: coach_rating_profile_ids)

coach_rating_profile_ids中的ID可以是任何顺序,并且不会影响所选Profile个对象的排序。您可以轻松地尝试coach_rating_profile_ids的排序来查看。例如:

profiles = Profile.where(id: coach_rating_profile_ids.reverse)

将给出相同的结果(假设没有发生其他交易)。

如果要在所选的“个人档案”集中设置特定顺序,则必须在其上使用明确的.order()(而不是id选择器上)。例如:

profiles = Profile.where(id: coach_rating_profile_ids).order(xxxx)

其中xxxx是某种排序标准。