订购来自`has_many through, - >的记录{distinct}`由关联值

时间:2016-06-17 22:24:34

标签: sql ruby-on-rails postgresql activerecord

我正在使用SELECT DISTINCT并且在尝试按相关值排序结果时出现问题。以这个例子(在Rails中):

我的Cook模型具有明显的customers关联:

has_many :customers, -> { distinct }, through: :orders, source: :user

它与众不同,因为我只想算一次客户,即使他们有多个订单。

为此生成的SQL是:

> cook.customers.to_sql
=> "SELECT DISTINCT \"users\".* FROM \"users\"
 INNER JOIN \"orders\" ON \"users\".\"id\" = \"orders\".\"user_id\"
 INNER JOIN \"meals\" ON \"orders\".\"meal_id\" = \"meals\".\"id\"
 WHERE \"meals\".\"cook_id\" = 1"

这很好用! (orders表通过meals关联,但可以随意忽略)

我想按照这些客户的订单的最新created_at值来订购此客户列表。但是当我这样做时,我收到一个错误:

cook.customers.order('orders.created_at DESC').to_sql
=> "SELECT DISTINCT \"users\".* FROM \"users\"
    INNER JOIN \"orders\" ON \"users\".\"id\" = \"orders\".\"user_id\"
    INNER JOIN \"meals\" ON \"orders\".\"meal_id\" = \"meals\".\"id        \"WHERE \"meals\".\"cook_id\" = 1  ORDER BY orders.created_at DESC"
  > cook.customers.order('orders.created_at DESC')
  ActiveRecord::StatementInvalid: PG::InvalidColumnReference: ERROR:  for SELECT DISTINCT, ORDER BY expressions must appear in select list
  LINE 1: ...eals"."id" WHERE "meals"."cook_id" = $1  ORDER BY orders.cre...

即使我明确地加入了表格(因为has_many through而不认为我应该这样做),这仍然无效。

cook.customers.joins(:orders).order('orders.created_at DESC').to_sql
=> "SELECT DISTINCT \"users\".* FROM \"users\" INNER JOIN \"orders\" \"orders_users\" ON \"orders_users\".\"user_id\" = \"users\".\"id\" INNER JOIN \"orders\" ON \"users\".\"id\" = \"orders\".\"user_id\" INNER JOIN \"meals\" ON \"orders\".\"meal_id\" = \"meals\".\"id\" WHERE \"meals\".\"cook_id\" = 1  ORDER BY orders.created_at DESC"

任何线索?我正在寻找一种能够返回ActiveRecord关系的解决方案(因此不使用sort_by),因为我计划将其他查询链接到此。

谢谢:)

3 个答案:

答案 0 :(得分:0)

你为什么要这样做呢 has_many :customers, -> { distinct }, through: :orders, source: :user

我可以让不同的客户使用它 cook.rb

class Cook < ActiveRecord::Base
  has_many :orders
  has_many :customers, through: :orders
end
cook = Cook.first
Customer.joins(:orders).joins(:cooks).where('"orders_customers_join"."cook_id" = ?', saad.id).distinct.to_sql

这会给你以下结果

"SELECT DISTINCT \"customers\".* FROM \"customers\" INNER JOIN \"orders\" ON \"orders\".\"customer_id\" = \"customers\".\"id\" INNER JOIN \"orders\" \"orders_customers_join\" ON \"orders_customers_join\".\"customer_id\" = \"customers\".\"id\" INNER JOIN \"cooks\" ON \"cooks\".\"id\" = \"orders_customers_join\".\"cook_id\" WHERE (\"orders_customers_join\".\"cook_id\" = 1)"

现在这将给我所有不同的客户。

答案 1 :(得分:0)

您不必手动指定加入条件,您可以使用includes来执行此操作,ActiveRecord将负责加入条件。

cook.customers.includes(:orders).order('orders.created_at DESC').references(:orders).to_sql

答案 2 :(得分:0)

对我来说这很有用。我的模型Apartment.rb有默认的范围排序。

这不起作用

has many :apartments
has_many :buildings, -> {distinct}, through: :apartments

这样做

has many :apartments
has_many :buildings, through: :apartments

def buildings
  super.uniq
end