Rails / ActiveRecord: почему подсчет приводит к синтаксической ошибке при вызове моего ActiveRecord: Relation? - PullRequest
0 голосов
/ 11 февраля 2019

Я пытался оптимизировать запрос.У меня есть модель с именем 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')

Используя 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'

Тем не менее, она отлично работает с length.size возвращает хэш с количеством (label_name_count) в качестве значения и идентификатором проблемы в качестве ключа.

У меня уже есть полдюжины тестов, вызывающих count для результата, я хочу знать, почемуон не работает до того, как я рассмотрю их изменение.

Что вызывает сбой #count и как я могу исправить это в моем запросе, чтобы убедиться, что он работает?

1 Ответ

0 голосов
/ 11 февраля 2019

У вас жестко зашит 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

, что псевдоним / as в числе является недопустимым SQL иВот почему sqlite3 сообщает об ошибке.

Если вы полагаетесь на length или size, запрос не изменяется, то есть выбирает не обернутый внутри count и выполняется первым.Только после извлечения записей и инициализации моделей подсчитываются экземпляры.Это будет работать как таковое, но крайне неэффективно, если вы заинтересованы только в подсчете.Однако если вам нужны экземпляры в другом месте, то этот подход подойдет.

Чтобы запрос работал с количеством, вам сначала нужно удалить проекцию.Либо

  • удаляя 'count as' в проекции выбора, если вы не полагаетесь на них в другом месте
  • , либо предоставляя значения выбора динамически, заключая область в метод
  • или сначала удалив выбранную проекцию, например, с помощью , за исключением .
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...