2009-05-13 2 views
7

Учитывая эти две таблицы:Предотвратить Oracle минус заявление от удаления дубликатов

CREATE TABLE TEST1 (TEST VARCHAR2(1 BYTE)) 
CREATE TABLE TEST2 (TEST VARCHAR2(1 BYTE)) 

Где TEST1 имеет две строки и со значением «A» и TEST2 имеет одну строку со значением «B».

Когда я запускаю эту команду:

SELECT TEST FROM TEST1 
MINUS 
SELECT TEST FROM TEST2 

Я получаю результат:

Test 
----- 
A 

Оказывается, что МИНУС удаляет дубликаты (так как есть два 'А' строки в TEST1).

Как вы можете получить запрос MINUS для включения повторяющихся значений (верните две строки «A»)?

ответ

0

Oracle поддерживает несколько столбцов в операторе IN, так что вы можете написать:

SELECT a, b, c 
FROM table1 
WHERE (a,b,c) not in (
    select a,b,c from table2 
) 
0

ВСЕ-модификатор UNION возвращает все строки (например, UNION ALL), может быть, он может быть применен к MINUS? Как и в случае

select field1 from table1 
minus all 
select field2 from table2 
+0

Этого я не могу бояться – cagcowboy

+0

Нет. Это будет иметь слишком много смысла;) –

0

Часть того, что делает минус, удаляет дубликаты. Подумайте об использовании NOT IN, чтобы избежать удаления дубликатов.

SELECT TEST FROM TEST1 WHERE TEST NOT IN(SELECT TEST FROM TEST2) 
1
SELECT field1 FROM table1 WHERE field1 NOT IN (SELECT field2 FROM table2) 

будет работать так долго, как field2 не может содержать значения NULL.

+0

Единственное, что на самом деле используется минус-оператор, выбирающий больше, чем просто одно поле (он выбирает 10 полей). –

+0

Вы можете сделать это с помощью нескольких столбцов ...WHERE (a, b) NOT IN (SELECT x, y FROM table2) –

7

Другим вариант:

SELECT TEST, row_number() OVER (PARTITION BY TEST ORDER BY TEST) FROM TEST1 
MINUS 
SELECT TEST, row_number() OVER (PARTITION BY TEST ORDER BY TEST) FROM TEST2 

Это будет МИНУС с каждым дубликатом рассматривается как отдельная запись. Обратите внимание, что в примере ниже, если TEST1 имеет два значения «C», а TEST2 имеет только один, вы получаете один из них.

dev> select * from test1; 

T 
- 
A 
A 
B 
C 
C 

dev> select * from test2; 

T 
- 
B 
C 

dev>  SELECT TEST, row_number() OVER (PARTITION BY TEST ORDER BY TEST) FROM TEST1 
    2  MINUS 
    3  SELECT TEST, row_number() OVER (PARTITION BY TEST ORDER BY TEST) FROM TEST2 
    4/

T ROW_NUMBER()OVER(PARTITIONBYTESTORDERBYTEST) 
- -------------------------------------------- 
A           1 
A           2 
C           2 
1

"NOT IN" ответы верны. Альтернатива, которая может быть проще для некоторых сценариев, является «НЕ СУЩЕСТВУЕТ» Оператор:

SELECT TEST FROM TEST1 
WHERE NOT EXISTS 
(SELECT null FROM TEST2 WHERE TEST2.TEST = TEST1.TEST); 

(Примечание: «нуль» в выбранном пункте не имеет смысла здесь)

Я лично использую оба метода , но мне часто нравится НЕ СУЩЕСТВУЮЩИЙ, потому что он более гибкий - например, для сравнения не требуется сравнение.

Последние версии оптимизатора часто преобразуют NOT IN в NOT EXISTS или наоборот; однако, если вы используете более старую версию (например, 8i или даже 9i, я думаю), вы можете увидеть преимущества производительности при переключении между этими двумя методами.

0
SELECT TEST FROM TEST1 WHERE TEST IN(
SELECT TEST FROM TEST1 
MINUS 
SELECT TEST FROM TEST2); 
+0

Пожалуйста, объясните, как ваш ответ решает проблему, и это поможет каждому понять ваше решение с большей ясностью и будущей ссылкой. – Aziz

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