Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
Порядок обработки условий в WHERE
|
|||
|---|---|---|---|
|
#18+
\nCREATE TABLE customers ( cust_id int PRIMARY KEY, cust_name char(20) ) CREATE TABLE orders ( order_id int PRIMARY KEY, cust_id int REFERENCES customers(Cust_id) ) GO INSERT customers VALUES (1, 'cust 1') INSERT customers VALUES (2, 'cust 2') INSERT customers VALUES (3, 'cust 3') INSERT orders VALUES (10001, 1) INSERT orders VALUES (20001, 2) GO Условие: не включать Cust2. Новый синтаксис (использование LEFT JOIN) решает эту здачу: \n... не устраните только ряд со значением NULL, который сохраняется при внешнем соединении! SELECT C.cust_id, C.cust_name, O.cust_id FROM Customers C LEFT JOIN Orders O ON C.cust_id=O.cust_id WHERE O.cust_id <> 2 or O.cust_id IS NULL Результаты таковы: cust_id cust_name cust_id ----------- -------------------- ----------- 1 cust 1 1 3 cust 3 (null) теперь старый: \n...теперь попробуем исключить Cust 2 с использованием старого синтаксиса: SELECT C.cust_id, C.cust_name, O.cust_id FROM Customers C, Orders O WHERE C.Cust_ID *= O.Cust_id AND (O.cust_id <> 2 or O.cust_id IS NULL) Вот результат: cust_id cust_name cust_id ----------- -------------------- ----------- 1 cust 1 1 2 cust 2 (null) 3 cust 3 (null) Как видите, в этот раз от Cust2 избавиться не удалось. Проверка на NULL выполняется перед соединением , так что операция соединения возвращает Cust2 обратно... Вы можете возразить, что в предыдущем запросе мне следовало задавать фильтр по Customer.Cust_id, а не по Orders.Cust_id: SELECT C.cust_id, C.cust_name, O.cust_id FROM Customers C, Orders O WHERE C.Cust_ID *= O.Cust_id AND (C.cust_id <> 2 or O.cust_id IS NULL) В результате получается: cust_id cust_name cust_id ----------- -------------------- ----------- 1 cust 1 1 2 cust 2 (null) 3 cust 3 (null) Увы ничего не изменилось! Теперь дело в том, что условие Orders.cust_id IS NULL применяется после (!!!) внешнего соединения !!! Я в шоке... То ДО, то ПОСЛЕ... Какой порядок? Спасибо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.06.2001, 12:27 |
|
||
|
Порядок обработки условий в WHERE
|
|||
|---|---|---|---|
|
#18+
2 Excel Это известная проблема и здесь уже как то обсуждалась, см. в BOL Specifying Joins in FROM or WHERE Clauses. Все дело в том, что ограничения на выборку сервер накладывает как бы слева направо сначала Join потом Where, а затем Having. Исходя из этого и пишите запросы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.06.2001, 12:49 |
|
||
|
Порядок обработки условий в WHERE
|
|||
|---|---|---|---|
|
#18+
Возможно "слева - направо", но тогда эта цитата не вяжется %( [quote]Проверка на NULL выполняется перед соединением[/qoute] ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.06.2001, 13:27 |
|
||
|
Порядок обработки условий в WHERE
|
|||
|---|---|---|---|
|
#18+
а не выполняется ничего ПЕРЕД соединением, а выполняется одновременное ограничение, грубо говоря ваш запрос можно переписать немного в другом виде и сразу станет все ясно. Ваш запрос SELECT C.cust_id, C.cust_name, O.cust_id FROM Customers C, Orders O WHERE C.Cust_ID *= O.Cust_id AND (O.cust_id <> 2 or O.cust_id IS NULL) Тепер изменим SELECT C.cust_id, C.cust_name, O.cust_id FROM Customers C, Orders O WHERE (C.Cust_ID *= O.Cust_id AND O.cust_id <> 2) or (C.Cust_ID *= O.Cust_id and O.cust_id IS NULL) Понятно? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.06.2001, 13:43 |
|
||
|
Порядок обработки условий в WHERE
|
|||
|---|---|---|---|
|
#18+
Т. е. я хотел сказать что по ограничениям вот эти два запроса идентичны: SELECT C.cust_id, C.cust_name, O.cust_id FROM Customers C, Orders O WHERE C.Cust_ID *= O.Cust_id AND (O.cust_id <> 2 or O.cust_id IS NULL) SELECT C.cust_id, C.cust_name, O.cust_id FROM Customers C, Orders O WHERE C.Cust_ID *= O.Cust_id ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.06.2001, 13:45 |
|
||
|
Порядок обработки условий в WHERE
|
|||
|---|---|---|---|
|
#18+
М-да. Забавная вещица. Посмотрите на планы выполнения запросов с JOIN и без. Они на самом деле по разному работают. Отсюда мораль. Хочешь однозначного результата - пользуйся Join. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.06.2001, 14:26 |
|
||
|
Порядок обработки условий в WHERE
|
|||
|---|---|---|---|
|
#18+
2 zamm Речь идет не о выборе оператора. Ни кто не сомневается в преимуществах JOIN (эти примеры взяты именно из главы, в которой объясняются преимущества использования внешних соединений JOIN над оператором *= ). Более того, я скорее всего ни когда не буду использовать "*=" . Но я буду использовать WHERE! Речь о том, что два практически одинаковых запроса, отдают приоритет фильтрам по совершенно непонятной мне логике... 2 Genady >понятно? Увы, нет Я, пожалуй, заострю внимание на самом вопросе (больно длинные видно были цитаты в первом постинге ) Есть два запроса. Меняется только одна таблица в условии (выделяю жирным). Результат - изменение порядка применения ограничений в WHERE: \nSELECT C.cust_id, C.cust_name, O.cust_id FROM Customers C, Orders O WHERE C.Cust_ID *= O.Cust_id AND (O.cust_id <> 2 or O.cust_id IS NULL) --(Проверка на NULL выполняется перед соединением) и SELECT C.cust_id, C.cust_name, O.cust_id FROM Customers C, Orders O WHERE C.Cust_ID *= O.Cust_id AND ( C .cust_id <> 2 or O.cust_id IS NULL) --(условие Orders.cust_id IS NULL применяется после внешнего соединения) Сравните. Просто заменили поле одной таблицы, на аналогичное поле другой таблицы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.06.2001, 16:05 |
|
||
|
Порядок обработки условий в WHERE
|
|||
|---|---|---|---|
|
#18+
Ну неправильно Вы запрос написали, послушайте zamm, посмотрите планы запросов и понятно все станет. В случае, когда не используется join не разделяется фильтр и соединение, а сразу накладываются ограничения. Хотите, чтобы работало с Where, тогда вот такой запрос писать надо: SELECT C.cust_id, C.cust_name, O.cust_id FROM Customers C, Orders O WHERE C.Cust_ID *= O.Cust_id AND C.cust_id <> 2 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 26.06.2001, 05:17 |
|
||
|
Порядок обработки условий в WHERE
|
|||
|---|---|---|---|
|
#18+
2 Genady Это не я запрос написал Это примеры взятые из книги (см. описание темы). А правильный запрос, составленный Вами, приводится в книге в качестве решения этой проблемы Но важно не это. Важно то, что я понял суть: [qoute]"В случае, когда не используется join не разделяется фильтр и соединение, а сразу накладываются ограничения."[/quote] Спасибо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 26.06.2001, 05:46 |
|
||
|
Порядок обработки условий в WHERE
|
|||
|---|---|---|---|
|
#18+
В базовой реляционной теории select from Table1, Table2 where (...SomeCondition...) запрос выбирает из двух таблиц декартово произведение записей (количество записей в результате равно произведению кол-ва записей Table1 на кол-во записей Table2), а уже после этого на полученный результат накладывает фильтр SomeCondition. Ясно, что реальные СУБД все запросы оптимизируют таким образом, чтобы избежать получения декартового произведения записей. Они прилагают все усилия, чтобы наложить фильтр до или во время объединения. Именно поэтому все подобные запросы автоматом преобразуются в запросы с JOIN. А для того, чтобы систематизировать наложение фильтров до или во время объединения по JOIN условие разбивается на объединяемые по AND и разделяемые по OR. Условия, объединяемые по AND в совокупности многократно ограничивают поток записей от источника, поэтому такие условия объединяются в одну логическую нитку. Условия, разделяемые по OR выделяются в разные логические нитки, по каждой из которых получается собственный набор данных. На выходе условия OR полученные наборы данных сливаются в единый набор данных. С учетом того, что в сливаемых наборах некоторые записи могут дублироваться (как отвечающие обеим частям условия), сервер производит "лишнюю" работу по их выборке, что существенно сказывается на быстродействии (не говоря уже о лишней операции объединения наборов). Поэтому нужно стараться избегать условий OR в запросах, на сколько это возможно. Genady совершенно верно подсказал, в запрос какого вида SQL-сервер автоматом преобразует ваш запрос. Для того, чтобы убедиться в этом, достаточно создать VIEW с текстом такого запроса в EM и сохранить его, а потом открыть на модификацию текст VIEW - вы увидите, что текст запроса преобразован в эквивалентный (с точки зрения SQL-сервера) запрос с другим текстом. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 26.06.2001, 15:52 |
|
||
|
Порядок обработки условий в WHERE
|
|||
|---|---|---|---|
|
#18+
2 Garya Спасибо. Теорию вразумел. Очень люблю исчерпывающюю теорию. Кстати, если это не Ваших рук дело, то укажите пожалуйста источник. Понятно написано. (Но разницу между двумя запросами так и не понял... поэксперементирую действительно с вьюхами) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 26.06.2001, 18:20 |
|
||
|
Порядок обработки условий в WHERE
|
|||
|---|---|---|---|
|
#18+
2 Excel Дело здесь вовсе не в теории, а в неправильно заданным условиям в Where. or O.cust_id IS NULL в условии начисто отметает любые ограничения стоящие с ним, ведь это условие уже заданно в выражении C.Cust_ID *= O.Cust_id, поэтому совершенно бессмысленно ставит с ним еще какие либо ограничения через Or. Выражение WHERE C.Cust_ID *= O.Cust_id AND (C.cust_id <> 2 or O.cust_id IS NULL) эквивалентно выражению WHERE C.Cust_ID *= O.Cust_id OR C.cust_id <> 2 Непонимаю какая проблема рассматривалась в книге, наверное эта проблема в том, что как хорошо было бы если бы запросы возвращали нам тот набор записей, какой мы хотим получить вне зависимости от того как написан запрос ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.06.2001, 03:25 |
|
||
|
|

start [/forum/topic.php?fid=46&msg=32008312&tid=1826361]: |
0ms |
get settings: |
11ms |
get forum list: |
23ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
33ms |
get topic data: |
13ms |
get forum data: |
3ms |
get page messages: |
70ms |
get tp. blocked users: |
2ms |
| others: | 257ms |
| total: | 418ms |

| 0 / 0 |
