SQL Server: оператор WHERE. Продолжение
В отличие от внутренних соединений, роль операторов ON и WHERE во внешних соединениях совершенно иная. Оператор WHERE по-прежнему используется в обычной роли фильтрации строк из виртуальной таблицы, возвращенной оператором FROM. Оператор ON играет более сложную роль сопоставления. Во внешнем соединении таблица отмечается как сохраненная. Например, в Sales.Customers AS С LEFT OUTER JOIN Sales.Orders AS О ON C.custid = O.custid таблица Customers отмечена как сохраненная, а предикат C.custid = O.custid считается предикатом сопоставления. Это означает, что будут сохранены все строки из таблицы Customers, независимо от исхода предиката сопоставления. Оператор ON определяет, какие строки с несохраненной стороны (Orders) сопоставляются со строками на сохраненной стороне (Customers). Клиент (customer) без единого сопоставленного заказа (order) все же возвращается со значениями NULL в качестве местозаполнителей для атрибутов из Orders. Типичная ошибка, которая происходит из-за путаницы между сопоставлением и фильтрацией, заключается в применении предполагаемого предиката сопоставления в операторе ON как предиката фильтрации в операторе WHERE. Например, предположим, в запросе нужно фильтровать только клиентов из Испании, но сопоставлять заказы клиентам, только если идентификатор клиента на обеих сторонах одинаков, а заказ размещен в 2016 году или позднее. Интуитивно пользователи задают предикаты, которые сравнивают элементы с обеих сторон в операторе ON и предикаты, применяемые к элементам с одной стороны в операторе WHERE. Такой подход в случае с нашим запросом приводит к ошибке, как показано в листинге ниже.
Предполагается, что предикат С.country = N'Spain' является предикатом фильтрации и используется как таковой в нашем запросе. Нужно сохранить только клиентов из Испании и отбросить остальных. Однако предполагается, что предикат O.orderdate >= '2016010 Г является предикатом сопоставления, так как необходимо сохранить клиентов, которые не размещали заказы в течение этого периода, но сейчас вы применяете его как предикат фильтрации. Поэтому клиенты, которые не делали заказов в течение этого периода, отбрасываются. На самом деле соединение в этом запросе становится внутренним соединением. Любые внешние строки, выданные внешним соединением для клиентов без заказов, имеют значения NULL в столбце orderdate, и фильтр O.orderdate >= ‘20160101’ отбрасывает их. Оптимизатор SQL Server применяет обнаружение несоответствий и преобразует внешнее соединение во внутреннее, предоставляя тот же план, который показан для запроса с внутренним соединением на рисунке выше. Чтобы исправить ошибку, необходимо применить предикат O.orderdate >= ‘20160101' как предикат сопоставления в операторе ON, например как в листинге ниже.
Этот запрос формирует вывод, представленный на экране выше.
Обратите внимание, что клиент 22 является клиентом из Испании, который не размещал заказов с начала 2016 года. План этого запроса показан на рисунке выше.
На этот раз оптимизатор обрабатывает соединение как внешнее.
Разберетесь с оператором Where в SQL как-нибудь в другой раз, потому что сейчас все ваше свободное время занимает прокачка вашего авто. Так в данный момент вы ищите где бы купить катализатор (http://замена-катализатора.москва/купить-катализатор/) от именитого производителя, который мог бы похвастаться невысокой ценой и отличным качеством. Спешу вам сообщить, что совершить такую покупку вы сможете на сайте замена-катализатора.москва.