Вопросы и ответы по MS SQL Server

  Все выпуски  

Вопросы и ответы по MS SQL Server


Информационный Канал Subscribe.Ru


Вопросы и ответы по MS SQL Server

Выпуск No. 16 от 2003-06-06

Вопрос : Как вычесть из таблицы те строки, которые есть в другой таблице?

Ответ:
Людей, которые знакомы только с MS SQL Server, такой вопрос ставит в тупик. Что здесь сложного? Берете и пишите запросик с использованием EXISTS или JOIN.
Но почему такой вопрос возникает у людей хорошо знающих SQL?
А вот почему. В стандарте ANSI SQL-92 кроме оператора объединения наборов данных (UNION) есть оператор вычитания (EXCEPT) и пересечения (INTERSECT).
В некоторых СУРБД есть реализация этих операторов, а в MS SQL Server нет. Например, в Oracle существует эквивалент оператора EXCEPT - MINUS.

А что же делать? Почему пользователей MS SQL Server так обделили? Может для того, чтобы не загружать лишними операторами?
Теперь уже не важно. Важно, что операторы EXCEPT и INTERSECT заменяются простыми запросами. А в случае с UNION такое себе сложно представить.

Итак. Чем заменить оператор EXCEPT? Или как вычесть из набора данных те строки, которые есть в другом наборе данных?
Создадим таблицы для экспериментов:
CREATE TABLE Set1 (Col1 int, Col2 int)

CREATE TABLE Set2 (Col1 int, Col2 int)
INSERT Set1 VALUES (1,2)
INSERT Set1 VALUES (2,3)
INSERT Set1 VALUES (2,3)
INSERT Set1 VALUES (3,4)
INSERT Set1 VALUES (4,5)
INSERT Set1 VALUES (4,5)
INSERT Set1 VALUES (5,6)

INSERT Set2 VALUES (1,2)
INSERT Set2 VALUES (2,3)
INSERT Set2 VALUES (5,6)
INSERT Set2 VALUES (5,6)

Первый очевидный способ заключается в использовании оператора EXISTS:
SELECT * FROM Set1 s1

WHERE NOT EXISTS(
SELECT * FROM Set2 s2
WHERE s2.Col1=s1.Col1 AND s2.Col2=s1.Col2
)

Результат выполнения:
Col1        Col2

----------- -----------
3 4
4 5
4 5

(3 row(s) affected)

В секции WHERE необходимо перечислять все столбцы, по которым идет вычитание наборов данных. Как правило, в таблицах есть один уникальный столбец - идентификационный номер. В таком случае перечисление всех столбцов не требуется.
Показанный выше код можно переписать используя оператор JOIN:
SELECT s1.*

FROM Set1 s1
LEFT JOIN Set2 s2 ON s1.Col1=s2.Col1 AND s1.Col2=s2.Col2
WHERE s2.Col1 IS NULL

Выбирайте сами вариант, который Вам больше нравиться. От себя лишь добавлю, что на MS SQL Server 2000 первый вариант работает быстрее, т.к. имеет более оптимальный план выполнения.

Если Вы внимательно посмотрели результат запроса, то заметили, что он содержит дублированные строки. Стандарт ANSI SQL-92 предусматривает для операторов EXCEPT и INTERSECT дополнительное ключевое слово ALL. Работает оно точно так же как и в случае с оператором UNION - при объявлении ALL строки-дубликаты в результате запроса не уничтожаются. А в показанных выше примерах была показана замена оператору EXCEPT ALL.
Таким образом, для замены оператора EXCEPT просто нужно добавить в запрос ключевое слово DISTINCT:
SELECT DISTINCT * FROM Set1 s1

WHERE NOT EXISTS(
SELECT * FROM Set2 s2
WHERE s2.Col1=s1.Col1 AND s2.Col2=s1.Col2
)

На этом закончим. Удалить созданные объекты можно с помощью следующего кода:
DROP TABLE Set1

DROP TABLE Set2

Обсудить и оценить эту статью >>
Надеюсь, Вы нашли эту информацию полезной. Вопросы, предложения и пожелания шлите на адрес sql@likor.ru
С уважением, Сергей Кошкин.
Архив рассылки смотрите на сайте Рассылки http://sql.softmatics.ru/
Рейтинг@Mail.ru

http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное