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

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

我有一个可以发布配置文件profile belongs_to :userhas_many :ratings

一个用户有_one :profile,和has_many :ratings

A 评级 belongs_to :profile && belongs_to :user

这些是上述模型的模式:

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

用户.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]

注意 p.ids 生成的 profile.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]

是什么导致了差异?为什么我不能让第一个查询始终产生与后一个查询相同的结果?

编辑 1

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

[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]

编辑2

当我尝试以下 joins 查询时,它返回违反 published 状态的 profiles(也就是返回具有 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]

编辑3

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

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

编辑 3a

当我尝试从错误页面的 REPL 访问 @profiles 时,这是我得到的:

>> @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>
>>

最佳答案

原因是 where 查询没有按照输入的顺序返回记录。因此 where 中 id 的顺序不会影响结果。如果您想对 p 中的记录进行排序,您应该在 where 查询之后链接 order。试试这个:

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')

关于ruby-on-rails - 为什么这两个查询以不同的顺序检索记录?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41295854/

相关文章:

ruby-on-rails - shared_children 不在 Capistrano 3 中工作

ruby-on-rails - 不是公认的存储提供商(Mongoid、Carrierwave 和 S3

ruby-on-rails - 无法使用 Devise gem 在 Rails 应用程序中注销,没有路由匹配/用户/sign_out

c# - Entity Framework Core 很慢——如何让它更快?

ruby-on-rails - ActiveRecord 不保存任何属性,保存默认值

ruby-on-rails - ActiveRecord touch 导致死锁

c++ - PQprepare 和 PQexecPrepared 用法

postgresql - 更改 Postgres 中的时间戳格式

sql - 限制类别页面上产品列表中子类别的项目数量?

ruby - 我可以使用 AREL/ActiveRecord 更优雅地编写此查询吗?