Информационный сайт

 

Реклама
bulletinsite.net -> Книги на сайте -> Программисту -> Тоу Д. -> "Настройка SQL. Для профессионалов" -> 111

Настройка SQL. Для профессионалов - Тоу Д.

Тоу Д. Настройка SQL. Для профессионалов — СПб.: Питер, 2004. — 333 c.
ISBN 5-94723-959-0
Скачать (прямая ссылка): nastroykasqldlyaprof2004.djvu
Предыдущая << 1 .. 105 106 107 108 109 110 < 111 > 112 113 114 115 116 117 .. 161 >> Следующая


Рассмотрим слегка отличающийся пример:

SELECT ,.. FROM Employees E

LEFT OUTER JOIN Departments D

ON E.DepartmentJD - D.DepartmentJD WHERE D.DepartmentJD IS NULL

С первого взгляда кажется, что это неестественный запрос, потому что первичный ключ (Department_ID) таблицы Departments не может быть равен null. Даже если бы null было допустимым значением первичного ключа, подобное соединение с другой таблицей никогда бы не было успешным для такого ключевого значения (так как условное выражение NULL = NULL возвращает истинностное значение «неизвестно»), Однако, так как это внешнее соединение, существует разумная интерпретация этого запроса — «Найти всех сотрудников, для которых не существует соответствующих отделов». Во внешнем случае этих внешних соединений все столбцы Departments, включая даже обязательно не равные null столбцы, получат значение null, поэтому условие D. DepartmentJD IS NULL будет истинно только во внешнем случае. Есть и более распространенный и простой для восприятия способ записи этого запроса:

SELECT ...

FROM Employees E

WHERE NOT EXISTS (SELECT *

FROM Departments D

WHERE E.DepartmentJD = D.DepartmentJD)

Хотя форма NOT EXISTS запросов такого рода более естественна и ее проще читать и понимать, в настройке SQL есть место и для другой формы (для лучшего понимания ее рекомендуется хорошо комментировать). Преимущество выражения условия NOT EXISTS в виде внешнего соединения, за которым следует Первич-ный_ключ IS NULL, заключается в том, что такая форма позволяет более точно контролировать, когда именно в плане исполнения будет выполнено соединение, и когда будет использована селективность этого условия. Обычно условия NOT EXISTS оцениваются после всех обычных соединений, по крайней мере, в Oracle. Это один из примеров, когда фильтр (не являющийся частью внешнего соединения) на присоединяемой внешне таблице действительно может быть предумышленным и верным.
226

7. Диаграммное изображение и настройка сложных SQL-запросов

ПРИМЕЧАНИЕ------------------------------------------------------------------------—--------

В старой записи внешних соединений в SQL Server комбинация внешнего соединения и условия «равно null» не работает. Например, преобразуя предыдущий пример в запись SQL Server, вы могли бы попробовать такой запрос:

SELECT ...

FROM Employees Е. Departments D WHERE E.Department_ID *= D.Department_ID AND D.Department_ID IS NULL Ho результат был бы совсем не тот, которого вы ожидаете! Вспомните, что SQL Server интерпретирует все фильтрующие условия для присоединяемой внешне таблицы itait часть соединения. SQL Server попытается провести соединение со строками Departments, для которых существуют равные null первичные ключи (например, значения D. Department_IU, равные null). Даже если бы такие строки существовали, нарушая правильный дизайн базы данных, они бы никогда не могли быть успешно присоединены к таблице Empl Oyees, так как соединение по условию равенства не может быть успешно выполнено для ключевых значений, равных null. Вместо этого запрос не отфильтрует никакие строки, а вернет всех сотрудников, причем все соединения будут внешними.

Внешние соединения, ведущие к внутренним соединениям

Рассмотрим рис. 7.24, на котором внешнее соединение ведет к внутреннему соединению.

Tl

ТЗ

Рис. 7.24. Внешнее соединение ведет к внутреннему соединению

В старом стиле Oracle SQL подобное соединение записывается так:

SELECT ...

FRDM Tablel Tl. Tablе2 Т2. TablеЗ ТЗ WHERE Tl.FKey2 = Т2.РКеу2(+) •

AND T2.FKey3 = ТЗ.РКеуЗ

Во внешнем случае первого соединения база данных сгенерирует псевдостроку из Т2, причем значение всех столбцов, в том числе Т2. FKey3 будет равно null. Однако равный null внешний ключ никогда не может быть успешно присоединен к другой таблице, поэтому строка, представляющая внешний случай соединения, будет отброшена при попытке выполнить внутреннее соединение с ТЗ. Таким образом, внешнее соединение, ведущее к внутреннему соединению, дает в точности тот же результат, который вы бы получили, если бы оба соединения были внутренними. Ho его стоимость выше, так как база данных отбрасывает стоки, которые не удовлетворяют соединению, позже в плане исполнения. Это всегда будет ошибкой. Если разработчик требует сохранить подобное соединение, замените внешнее соединение, ведущее к внутреннему, внешним соединением, ведущим к другому внешнему соединению. В противном случае используйте два внутренних соединения.
Необычные диаграммы соединений

227

Внешние соединения, указывающие на детальную таблицу

Рассмотрим рис. 7.25, где указатель стрелки посередине связи обозначает внешнее соединение, указывающее на детальную таблицу.

Или в старой записи Oracle:

SELECT ...

FROM Departments D. Employees E

WHERE D.Department_ID = E.Department_ID(+)

В старой записи SQL Server:

SELECT ...

FROM Departments D. Employees E WHERE D.Department_ID *= E.Department_ID

В любом случае, что же семантически означает этот запрос? Его можно представить как обращение: «Перечисли мне всех сотрудников, для которых указаны отделы (внутренний случай), а также данные об их отделах, и еще присовокупи данные об отделах, в которых нет сотрудников (внешний случай)». Во внутреннем случае результат сопоставляет каждую строку с детальной сущностью (сотрудник, принадлежащий какому-то отделу), а во внешнем случае результат отображает каждую строку на главную сущность (отдел, не принадлежащий ни одному сотруднику). Маловероятно, что такая нелепая смесь сущностей будет полезна и необходима в одном запросе, поэтому подобные запросы, в которых внешние соединения ведут к детальным таблицам, редко бывают верны. Самый распространенный случай такой ошибки — это соединение с детальной таблицей, которая обычно предлагает ноль или одну детальную строку для каждой главной, и лишь изредка это соединение предлагает несколько детальных строк для главной таблицы. Иногда разработчики упускают из виду последствия этого редкого случая «многие к одному», а во время тестирования ошибка может и не всплыть.
Предыдущая << 1 .. 105 106 107 108 109 110 < 111 > 112 113 114 115 116 117 .. 161 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100