Исключить строки на основе других строк (SQL)

Скажем, у меня есть запрос вроде этого:

SELECT *
FROM TABLE

И это возвращает это:

TABLE
ID | DATA | VAL
===============
01 | ABCD | 1
01 | DEFG | 2
02 | FGHI | 3
02 | HIJK | 2
03 | JKLM | 3
03 | LMNO | 4
04 | NOPQ | 0
04 | PQRS | 1

В настоящее время у меня есть запрос, который пытается найти только хорошие значения, подобные этому, но он некорректен, потому что включены идентификаторы с плохими VAL в других строках, а это не то, что я хотел бы.

SELECT *
FROM TABLE
WHERE TABLE.VAL IN ("1","2","3")

возвратил бы это (с отсутствующими LMNO и PQRS):

TABLE
ID | DATA | VAL
===============
01 | ABCD | 1
01 | DEFG | 2
02 | FGHI | 3
02 | HIJK | 2
03 | JKLM | 3
04 | NOPQ | 0

Тем не менее, я хочу только строки, где идентификатор не имеет плохих значений. Итак, 01 и 02 в порядке, потому что все их строки имеют хорошие результаты. 03 и 04 плохие, потому что они испорчены плохими результатами в других строках.

Я мог бы просто привести результат в таком виде и обработать его таким образом в программном обеспечении, но кажется, что это возможно с базой данных, и, как правило, делать это в базе данных лучше, чем в программном обеспечении (вы знаете, вот для чего они там...)

Лучшее, что я мог придумать, это:

SELECT *
FROM TABLE
WHERE COUNT( SELECT ID
             FROM TABLE
             WHERE TABLE.VAL NOT IN ("1","2","3")
           ) = 0

Это жизнеспособно? Есть ли лучшая альтернатива?

Спасибо!

4 ответа

Решение

Использование:

SELECT * 
  FROM TABLE a
 WHERE a.val IN (1,2,3)
   AND NOT EXISTS(SELECT NULL
                    FROM TABLE b
                   WHERE b.id = a.id
                     AND b.val NOT IN (1, 2, 3))

Вы могли бы использовать оператор минус.

псевдо-запрос

select everything
from tables
where id in ( select id from table minus select id from table where val is bad )

Вот еще одна альтернатива, которая будет проходить через TBL один раз, агрегировать и, используя найденные идентификаторы, извлекать данные из TBL

SELECT *
WHERE ID IN
(
    SELECT
       ID,
       CASE WHEN val in (1,2,3) THEN 1 ELSE 0 END Test
    FROM TBL
    GROUP BY ID
    HAVING MIN(val) = 1
)

Для ключей с несколькими столбцами и в качестве альтернативы вышеуказанной форме IN вы можете использовать форму JOIN.

SELECT T.*
FROM (
    SELECT
       Company, OrderNumber,
       CASE WHEN val in (1,2,3) THEN 1 ELSE 0 END Test
    FROM TBL
    GROUP BY Company, OrderNumber
    HAVING MIN(val) = 1
    ) KEEP
INNER JOIN TBL T ON T.Company = KEEP.Company and T.OrderNumber=KEEP.OrderNumber

Вы могли бы попробовать что-то вроде

SELECT *
FROM TABLE
WHERE TABLE.ID NOT IN(
    SELECT ID
    FROM TABLE
    WHERE TABLE.VAL < '1'
    OR TABLE.VAL > '3'
)
Другие вопросы по тегам