Поиск групп, в которых отсутствуют значения одного столбца

#sql #sql-server #tsql

#sql #sql-сервер #tsql

Вопрос:

Надеюсь, кто-нибудь сможет пролить свет на проблему, которую я пытаюсь решить.

Типы

 Type 
------
'Type1'
'Type2'
'Type3'
 

Коды

 Code |  ID  | Type
---------------------
ABC  | 1234 | 'Type1'
ABC  | 1234 | 'Type2'
CDE  | 2345 | 'Type1'
CDE  | 2345 | 'Type3'
EFG  | 3456 | 'Type2'
 

Я хотел бы иметь возможность определять те пары Код / идентификатор, в которых отсутствует определенный тип.
Результат этого запроса должен выдать.

 Code |  ID  | Type
--------------------
ABC  | 1234 | 'Type3'
CDE  | 2345 | 'Type2'
EFG  | 3456 | 'Type1'
EFG  | 3456 | 'Type3'
 

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

1. Я не думаю, что это возможно с простым SQL

2. @RedGuy11 ты так думаешь?

3. Где полный список всех пар <Код, идентификатор>? Без этого ваша цель невозможна. У вас есть одно предложение, которое предполагает , что полный список — это просто все отдельные пары в вашей таблице. Это безопасно?

Ответ №1:

Для этого вам нужна условная агрегация:

 SELECT
    c.Code,
    c.ID,
    t.Type
FROM Types t
CROSS APPLY (
    SELECT *
    FROM Codes c
    CROSS APPLY (VALUES (CASE WHEN c.Type = T.Type THEN 1 END) ) AS v (IsMatch)
    GROUP BY Code, ID
    HAVING COUNT(IsMatch) = 0
) c;
 

Другим вариантом является перекрестное объединение возможных идентификаторов с типами, а затем EXCEPT удаление существующих. Проблема в том, что это означает повторное сканирование таблицы:

 SELECT
    c.Code,
    c.ID,
    t.Type
FROM Types t
CROSS JOIN (
    SELECT DISTINCT Code, ID
    FROM Codes c
) c
EXCEPT
SELECT
    c.Code,
    c.ID,
    c.Type
FROM Codes c;
 

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

1. Спасибо @Charlieface — первый запрос жалуется на то, что в агрегированном выражении, содержащем внешнюю ссылку, указано несколько столбцов. Второй запрос работает хорошо.

2. Исправлено. Я думаю, что первый запрос лучше из-за только одного сканирования.

Ответ №2:

Обычно я подхожу к этому, используя a CROSS JOIN для генерации всех комбинаций и LEFT JOIN (или NOT EXISTS для удаления существующих:

 SELECT c.Code, c.ID, t.Type
FROM (SELECT DISTINCT Code, Id FROM Codes c
     ) c CROSS JOIN
     Types t LEFT JOIN
     codes
     ON codes.id = c.id AND codes.type = t.type
WHERE codes.code IS NULL;
 

Если у вас есть отдельный список кодов (который у вас должен быть), вы можете использовать его вместо SELECT DISTINCT .

Ответ №3:

как насчет этого?

 select Code,  ID , Type 
from youtable 
where 'Type' = '' or `Type` IS NULL
 

или это?

 select Code,  ID , t.typeid
from youtable y
left join Types t on y.typeid = t.typeid
where t.typeid IS NULL
 

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

1. Это не отвечает на вопрос

2. @Charlieface: Почему нет? Вы считаете, что это неправильный ответ? Если да, то чего не хватает участнику? Предоставление конструктивной обратной связи поможет им улучшить свой ответ, если это необходимо.