Rails: запрос ActiveRecord, где вся ассоциация является / не является значением - PullRequest
0 голосов
/ 19 октября 2018

Take Rails: запрос ActiveRecord, основанный на значении ассоциации , например,

Если мы хотим найти отчеты с любым связанным servers 'company_id, равным 5, мы можемзаписать как Report.includes(:servers).where(servers: {company_id: 5})

Если в отчете имеется несколько связанных серверов, то для некоторого сервера company_id равен 5, для некоторого company_id - 6.

скажем,

  • report_a имеет 2 сервера, с company_id, 5,6 отдельно
  • report_b имеет 2 сервера, оба с company_id, 5
  • report_c имеет 2 сервера, оба с company_id, 6

Как найти отчеты для всех связанных серверов: company_id равен 5? (Только для всех связанных серверов company_id равен 5, тогда отчет квалифицирован)

в приведенном выше случае report_b равенответ

И найти отчеты со всеми соответствующими серверами company_id не равен 5? (только для всех связанных серверов company_id не равен 5, тогда отчет квалифицирован)

в приведенном выше случае, report_c ответ

Можно ли использовать только where?

Ответы [ 2 ]

0 голосов
/ 19 октября 2018

Как найти отчеты для всех связанных серверов: company_id равен 5?

Это можно сделать, сначала найдя набор отчетов, в котором хотя бы один сервер имеет company_id = 5. Затем просто найдите отчеты, которыеНЕ в этом наборе.

server_conditions = Server.where.not(company_id: 5)
  .or(Server.where(id: nil))  # Include reports which have NO servers.

reports_to_exclude = Report
  .left_joins(:servers)  # see notes about joins vs left_joins
  .merge(server_conditions)

Report.where.not(id: reports_to_exclude)  # ActiveRecord automatically selects `id` from reports_to_exclude, but it could be done explicitly, id: reports_to_exclude.select(:id)

объединения против left_joins

Если есть записи отчетов, которые НЕ имеют записей о связанных серверах, то joins даст результат, отличный от left_joins.left_joins будет исключать таких отчетов, в то время как joins будет включать их.

Вам решать, какое поведение является правильным.Если вы знаете, что у вас никогда не будет отчета, у которого нет связанного сервера, то в любом случае сработает (возможно, лучше использовать joins, но вам всегда следует обращать внимание на влияние на производительность базы данных).

findв отчетах со всех соответствующих серверов company_id не равен 5?

Принцип здесь тот же.Во-первых, найдите набор отчетов, в котором есть сервер с company_id, равным 5. Затем выберите все остальные отчеты, которых нет в этом наборе.

reports_to_exclude = Report.joins(:servers).where(servers: { company_id: 5 })
Report.where.not(id: reports_to_exclude)

Можно ли использовать, используя только где?

Это как можно ближе к вам.

0 голосов
/ 19 октября 2018

Я очень сомневаюсь, что это можно сделать, используя where ТОЛЬКО.Но ваш пример также содержит вызов includes, поэтому я предполагаю, что вы имели в виду «это можно сделать с помощью методов ActiveRecord, используя как можно меньше необработанного SQL».Что ж, это достижимо.

Как получить отчеты, имеющие только серверы с заданным значением company_id

Это классический запрос SELECT с INNER JOIN между reports и servers.Поскольку нам нужно просмотреть все серверы отчета, мы группируем отчеты по их идентификатору и добавляем HAVING, чтобы найти max и min из servers.company_id для данного отчета.Отчеты, которые мы ищем, имеют max(company_id) == min(company_id) == 5:

company_id = 5
Report.joins(:servers)
      .group('reports.id')
      .having("max(servers.company_id) = #{company_id} AND min(servers.company_id) = #{company_id}")

Как получать только отчеты, серверы которых не указали company_id

Лучший способ сделать это - извлечь эти отчетыкоторые не соответствуют заданному условию (т. е. отчеты, имеющие серверы с указанным company_id), а затем исключают их.Таким образом, мы могли бы получать отчеты, имеющие серверы с другими значениями company_ids, а также отчеты без серверов.

Report.where.not(
  id: Report.joins(:servers).where(servers: { company_id: 5 })
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...