У меня есть следующие пять таблиц:
Каждый Продукт связан с поставщиком Интернет-услуг, каждое подключение указано в списке Продуктов. Каждый продукт может иметь несколько надстроек за счет использования сводной таблицы (в которой просто есть 2 поля: одно для идентификатора продукта и одно для идентификатора надстройки).
Результат, который меня интересует, - это каждое соединение с перечисленными надстройками (для этого я использую MySQL GROUP_CONCAT, чтобы составить список поля имя надстройки, разделенный запятыми). Это нормально работает, запрос выглядит примерно так:
SELECT i.name AS ispname, i.img_link, c.download, c.upload, c.monthly_price, c.link,
GROUP_CONCAT(a.name) AS addons, SUM(pa.monthly_fee) AS addon_price
FROM isp i JOIN product p ON i.id = p.isp_id
JOIN `connection` c ON p.id = c.product_id LEFT JOIN product_addon pa ON pa.product_id = p.id AND pa.forced = 0
LEFT JOIN addon a ON pa.addon_id = a.id GROUP BY c.id
Я использую ЛЕВЫЕ СОЕДИНЕНИЯ, так как продукты могут вообще не иметь надстроек.
Моя проблема в том, что можно выбрать некоторые надстройки, которые ДОЛЖНЫ иметь перечисленные соединения, представленные в виде списка идентификаторов надстроек, например (1,14 237). Если я добавлю его в качестве дополнительного условия в операторы JOIN (И pa.addon_id В (...)), он вернет все соединения, которые имеют только одно из перечисленных дополнений, но не обязательно все из них.
Есть ли способ вернуть все соединения, которые, как минимум, имеют все надстройки (они также могут иметь дополнительные) через SQL?


Вы можете добавить к предложению WHERE:
AND NOT EXISTS (SELECT NULL FROM addon a2
WHERE a2.addon_id IN (1,14,237)
AND NOT EXISTS
( SELECT NULL
FROM product_addon pa2
WHERE pa2.addon_id = a2.addon_id
AND pa2.product_id = p.product_id
)
)
Или эквивалентно:
AND NOT EXISTS (SELECT NULL FROM addon a2
LEFT JOIN product_addon pa2
ON pa2.addon_id = a2.addon_id
AND pa2.product_id = p.product_id
WHERE a2.addon_id IN (1,14,237)
AND pa2.product_id IS NULL
)
)
GROUP BY set-of-column
HAVING SUM(CASE WHEN ISNULL(pa.addon_id, 0) IN (1,14,237) THEN 1 ELSE 0 END) = 3