Rails/ActiveRecord:为什么在我的 ActiveRecord:Relation 上调用 count 会导致语法错误?

use*_*603 5 activerecord ruby-on-rails

我一直在尝试优化查询。我有一个名为的模型Issue和一个名为Labels它们的模型,它们具有多对多的关系。

为了得到列表issues具有labels与每一个物品的给定阵列中的匹配,我使用的名称:

    Issue.select('issues.id, count(labels.id) as matching_label_count')
      .joins(:labels)
      .where(labels: { name: [*labels] })
      .having("matching_label_count = #{labels.size}")
      .group('issues.id')
Run Code Online (Sandbox Code Playgroud)

使用 pry,我看到查询Issue::ActiveRecord_Relation按预期返回并且它响应ActiveRecord::Calculations方法。但是,当我调用count结果时,出现语法错误:

    pry(main)> Issue.select('issues.id, count(labels.id) as
    matching_label_count').includes(:labels).where(labels: { name: labels
    }).having("matching_label_count = #{labels.size}").group('issues.id').count
    (0.9ms)  SELECT COUNT(DISTINCT issues.id, count(labels.id) as
    matching_label_count) AS
    count_issues_id_count_labels_id_as_matching_label_count, issues.id,
    count(labels.id) as matching_label_count, issues.id AS issues_id FROM "issues"
    LEFT OUTER JOIN "tags" ON "tags"."issue_id" = "issues"."id" LEFT OUTER JOIN
    "labels" ON "labels"."id" = "tags"."label_id" WHERE "labels"."name" IN (?, ?)
    GROUP BY issues.id HAVING (matching_label_count = 2) ORDER BY
    "issues"."created_at" DESC  [["name", "bug"], ["name", "enhancement"]]

    ActiveRecord::StatementInvalid: SQLite3::SQLException: near "as": syntax error:
    SELECT COUNT(DISTINCT issues.id, count(labels.id) as matching_label_count) AS
    count_issues_id_count_labels_id_as_matching_label_count, issues.id,
    count(labels.id) as matching_label_count, issues.id AS issues_id FROM "issues"
    LEFT OUTER JOIN "tags" ON "tags"."issue_id" = "issues"."id" LEFT OUTER JOIN
    "labels" ON "labels"."id" = "tags"."label_id" WHERE "labels"."name" IN (?, ?)
    GROUP BY issues.id HAVING (matching_label_count = 2) ORDER BY
    "issues"."created_at" DESC from /Users/Arnould/.rvm/gems/ruby-2.6.0/gems/sqlite3-1
    .3.13/lib/sqlite3/database.rb:91:in `initialize' Caused by
    SQLite3::SQLException: near "as": syntax error from /Users/Arnould/.rvm/gems/ruby-
    2.6.0/gems/sqlite3-1.3.13/lib/sqlite3/database.rb:91:in `initialize'
Run Code Online (Sandbox Code Playgroud)

但是,它确实可以与length. size返回一个以 count ( label_name_count) 作为值和问题 id 作为键的散列。

我已经有六个测试调用count结果我想知道为什么在我考虑更改它们之前它不起作用。

是什么导致#count失败,我该如何修复我的查询以确保它正常工作?

ulf*_*rts 4

count(labels.id) as matching_label_count您已在查询的选择投影中进行了硬连接。当您使用该count方法时,ActiveRecord 会将所有选择字段包装在COUNT其自己的导致中:

SELECT COUNT(DISTINCT issues.id, count(labels.id) as matching_label_count) AS
    count_issues_id_count_labels_id_as_matching_label_count

Run Code Online (Sandbox Code Playgroud)

as计数中的alias/是无效的 SQL,这就是 sqlite3 报告错误的原因。

如果您依赖lengthor size,查询不会改变,即选择不包含在 a 内count并首先执行。仅在检索记录并初始化模型后才对实例进行计数。如果您只对计数感兴趣,那么这会起作用,但效率非常低。如果您在其他地方也需要实例,那么这种方法就很好。

为了使查询能够使用计数,您必须首先删除投影。或者通过

  • 如果您在其他地方不依赖它们,则删除选择投影中的“计数为”
  • 或者通过将范围包装在方法中来动态提供选择值
  • 或者首先删除选择的投影,例如通过 except