我能强制执行一个活动记录查询链吗?

3

我有一个特殊情况,我想在执行SQL查询之后才使用.first

我的情况如下:

User.select("sum((type = 'foo')::int) as foo_count",
            "sum((type = 'bar')::int) as bar_count")
    .first
    .yield_self { |r| r.bar_count / r.foo_count.to_f }

然而,这会抛出一个SQL错误,提示我在GROUP BY子句中应该包含我的user_id。我已经使用to_a找到了一个hacky的解决方案,但我真的想知道是否有一种正确的方法来强制在我的调用.first之前执行。


pluck 可以替代 select 吗? - tadman
1
是的,它可以!User.pluck("sum((type = 'foo')::int)::float / sum((type = 'bar')::int)::float").first 就是解决方法。 - Ulysse BN
2个回答

2
错误是因为first使用了一个order by语句来按id排序。

"查找第一条记录(或前N条记录,如果提供了参数)。如果未定义顺序,则将按主键排序。"

而应该尝试使用take

"返回记录(或前N条记录,如果提供了参数),没有任何隐含的顺序。顺序将取决于数据库实现。如果提供了顺序,它将被遵守。"

所以

User.select("sum((type = 'foo')::int) as foo_count",
        "sum((type = 'bar')::int) as bar_count")
.take
.yield_self { |r| r.bar_count / r.foo_count.to_f }

应该能够适当地工作,但如所述,顺序是不确定的。

我不在意顺序,因为我的集合里只有一个结果! - Ulysse BN
1
@UlysseBN 我当然能看得出来。这个评论更多是为了那些将来偶然发现这个答案的人。 - engineersmnky

1
你可能想要使用pluck,它只检索数据而不是使用select来改变加载到models中的字段:
User.pluck(
  "sum((type = 'foo')::int) as foo_count",
  "sum((type = 'bar')::int) as bar_count"
).map do |foo_count, bar_count|
  bar_count / foo_count.to_f 
end

如果必要的话,您也可以在查询中进行除法运算。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接