2011-01-27 4 views
2

Say У меня есть запрос, как это:Исключить строки на основе других строк (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 и ФХЦЧ отсутствует):

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

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

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

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

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

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

Спасибо!

+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)) 
+0

Я уверен, что это то, что мне нужно. «Мы имеем дело с Progress 4GL, и они делают все возможное, давая палец стандартам SQL, поэтому это дает мне массу проблем. – corsiKa

+0

Для справки это решило проблему. Оказывается, парень возвращался более 1000 строк и удаление их в программном обеспечении, чтобы обрезать его до 80 или около того, в котором он нуждался. Это заняло 24-секундный запрос до 2 (и я готов поспорить, что большинство из них являются транзакционными накладными расходами ...) Спасибо! – corsiKa

1

вы можете использовать минус-оператор.

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

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

кажется элегантным :) – corsiKa

+0

МИНУС - это Oracle, специфический, нет? ANSI будет EXCEPT –

1

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

SELECT * 
FROM TABLE 
WHERE TABLE.ID NOT IN(
    SELECT ID 
    FROM TABLE 
    WHERE TABLE.VAL < '1' 
    OR TABLE.VAL > '3' 
) 
+0

Мне не гарантируются последовательные номера :( – corsiKa

+0

ну, вы просто меняете подзапрос от большего/меньше допустимого диапазона до WHERE IN (плохие значения) – WebChemist

1

Вот еще один вариант, который будет проходить через ТПС один раз, агрегат, и с использованием найденные идентификаторы, извлечение данных из 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 
+0

Есть ли способ сделать это, когда идентификатор является мульти-ключом?Например, у меня есть компания и номер заказа для идентификации записи. – corsiKa

+0

@ glow - обязательно, см. Обновленный ответ – RichardTheKiwi

Смежные вопросы