Как найти группы строк, где все строки в каждой группе имеют определенное значение столбца
Пример данных:
ID1 ID2 Num Type
---------------------
1 1 1 'A'
1 1 2 'A'
1 2 3 'A'
1 2 4 'A'
2 1 1 'A'
2 2 1 'B'
3 1 1 'A'
3 2 1 'A'
Желаемый результат:
ID1 ID2
---------
1 1
1 2
3 1
3 2
Обратите внимание, что я группирую по ID1 и ID2, но не по Num, и что я специально ищу группы, в которых Type = 'A'. Я знаю, что это выполнимо путем объединения двух запросов к одной и той же таблице: один запрос, чтобы найти все группы, имеющие отдельный тип, и другой запрос, чтобы отфильтровать строки с Type = 'A'. Но мне было интересно, если это можно сделать более эффективным способом.
Я использую SQL Server 2008, и мой текущий запрос:
SELECT ID1, ID2
FROM (
SELECT ID1, ID2
FROM T
GROUP BY ID1, ID2
HAVING COUNT( DISTINCT Type ) = 1
) AS SingleType
INNER JOIN (
SELECT ID1, ID2
FROM T
WHERE Type = 'A'
GROUP BY ID1, ID2
) AS TypeA ON
TypeA.ID1 = SingleType.ID1 AND
TypeA.ID2 = SingleType.ID2
РЕДАКТИРОВАТЬ: Обновлены примеры данных и запросов, чтобы указать, что я группируюсь по двум столбцам, а не по одному.
2 ответа
SELECT ID1, ID2
FROM MyTable
GROUP BY ID1, ID2
HAVING COUNT(Type) = SUM(CASE WHEN Type = 'A' THEN 1 ELSE 0 END)
Есть две альтернативы, которые не требуют агрегирования (но требуют отдельной)
ANTI-JOIN
SELECT DISTINCT t1.ID1, t1.ID2
FROM
table t1
LEFT JOIN table t2
ON t1.ID1 = t2.ID1
and t1.Type <> t2.Type
WHERE
t1.Type = 'A'
AND
t2.ID1 IS NULL
Посмотрите, как работает этот запрос data.se. Пример для 9132209 (Anti-Join)
НЕ СУЩЕСТВУЕТ
SELECT DISTINCT t1.ID1, t1.ID2
FROM
table t1
WHERE
t1.Type = 'A'
AND
NOT EXISTS
(SELECT 1
FROM table t2
WHERE t1.ID1 = t2.ID1 AND Type <> 'A')
Посмотрите, как работает этот data.se пример запроса для 9132209 Not Exists