Опубликован: 28.12.2011 | Уровень: для всех | Доступ: свободно

Лекция 5: Выборка данных. Общее построение предложения SELECT и фразы FROM и WHERE

Фраза WHERE предложения SELECT

... Явились тут на нескольких листах:

Какой-то Шмидт, два брата Шулаковы,

Зерцалов, Палкин, Савич, Розенбах,

… …

… …

Мадам Гриневич, Глазов, Рыбин, Штих,

Бурдюк-Лишай — и множество других.

A. K. Toлcтoй, "Сон Попова"

Многоточие в цитате из русского классика имеет тот же смысл, что и в приводившихся ранее ответах 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 к трехзначной логике.

В рамках трехзначной логики таблицы значений для логических операторов выглядят следующим образом:

AND:
TRUE NULL FALSE
TRUE TRUE NULL FALSE
NULL NULL NULL FALSE
FALSE FALSE FALSE FALSE
OR:
TRUE NULL FALSE
TRUE TRUE TRUE TRUE
NULL TRUE NULL NULL
FALSE TRUE NULL FALSE
NOT:
NOT (TRUE) NOT (NULL) NOT (FALSE)
FALSE NULL TRUE

Встроенная шкала приоритетности выполнения операций допускает однозначные бесскобочные формулировки. Например, условие 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 она не подвержена двузначной логике с психологически понятным человеку правилом "третьего не дано".

Ярослав Прозоров
Ярослав Прозоров

В лекции № 7 "Введение в Oracle SQL" в подразделе "Несамостоятельность группировки с обобщениями ROLLUP, CUBE и GROUPING SETS"  представленная таблица сравнения содержит ошибки - окончания запросов пропущены. Видимо, ошибки вызваны некорректным переносом материала лекции.

Володимир Миколайчук
Володимир Миколайчук
Помогите разобраться поетапно с логикой запроса
-------TOOLS
NAME PRICE TYPE
drill 155 A
sawzall 192 N
mitre saw 292 M
router 86 I
RAD 145 M
jigsaw 128 I
screwdriver 77 P
------TOOL_TYPES
TYPE USAGE
A Always
I Often
M Sometimes
N Rarely
P Never

Запрос SQL:
SELECT t.type, SUM(t.price)
FROM tools t
GROUP BY t.type
HAVING SUM(t.price) >= (SELECT AVG(price)
FROM tools
WHERE type IN (SELECT type
FROM tool_types
WHERE usage = 'Often'));

И сколько строк он все таки вернет
Жанбек Сарсенов
Жанбек Сарсенов
Россия, Москва, Московский Государственный Университет имени Ломоносова М.В., 2002