В лекции № 7 "Введение в Oracle SQL" в подразделе "Несамостоятельность группировки с обобщениями ROLLUP, CUBE и GROUPING SETS" представленная таблица сравнения содержит ошибки - окончания запросов пропущены. Видимо, ошибки вызваны некорректным переносом материала лекции. |
Лекция 5: Выборка данных. Общее построение предложения SELECT и фразы FROM и WHERE
Фраза WHERE предложения SELECT
... Явились тут на нескольких листах:
Какой-то Шмидт, два брата Шулаковы,
Зерцалов, Палкин, Савич, Розенбах,
… …
… …
Мадам Гриневич, Глазов, Рыбин, Штих,
Бурдюк-Лишай — и множество других.
Многоточие в цитате из русского классика имеет тот же смысл, что и в приводившихся ранее ответах Oracle: рамки технического документа стеснительны для хорошей поэзии, равным образом как и для хорошей информационной системы. Чтобы сделать увлекательный, но несколько затянутый список более обозримым, Oracle рекомендует применить к стихотворению графа Толстого фразу WHERE.
Фраза WHERE принимает на входе строки, полученные в результате вычисления предшествующей фразы, отбирает из этих строк те, что дают значение "истина" для некоторого условного выражения, и отобранные таким образом строки передает следующим фразам в общей схеме выполнения запроса. Выполняемое ею действие унаследовано из реляционной модели, от операции, называемой там "ограничением" (выбраковкой, restriction). По этой причине, собственно, ей бы и следовало дать в SQL обозначение SELECT (от латинского selectus — "выбранный"), но создатели SQL отнесли это обозначение на счет данных вообще, а не строк.
Логический алгоритм отработки фразы WHERE прост:
Результат_WHERE := пусто; для каждой Строки во Входном_множестве выполнить: если Условное_выражение = TRUE то Результат_WHERE :+ Строка; конец цикла;
Ниже говорится о способах формирования условных выражений ради отбора строк фразой WHERE. Они строятся из обычных выражений с помощью операций сравнения и ряда иных, а также из прочих условных выражений с помощью логических операций.
Операторы сравнения значений
Сравнение "обычных" (числовых, строковых или временных) значений друг с другом — традиционный и очевидный способ получить условное выражение:
Оператор сравнения | Действие |
---|---|
= | равно |
< | меньше |
> | больше |
<= | меньше или равно |
>= | больше или равно |
<>, !=, ^= | не равно |
В силу исторических причин сравнение на неравенство имеет три равносильных обозначения. В стандарт SQL из них входит только <>.
Объектные типы сравнивать можно, только если это предусмотрено программистом БД в определении типа. Данные встроенных объектных типов XMLTYPE, или ANYDATA, например, сравнивать нельзя.
Сравнение строк текста
Строки текста типа CHAR имеют в Oracle при сравнении неочевидную особенность, уходящую корнями в стандарт SQL. Она состоит в игнорировании хвостовых пробелов при сравнении (на равенство или неравенство — не важно), например:
SQL> SELECT 'ok' FROM dual WHERE 'Париж' = 'Париж '; 'O -- ok SQL> SELECT 'ok' FROM dual WHERE 'Париж' <> 'Париж '; no rows selected
Одновременно эти "одинаковые" строки имеют в SQL все-таки разные свойства:
SQL> SELECT 'ok' FROM dual 2 WHERE LENGTH ( 'Париж' ) = LENGTH ( 'Париж ' ) 3 ; no rows selected
При выполнении операций обобщения или устранения дубликатов по столбцу (например, с использованием DISTINCT, GROUP BY или UNION) внутренняя логика осуществления которых подразумевает сравнение, такое поведение, по замечанию Кристофера Дейта, способно довести прикладного программиста до состояния медитации, официально делая результат запроса к БД непредсказуемым. Опыты показывают, что СУБД Oracle все же отошла здесь от стандарта и во внутренних сравнениях полагает, что 'Париж' = 'Париж ' не дает TRUE. Справедливости ради можно обратить внимание, что именно перечисленые операции типично будут выполнять внутренние сравнения на значениях, собраных в столбец, и будучи при этом приведенных СУБД к общему формату (выражаясь проще – дополненых положеным количеством пробелов), вследствие чего проблема себя не проявит.
Действия со строками типа VARCHAR2 учитывают хвостовые пробелы на правах обычных символов.
Логические операторы AND, OR и NOT в логических выражениях
Подобно выражениям прочих типов, логические могут строиться на основе более простых с помощью собственных, логических операторов. Таковыми служат бинарные AND и OR, а также унарный NOT. Отсутствие величины, обозначаемое как NULL, для логических значений допускается, как и для прочих. Формально символ NULL может восприниматься здесь как третье допустимое значение, дополняющее TRUE и FALSE, а это приводит SQL к трехзначной логике.
В рамках трехзначной логики таблицы значений для логических операторов выглядят следующим образом:
Встроенная шкала приоритетности выполнения операций допускает однозначные бесскобочные формулировки. Например, условие C1 OR C2 AND C3 отрабатывается так:
C2 AND C3 → a1 C1 OR a1 → результат
Тем не менее методически бесскобочной формулировкой рекомендуется пользоваться с осторожностью, только в самых очевидных случаях. Излишне последовательное ее применение провоцирует риски ошибок программиста, равно как и излишне педантичная расстановка скобок.
Упражнение. Выдайте всех сотрудников, кроме клерков и продавцов.
Следует обратить внимание на асимметрию отношения операций AND и OR к NULL в качестве одного из операндов. Содержательно она соответствует пониманию NULL как "неизвестно чего" (unknown): то ли TRUE, то ли FALSE, но чего-то из двух (а в стандарте SQL:1999 для булевского типа "третье" значение носит официальное название UNKNOWN). К сожалению, SQL ничего не противопоставляет иному пониманию NULL, в жизни допустимому (SQL как таковой вообще никак не учитывает никакое "понимание" и не связан с ним). Если в конкретных обстоятельствах NULL содержательно означает "значение отсутствует", булева логика SQL превращается для программиста в чистую формальность, не соотносящуюся с каким-либо интуитивным пониманием.
Сравните два примера замены прямого условного выражения на обратное:
SQL> SELECT 'ok' FROM dual WHERE 1 = 1 OR 1 = NULL; 'O -- ok SQL> SELECT 'ok' FROM dual WHERE NOT ( 1 = 1 OR 1 = NULL ); no rows selected В то же время: SQL> SELECT 'ok' FROM dual WHERE 1 = 2 OR 1 = NULL; no rows selected SQL> SELECT 'ok' FROM dual WHERE NOT ( 1 = 2 OR 1 = NULL ); no rows selected
Замена прямого условия на обратное требует внимания программиста: как минимум в SQL она не подвержена двузначной логике с психологически понятным человеку правилом "третьего не дано".