如何使用AREL命名计算的布尔列?

时间:2013-08-16 19:16:45

标签: sql ruby-on-rails arel

我有一个SQL查询,我正在尝试转换为AREL。它开始于:

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>

有什么想法吗?

3 个答案:

答案 0 :(得分:1)

应该这样做,为您提供01

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"

答案 1 :(得分:0)

我不确定这是可能的:gteq等是在查询的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'))

答案 2 :(得分:0)

注意:很多这是猜想,因为Arel实际上是完全无法记录的!可能有更好或更快的方法来实现这一点,但是它的外观,下面的东西应该是正确的。

请记住,Arel的那些部分只生成需要传递给SelectManager或其他可以处理它们的实体的AST节点。

要生成句法元素,您可以执行以下操作:

node = Arel::Nodes::As.new(
  Arel::Table.new(:products)[:id].count.gt(0),
  'exists'
)

生成可以传递给SelectManager的"COUNT(`products`.`id`) > 0 AS 'exists'"的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布尔值,具体取决于数据库后端,我将其留作读者的练习,即,我是如何来到这里寻找方法的做得恰到好处。