我有一个试图转换为 AREL 的 SQL 查询。它开始:
SELECT COUNT(id) > 0 AS exists...
到目前为止,我有:
Arel::Table.new(:products)[:id].count.gt(0).as(:exists)
但我得到:
NoMethodError - undefined method `as' for #<Arel::Nodes::GreaterThan:0x007fc98c4c58d0>
有任何想法吗?
我有一个试图转换为 AREL 的 SQL 查询。它开始:
SELECT COUNT(id) > 0 AS exists...
到目前为止,我有:
Arel::Table.new(:products)[:id].count.gt(0).as(:exists)
但我得到:
NoMethodError - undefined method `as' for #<Arel::Nodes::GreaterThan:0x007fc98c4c58d0>
有任何想法吗?
这应该这样做,给你一个0
or 1
。
Arel::Table.new(:products)[:id].count.as('exists').gt(0)
测试:
> Arel::Table.new(:products)[:id].count.as('exists').gt(0).to_sql
=> "COUNT([products].[id]) AS exists > 0"
我不确定这是可能的:gt
,eq
等是查询的 WHERE 部分中使用的表达式。您在这里尝试做的是在作为 SELECT 一部分的字段列表中进行操作,该列表由 Arel 的project
方法处理。这是有效的:
Arel::Table.new(:products).project(product[:id].count.as(:exists))
但是,如果您添加条件,它将不起作用gt(0)
这并不花哨,但它可以满足您的需求:
Arel::Table.new(:products).project(Arel.sql('COUNT(id) > 0').as('exists'))
注意:很多这都是推测,因为 Arel 出于所有实际目的,完全没有文档记录!可能有更好或更快的方法来做到这一点,但从外观上看,下面的内容应该是正确的。
请记住,Arel 的那些部分只生成需要传递给 SelectManager 或其他可以处理它们的实体的 AST 节点。
要生成句法元素,您可以执行以下操作:
node = Arel::Nodes::As.new(
Arel::Table.new(:products)[:id].count.gt(0),
'exists'
)
"COUNT(`products`.`id`) > 0 AS 'exists'"
这会产生可以传递给 SelectManager 的SQL 片段#project
。你可以做一些诡计,比如:
Products
.where(nil) # shortcut to get a relation
.tap do |rel|
node = () # from above
# Go into the SelectManager and *add* a projection.
# If you want to *replace* the entire projection, first do:
# rel.arel.projections = []
rel.arel.project(node)
end
至于根据数据库后端将谓词的结果实际映射回适当的 Ruby 布尔值,我将其作为练习留给读者,也就是说,这就是我来这里寻找正确执行此操作的方法的方式。