【问题标题】:Is there a clean way to use ORDER BY inside an Arel NamedFunction Node?有没有在 Arel NamedFunction 节点中使用 ORDER BY 的干净方法?
【发布时间】:2016-04-03 19:50:47
【问题描述】:

我正在使用 ActiveRecord 4.2 / Arel 6.0 / Postgres 并有以下输入:

  • Arel::Attributes::Attribute 来自 Arel::Table (column)
  • 多个 Arel::Nodes::Ordering 节点 (orders)

我想使用聚合函数构建一个 Arel::Nodes::NamedFunction,该函数包含由 Attribute 指定的列并按 Ordering 节点排序。

生成的 SQL 可能类似于:

array_agg("posts"."id" ORDER BY "posts"."published_at" DESC)

我目前的解决方案是首先构建一个Arel::Nodes::SelectStatement,向其中添加列和订单,将其转换为 SQL,去除前导 SELECT 关键字,将其包装在 Arel::Nodes::SqlLiteral 中并将其传递给 @987654333 @节点:

select = Arel::Nodes::SelectStatement.new
select.cores.last.projections << column
select.orders = orders

sql = select.to_sql.sub(/^SELECT /, '')
literal = Arel::Nodes::SqlLiteral.new(sql)

array_agg = Arel::Nodes::NamedFunction.new('array_agg', [literal])

显然,这是一个巨大的黑客攻击。

将ORDER BY 保留在聚合函数之外不是一种选择,因为它会与用于聚合的GROUP BY 冲突。

那么有没有一种更简洁的方法可以在不滥用 SelectStatement / SelectManager 的情况下实现这一目标?

【问题讨论】:

    标签: ruby-on-rails rails-activerecord arel


    【解决方案1】:

    我不知道这是否适合您,但我发现这是一种按 DESC 顺序订购的干净方式。您使用的语法与我不同,但看起来这就是您要寻找的。​​p>

    arel  = Post.arel_table
    query = arel.project(Arel.select('*'))
    query.order(arel[:published_at].desc).to_sql
    

    这是我对您正在尝试做的事情的最佳猜测。

    【讨论】:

    • 您所描述的是普通的SELECT … FROM … ORDER BY,而我的问题是关于在聚合函数中使用ORDER BY。
    【解决方案2】:

    解决方案是使用Arel::Nodes::InfixOperation 构建“ORDER BY”节点并使用Arel::Nodes::StringJoin 构建逗号分隔的Arel::Nodes::Ordering 列表:

    ordering = Arel::Nodes::StringJoin.new(orders)
    order_by = Arel::Nodes::InfixOperation.new('ORDER BY', column, ordering)
    array_agg = Arel::Nodes::NamedFunction.new('array_agg', [order_by])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多