Как найти группы строк, где все строки в каждой группе имеют определенное значение столбца

Пример данных:

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

Другие вопросы по тегам