У меня есть таблица, в которой один столбец имеет повторяющиеся записи, но другие столбцы разные. так что-то вроде этого
Статус версии подкода кода
1234 D1 1 А
1234 D1 0 P
1234 DA 1 А
1234 ДБ 1-пол.
5678 BB 1 А
5678 BB 0 P
5678 БП 1 А
5678 BJ 1 А
0987 HH 1 А
Итак, в приведенной выше таблице. субкод и версия - уникальные значения, тогда как код повторяется. Я хочу перенести записи из приведенной выше таблицы во временную таблицу. Только записи, которые я хотел бы передать, - это когда ВСЕ субкоды для кода имеют статус «A», и я хочу, чтобы они присутствовали во временной таблице только один раз.
Итак, из примера выше. временная таблица должна иметь только 5678 и 0987, поскольку все подкоды, относящиеся к 5678, имеют статус 'A', а все подкоды для 0987 (у него только один) имеют статус A. 1234 опущен, потому что его подкод 'DB' имеет статус 'P'
Буду признателен за любую помощь!


По вашему выбору добавьте предложение where, которое гласит:
Select [stuff]
From Table T
Where Exists
(Select * From Table
Where Code = T.Code
And Status = 'A')
And Not Exists
(Select * From Table I
Where Code = T.Code
And Not Exists
(Select * From Table
Where Code = I.Code
And SubCode = I.SubCode
And Status = 'A'))
На английском, Покажи мне ряды, где есть хотя бы одна строка со статусом 'A', и нет строк с каким-либо конкретным подкодом, у которых нет хотя бы одной строки с этим кодом / субкодом, со статусом 'A'
Теперь это работает ... у меня был "<>" вместо " = "
INSERT theTempTable (Code)
SELECT t.Code
FROM theTable t
LEFT OUTER JOIN theTable subT ON (t.Code = subT.Code AND subT.status <> 'A')
WHERE subT.Code IS NULL
GROUP BY t.Code
Это должно помочь. Логика немного сложна, но я постараюсь объяснить, как она получена.
Внешнее соединение в сочетании с проверкой IS NULL позволяет вам искать отсутствие критерия. Объедините это с обратным тому, что вы обычно ищете (в данном случае status = 'A'), и запрос будет успешным, когда нет строк, которые не совпадают. Это то же самое, что ((нет строк) ИЛИ (все строки совпадают)). Поскольку мы знаем, что есть строки из-за другого запроса в таблице, все строки должны совпадать.
Это не дает правильных результатов. 5678 будет исключен, поскольку существует по крайней мере одна строка со статусом, отличным от «A».
Немного неясно, входит ли в игру столбец версии. Например, вы хотите рассматривать только строки с самой большой версией или если ЛЮБОЙ вложенный код имеет "A", если он считается. Возьмем, к примеру, 5678, BB, где версия 1 имеет "A", а версия 0 - "B". Включен ли 5678, потому что по крайней мере один из подкодов BB имеет "A" или потому, что версия 1 имеет "A".
В следующем коде предполагается, что вам нужны все коды, в которых каждый подкод имеет хотя бы одну букву «A», независимо от версии.
SELECT
T1.code,
T1.subcode,
T1.version,
T1.status
FROM
MyTable T1
WHERE
(
SELECT COUNT(DISTINCT subcode)
FROM MyTable T2
WHERE T2.code = T1.code
) =
(
SELECT COUNT(DISTINCT subcode)
FROM MyTable T3
WHERE T3.code = T1.code AND T3.status = 'A'
)
Если у вас большой стол, производительность может быть ужасной. Я попытаюсь придумать запрос, который, вероятно, будет иметь лучшую производительность, поскольку это было не в моей голове.
Кроме того, если вы объясните всю степень своей проблемы, возможно, мы сможем избавиться от этой временной таблицы ...;)
Вот еще два возможных метода. По-прежнему много подзапросов, но похоже, что они будут работать лучше, чем описанный выше метод. Они оба очень похожи, хотя у второго здесь был лучший план запроса в моей БД. Конечно, с ограниченными данными и без индексации это не лучший тест. Вам следует попробовать все методы и посмотреть, какой из них лучше всего подходит для вашей базы данных.
SELECT
T1.code,
T1.subcode,
T1.version,
T1.status
FROM
MyTable T1
WHERE
EXISTS
(
SELECT *
FROM MyTable T2
WHERE T2.code = T1.code
AND T2.status = 'A'
) AND
NOT EXISTS
(
SELECT *
FROM MyTable T3
LEFT OUTER JOIN MyTable T4 ON
T4.code = T3.code AND
T4.subcode = T3.subcode AND
T4.status = 'A'
WHERE T3.code = T1.code
AND T3.status <> 'A'
AND T4.code IS NULL
)
SELECT
T1.code,
T1.subcode,
T1.version,
T1.status
FROM
MyTable T1
WHERE
EXISTS
(
SELECT *
FROM MyTable T2
WHERE T2.code = T1.code
AND T2.status = 'A'
) AND
NOT EXISTS
(
SELECT *
FROM MyTable T3
WHERE T3.code = T1.code
AND T3.status <> 'A'
AND NOT EXISTS
(
SELECT *
FROM MyTable T4
WHERE T4.code = T3.code
AND T4.subcode = T3.subcode
AND T4.status = 'A'
)
)
Хорошее решение. FROM - враг производительности, но вы это знаете.
Вот мое решение
SELECT Code
FROM
(
SELECT
Code,
COUNT(SubCode) as SubCodeCount
SUM(CASE WHEN ACount > 0 THEN 1 ELSE 0 END)
as SubCodeCountWithA
FROM
(
SELECT
Code,
SubCode,
SUM(CASE WHEN Status = 'A' THEN 1 ELSE 0 END)
as ACount
FROM CodeTable
GROUP BY Code, SubCode
) sub
GROUP BY Code
) sub2
WHERE SubCodeCountWithA = SubCodeCount
Разберем его изнутри.
SELECT
Code,
SubCode,
SUM(CASE WHEN Status = 'A' THEN 1 ELSE 0 END)
as ACount
FROM CodeTable
GROUP BY Code, SubCode
Сгруппируйте коды и подкоды (каждая строка представляет собой отдельную пару кода и подкода). Посмотрите, сколько отличий получено в каждой паре.
SELECT
Code,
COUNT(SubCode) as SubCodeCount
SUM(CASE WHEN ACount > 0 THEN 1 ELSE 0 END)
as SubCodeCountWithA
FROM
--previous
GROUP BY Code
Перегруппируйте эти пары по коду (теперь каждая строка - это код) и подсчитайте, сколько существует субкодов и сколько субкодов имеют A.
SELECT Code
FROM
--previous
WHERE SubCodeCountWithA = SubCodeCount
Испускайте те коды, которые имеют такое же количество субкодов, что и субкоды с A.
Тоже интересное решение. В ограниченном наборе данных выше в таблице без индексов я вижу высокую стоимость сортировки (относительно), но с реальной таблицей с данными это может быть лучше, чем сканирование таблицы из моего метода.
Это не дает правильных результатов. 5678 будет исключен, поскольку существует по крайней мере одна строка со статусом, отличным от «A». (также в вашем запросе есть SubCode, где, я думаю, вы имели в виду статус)