如何模拟ActiveRecord Model.count.to_sql

Reg*_*ieB 8 ruby sql activerecord ruby-on-rails

我想显示计数中使用的SQL.但是,Model.count.to_sql无法工作,因为count返回没有to_sql方法的FixNum.我认为最简单的解决方案是这样做:

Model.where(nil).to_sql.sub(/SELECT.*FROM/, "SELECT COUNT(*) FROM")
Run Code Online (Sandbox Code Playgroud)

这会创建Model.count与之相同的SQL ,但它是否会导致问题进一步发生?例如,如果我添加一个复杂的where子句和一些连接.

有没有更好的方法呢?

kbr*_*ock 7

您可能想深入了解 Arel:

Model.select(Arel.star.count).to_sql
Run Code Online (Sandbox Code Playgroud)

旁白:我发现我经常想要查找子计数,因此我将 count(*) 嵌入到另一个查询中:

child_counts = ChildModel.select(Arel.star.count)
                         .where(Model.arel_attribute(:id).eq(
                                ChildModel.arel_attribute(:model_id)))

Model.select(Arel.star).select(child_counts.as("child_count"))
     .order(:id).limit(10).to_sql
Run Code Online (Sandbox Code Playgroud)

然后为您提供每个模型的所有子项计数:

SELECT  *,
        (
          SELECT COUNT(*)
          FROM "child_models"
          WHERE "models"."id" = "child_models"."model_id"
        ) child_count
FROM "models"
ORDER BY "models"."id" ASC
LIMIT 10
Run Code Online (Sandbox Code Playgroud)

祝你好运

更新:

不确定您是否正在尝试以通用方式解决此问题。也不确定您在Model.

我们确实有一个方法,可以自动调用放入 ui 层的查询的计数。我发现 usingcount(:all)比 simple 更稳定count,但听起来这与您的用例不重叠。也许您可以使用except我们使用的子句改进您的解决方案:

SELECT  *,
        (
          SELECT COUNT(*)
          FROM "child_models"
          WHERE "models"."id" = "child_models"."model_id"
        ) child_count
FROM "models"
ORDER BY "models"."id" ASC
LIMIT 10
Run Code Online (Sandbox Code Playgroud)

where 子句所需的子句where和连接对我们来说工作得很好。我们倾向于保留连接和 where 子句,因为它需要成为计数的一部分。虽然你肯定想删除includes(在我看来应该由rails自动删除),但是references(更棘手,特别是在它引用 ahas_many并需要一个不同的情况下)开始在那里抛出扳手。如果您需要使用引用,您可以将它们转换为left_join.

您可能需要仔细检查这些“连接”方法采用的参数。其中一些采用表名称,另一些采用关系名称。后来的 Rails 版本变得更好,并采用关系名称 - 确保您正在查看正确版本的 Rails 文档。

另外,在我们的例子中,我们花费更多的时间尝试获得具有更复杂关系的子选择,我们必须进行一些修改。看起来我们没有那么多处理 where 子句。 参考2


小智 6

你可以试试

Model.select("count(*) as model_count").to_sql
Run Code Online (Sandbox Code Playgroud)