将SQL转换为Arel-列[...]必须出现在GROUP BY子句中

时间:2018-11-26 08:48:33

标签: postgresql arel

我有一个正常的SQL查询,我想将其转换为Arel,但我似乎继续遇到相同的错误。

有效的SQL:

Order.find_by_sql(
    "SELECT COUNT(order_number) AS order_count,
    restaurant_id, date_part('month', date) AS date_month,
    date_part('year', date) AS date_year 
    FROM orders
    WHERE restaurant_id is not null
    GROUP BY(restaurant_id, date_part('month', date), date_part('year', date))
    ORDER BY date_part('year', date) desc, date_part('month', date) desc;"
  )

尝试1 (不起作用)

orders = Order.arel_table

Order
    .where.not(restaurant_id: nil)
    .select(:restaurant_id)
    .select(:date)
    .select(Order.arel_table[:order_number].count.as('order_count'))
    .select(
        Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('month'), :date]),
        Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('year'), orders[:date]])
    )
    .group(
        :restaurant_id, 
        Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('month'), orders[:date]]), 
        Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('year'), orders[:date]])
    )

尝试2 (无效)

orders = Order.arel_table
query = orders
      .where(orders[:restaurant_id].not_eq(nil))
      .project(
          orders[:restaurant_id],
          Order.arel_table[:order_number].count.as('order_count'),
          Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('month'), orders[:date]]).as('date_month'),
          Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('year'), orders[:date]]).as('date_year'),
      )
      .group(
          orders[:restaurant_id],
          Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('month'), orders[:date]]),
          Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('year'), orders[:date]])
      )
      .order(orders[:date].desc)
      .to_sql
Order.find_by_sql(query)

这两种方法都会导致以下错误:

  

PG :: GroupingError:错误:列“ orders.date”必须出现在GROUP BY子句中或在聚合函数中使用

问题是我不想按日期分组,而是按月分组。有什么技巧可以解决吗?

我最初也尝试使用Arel::Nodes::NamedFunction.new('date_part', ['month', :date])而不是Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('month'), orders[:date]]),但是结果如下:

  

不受支持的参数类型:字符串。而是构造一个Arel节点。

任何帮助,我们将不胜感激。谢谢!

1 个答案:

答案 0 :(得分:0)

因此,经过数小时的挖掘,事实证明这是一大难题!我遇到的问题是在我的default_scope模型上设置了Order-这就是按:date进行排序的地方。最后,我决定删除默认范围,在实际需要的地方进行排序,剩下的关于查询的内容是这样:

orders = Order.arel_table
query = orders
  .where(orders[:restaurant_id].not_eq(nil))
  .project(
      orders[:restaurant_id],
      Order.arel_table[:order_number].count.as('order_count'),
      Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('month'), orders[:date]]).as('date_month'),
      Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('year'), orders[:date]]).as('date_year'),
  )
  .group(
      orders[:restaurant_id],
      Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('month'), orders[:date]]),
      Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('year'), orders[:date]])
  )
  .order(
      orders[:restaurant_id],
      Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('year'), date]).desc,
      Arel::Nodes::NamedFunction.new('date_part', [Arel::Nodes.build_quoted('month'), date]).desc

  )
  .to_sql

Order.find_by_sql(query)

经验教训:尽可能避免使用default_scope。如果您独自工作,很可能会随着时间的流逝而忘记使用它。如果您在团队中工作,您可能会花一个人整整一天的时间。