Адресная книга: Преобразуйте запрос «достаточно хотя бы одного списка» в запрос «должны присутствовать все списки».

#mysql #sql-server #sqlite

#mysql #sql-сервер #sqlite

Вопрос:

У меня есть база данных SQLite3, которая содержит, среди прочего, эти пять таблиц: Адресная книга SQL Schema

Списки могут быть назначены контактам и заданиям на печать. Если я хочу обработать задание на печать (например, печать контактов на конвертах) Мне нужно получить все те контакты, которым были назначены те же списки, что и для этого задания на печать.

Пока я получил этот SQL-запрос, но он извлекает все контакты, у которых есть хотя бы один список, общий для данного задания печати, но мне нужно, чтобы все назначенные списки соответствовали:

 SELECT DISTINCT `contact`.* FROM `contact` JOIN (
  SELECT `contact_id` FROM `contact_list` JOIN (
    SELECT `list_id` FROM `job_list` WHERE `job_id` = :id
  ) AS `inner` ON `inner`.`list_id` = `contact_list`.`list_id`
) AS `outer` ON `outer`.`contact_id` = `contact`.`id`
  

Я рассматриваю это как «по крайней мере, один список достаточно хорош», но мне нужно «все списки также должны быть назначены заданию».

Как выглядит такой запрос?

Редактировать:

Вот несколько запросов, которые генерируют образцы данных: Образцы данных SQL

И вот ожидаемые результаты для каждого задания печати:

 job_id      contact_id
1           1, 2, 3
2           5
3           4, 6
  

Контакт 7 никогда не должен отображаться

Результат

 SELECT * FROM contact WHERE id IN (
  WITH flattenJob (job_id, jlist) AS (
    SELECT job_id, group_concat(list_id) 
    FROM job_list
    GROUP BY job_id
  ),
  flattenCont (contact_id, clist) AS (
    SELECT contact_id, group_concat(list_id)
    FROM contact_list
    GROUP BY contact_id
  )
  SELECT contact_id
  FROM flattenJob
  JOIN flattenCont ON jlist = clist
  WHERE job_id = :id
)
ORDER BY name
  

Комментарии:

1. Спасибо за ваш ответ. Я отредактировал свой первоначальный пост.

Ответ №1:

Похоже, цель состоит в том, чтобы распечатать один конверт на контакт (сэкономить деньги, сохранить окружающую среду, Ура!); По сути, дедуплицировать списки. Идея состояла бы в том, чтобы превратить «составное задание» (например, задание 3) в его собственную сущность. Одним из способов было бы использовать виртуальные таблицы, что-то вроде этого:

 WITH flattenJob (job_id,jlist) as
 (select job_id,group_concat(list_id) 
 from job_list
 group by job_id
 ),
 flattenCont (contact_id,clist)
 as (select contact_id,group_concat(list_id)
 from contact_list
 group by contact_id
 )
 select job_id,contact_id,jlist,clist
 from flattenJob
 JOIN flattenCont on jlist = clist
  

Это результат выборки данных:

 job_id      contact_id  jlist       clist
----------  ----------  ----------  ----------
1           1           1           1
1           2           1           1
1           3           1           1
2           5           2           2
3           4           1,2         1,2
3           6           1,2         1,2
  

Это должно дать вам хорошую отправную точку для создания успешного запроса.