有没有一种在 Arel NamedFunction 节点内使用 ORDER BY 的简洁方法?
Is there a clean way to use ORDER BY inside an Arel NamedFunction Node?
我正在使用 ActiveRecord 4.2 / Arel 6.0 / Postgres 并有以下输入:
- 来自
Arel::Table
(column
) 的 Arel::Attributes::Attribute
- 几个
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
并将其传递给 NamedFunction
节点:
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])
显然,这是一个巨大的 hack。
将 ORDER BY
保留在聚合函数之外不是一个选项,因为它会与用于聚合的 GROUP BY
冲突。
那么有没有更简洁的方法来实现这一目标而不滥用 SelectStatement
/ SelectManager
?
我不知道这是否适合您,但我发现这是一种按 DESC 顺序进行排序的简洁方法。你使用的语法和我的不一样,但看起来这就是你要找的。
arel = Post.arel_table
query = arel.project(Arel.select('*'))
query.order(arel[:published_at].desc).to_sql
这是我对您要执行的操作的最佳猜测。
解决方案是使用 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])
我正在使用 ActiveRecord 4.2 / Arel 6.0 / Postgres 并有以下输入:
- 来自
Arel::Table
(column
) 的 - 几个
Arel::Nodes::Ordering
节点(orders
)
Arel::Attributes::Attribute
我想构建一个 Arel::Nodes::NamedFunction
,其中包含由 Attribute
指定的列并按 Ordering
节点排序的聚合函数。
结果 SQL 可能类似于:
array_agg("posts"."id" ORDER BY "posts"."published_at" DESC)
我目前的解决方案是首先构建一个 Arel::Nodes::SelectStatement
,向其添加列和订单,将其转换为 SQL,去除前导 SELECT
关键字,将其包装在一个Arel::Nodes::SqlLiteral
并将其传递给 NamedFunction
节点:
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])
显然,这是一个巨大的 hack。
将 ORDER BY
保留在聚合函数之外不是一个选项,因为它会与用于聚合的 GROUP BY
冲突。
那么有没有更简洁的方法来实现这一目标而不滥用 SelectStatement
/ SelectManager
?
我不知道这是否适合您,但我发现这是一种按 DESC 顺序进行排序的简洁方法。你使用的语法和我的不一样,但看起来这就是你要找的。
arel = Post.arel_table
query = arel.project(Arel.select('*'))
query.order(arel[:published_at].desc).to_sql
这是我对您要执行的操作的最佳猜测。
解决方案是使用 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])