Язык выборки данных
Выбери формат для чтения
Загружаем конспект в формате pdf
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
ЛЕКЦИЯ № 5
3. ЯЗЫК ВЫБОРКИ ДАННЫХ..........................................................................1
3.1. Синтаксис запроса SELECT......................................1
3.2. Запросы к одной таблице...........................................6
3.2.1. Секции SELECT и FROM..................................9
3.2.2. Секция WHERE................................................19
3.2.2.1. Простое сравнение................................20
3.2.2.2. Сравнение значений с плавающей запятой в Oracle
22
3.2.2.3. Проверка на логическое значение.........22
3.2.2.4. Проверка на принадлежность диапазону значений
23
3.2.2.5. Проверка на соответствие шаблону. .24
3.2.2.6. Проверка на членство во множестве. 26
3.2.2.7. Проверка на NULL.................................26
3.2.2.8. Проверка на наличие последовательности символов
27
3.2.2.9. Проверка на семантическое совпадение28
3.2.2.10. Проверка на совпадение с началом строки 29
3.2.2.11. Проверка двух значений на отличие. .29
3.2.2.12. Проверка на соответствие регулярному выражению 30
3.2.2.13. Составные условия поиска..................32
3. ЯЗЫК ВЫБОРКИ ДАННЫХ
В этой главе приводятся возможности SQL-запросов, называемых языком
выборки данных из базы данных, или DQL (Data Query Language). Это самая
большая глава из представленных в настоящем учебнике, потому что именно
для организации выборки информации из БД SQL используется наиболее
интенсивно подавляющим большинством пользователей.
Начиная с самых простых возможностей и последовательно переходя
ко все более сложным конструкциям, в данной главе рассматриваются
практически все указанные в стандарте SQL средства выборки данных. Глава
содержит большое количество примеров, выполненных на учебной БД под
управлением различных СУБД (Firebird, Oracle, MS SQL Server). Изложение
данной главы будем вести, опираясь по умолчанию на синтаксис и
особенности выполнения запросов в СУБД Firebird, запросы в других СУБД
будут приведены для сравнения, если они имеют отличия в плане синтаксиса
или результата выполнения.
Кроме указанных в стандарте SQL средств выборки данных, в главе
представлены некоторые дополнительные возможности, реализованные
в СУБД Firebird, Oracle и MS SQL Server.
3.1. СИНТАКСИС ЗАПРОСА SELECT
Для выборки данных из БД используется запрос-выборка SELECT. Он
позволяет производить выборку требуемых данных из таблиц и
преобразовывать в нужный вид полученные результаты. В общем случае
1
результатом реализации запроса SELECT является другая таблица, которую
будем называть набором данных (НД). К этой новой (рабочей) таблице может
быть снова применен запрос SELECT, т. е. такие операции могут быть вложены
друг в друга.
Вот так в общем виде выглядит SQL-запрос на выборку данных из таблиц
реляционной базы данных. Указывается, что нужно выбрать, откуда, какие
при этом установить критерии отбора и каким образом отсортировать строки
в результате запроса:
SELECT <что> FROM <откуда>
[WHERE <список условий отбора строк>]
[GROUP BY <столбец>] [HAVING <условие отбора групп>]
[ORDER BY {<столбец> [ASC|DESC]}]; .
SELECT (выбрать) – данные из указанных столбцов и (если необходимо)
выполнить перед выводом их преобразование в соответствии с указанными
выражениями и (или) функциями. Под "что" подразумевается список
столбцов таблиц или столбцов запроса (через запятую). FROM (из, откуда) –
перечисленных таблиц, в которых расположены эти столбцы, под "откуда" –
сами эти таблицы и подзапросы (также через запятую). В квадратных
скобках указаны необязательные части SQL-запроса, к которым, в том числе,
относится секция WHERE (где).
WHERE (где) – строки из указанных таблиц должны удовлетворять
указанному перечню условий отбора строк. В секции WHERE перечисляются
ограничения на значения столбцов, объединенные логическими операциями
И (AND) и ИЛИ (OR). Фактически, в секции WHERE задается условие,
которое может быть верным или неверным для каждой строки или
комбинации строк таблицы в секции FROM.
GROUP BY (группируя по) – указанному перечню столбцов с тем, чтобы
получить для каждой группы единственное агрегированное значение,
используя в секции SELECT SQL-функции SUM (сумма), COUNT
(количество), MIN (минимальное значение), MAX (максимальное значение)
или AVG (среднее значение).
HAVING (имея) – в результате лишь те группы, которые удовлетворяют
указанному перечню условий отбора групп.
Самый обычный SQL запрос выглядит примерно так:
SELECT Таблица1.Столбец1, Таблица2.Столбец2
FROM Таблица1, Таблица2
WHERE Таблица1.Столбец1 >10 AND
Таблица1.Столбец2 = Таблица2.Столбец1
ORDER BY Таблица1.Столбец1 ASC, Таблица2.Столбец2 DESC;.
Сразу можно заметить, что в условиях отбора строк допускается
использовать не только те столбцы, что перечислены в секции SELECT, а
любые столбцы таблиц, перечисленных в секции FROM.
Запрос SELECT может использоваться:
2
как самостоятельная команда на получение и вывод строк таблицы,
сформированной из столбцов и строк одной или нескольких таблиц
(представлений);
элемент SELECT, WHERE- или HAVING-условия (сокращенный вариант
предложения, называемый «вложенный запрос»);
запрос на формирование данных представления в команде CREATE VIEW;
средство выборки информации, необходимой для модификации данных
в других таблицах (многострочные запросы DML);
средство присвоения глобальным переменным значений из строк
сформированной таблицы (INTO-фраза).
Рассмотрим синтаксис запроса SELECT в СУБД Firebird, Oracle и MS SQL
Server.
Полный синтаксис запроса SELECT в Firebird имеет вид [29, 40, 44]:
[WITH [RECURSIVE]
имя_производной_таблицы1 [(<список_столбцов>)]
AS (<табличный_подзапрос> )
[, имя_производной_таблицы2 [(<список_столбцов>)]
AS (<табличный_подзапрос> )...]
SELECT [FIRST m] [SKIP n]
[{DISTINCT | ALL}]
{* | <возвращаемый_элемент1> [[AS] псевдоним_элемента1]
[,<возвращаемый_элемент2> [[AS] псевдоним_элемента2] ]…}
FROM { <таблица1> [[AS] псевдоним1] [,<таблица2> [[AS] псевдоним2]]…
| <таблица1> [[AS] псевдоним1] <тип_соединения1> <таблица2> [[AS]
псевдоним2]
[{ON<условие_соединения1> | USING (<список_столбцов>)}]
[<тип_соединения2> <таблица3> [псевдоним3]
[{ON<условие_соединения2> | USING (<список_столбцов>)}]]…}
[WHERE <условие_поиска>]
[GROUP BY <элемент_группировки1> [, <элемент_группировки2>]…]
[HAVING <условие_поиска>]
[PLAN <список_пунктов_плана>]
[ORDER BY <элемент_сортировки1> [, <элемент_сортировки 2>]…]
[ROWS k [TO r ]],
где
<список_столбцов>:: = столбец1 [, столбец2 ...];
1.
<возвращаемый_элемент> :: =
{ [<таблица>.]*
| [<таблица>.]столбец
| NULL
| константа
| переменная
| <выражение>
| (<скалярный_подзапрос> ) };
<таблица>:: =
3
{ базовая_таблица | представление | имя_производной_таблицы
| <производная_таблица>};
<производная_таблица> ::=
(<табличный_подзапрос>) [[AS] псевдоним] [(<список_столбцов>)];
<тип_соединения>::=
{CROSS JOIN
| [NATURAL] [{INNER | {LEFT | RIGHT | FULL} [OUTER]}] JOIN};
<условие_соединения>::=
{<таблица1>.столбец <операция_сравнения> <таблица2>.столбец};
<операция_сравнения> ::= { = | < | > | {<= | !> } | { >= | !< } | { <> | != }};
<условие_поиска> ::= [NOT] <условие_поиска1>
[[AND|OR][NOT] <условие_поиска2>]…,
в котором
<условие_поиска> ::=
{ <значение> <операция_сравнения> {<значение1>
| (<скалярный_подзапрос> )
| {ANY| ALL} (<подзапрос_столбца>)}
| <значение> [NOT] BETWEEN <значение1> AND <значение2>
| <значение> [NOT] LIKE 'шаблон' [ESCAPE 'символ_пропуска']
| <значение> [NOT] CONTAINING <значение1>
| <значение> [NOT] STARTING WITH <значение1>
| <значение> [NOT] IN ({<значение1> [, <значение2> …] | <подзапрос_столбца>})
| <значение> IS [NOT] NULL
| <значение> IS [NOT] DISTINCT FROM <значение1>
| EXISTS (<табличный_подзапрос>)
| SINGULAR (<табличный_подзапрос>)
| <значение> [NOT] SIMILAR TO 'регулярное_выражение' [ESCAPE
'символ_пропуска']};
<значение>::= {[<таблица>.] столбец | константа | <выражение> | функция};
<элемент_сортировки> :: ={ [<таблица>.] столбец
| порядковый_номер_столбца
| псевдоним_столбца
| <выражение>}
[ASC[ENDING] | DESC [ENDING]]
[NULLS FIRST | NULLS LAST]}…;
2.
<элемент_группировки> := { [<таблица>.] столбец
| порядковый_номер_столбца
| псевдоним_столбца
| <выражение>}.
Синтаксис запроса SELECT в Oracle практически совпадает с синтаксисом
Firebird, за исключением того, что не используются конструкция FIRST m
SKIP n, секция PLAN <список_пунктов_плана> и ROWS k TO r [45, 46, 47].
В MS SQL Server полный синтаксис запроса SELECT имеет вид [23, 37]:
4
[WITH
имя_производной_таблицы1 [(<список_столбцов>)]
AS (<табличный_подзапрос> )
[, имя_производной_таблицы2 [(<список_столбцов>)]
AS (<табличный_подзапрос> )...]
SELECT [ ALL | DISTINCT ] [ TOP (<выражение>) [ PERCENT ] [ WITH TIES ] ]
{* | <возвращаемый_элемент1> [[AS] псевдоним_элемента1]
[,<возвращаемый_элемент2> [[AS] псевдоним_элемента2] ]…}
[ INTO <новая таблица> ]
[FROM <исходная таблица> [, <исходная таблица>]... ]
[WHERE <условие_поиска>]
[GROUP BY { <элемент_группировки1>
| { ROLLUP | CUBE | GROUPING SETS } ( <элемент> [, <элемент>]... ) }
[, { <элемент_группировки2>
| { ROLLUP | CUBE | GROUPING SETS } ( <элемент> [, <элемент>]... ) } ]
…]
[HAVING <условие_поиска>]
[ORDER BY <элемент_сортировки1> [,<элемент_сортировки 2>] [<секция
OFFSET>]
[FOR { BROWSE | }]
[OPTION ( <подсказка запроса> [, <подсказка запроса>]... ) ],
где
<возвращаемый_элемент> :: =
{ { <имя таблицы> | <имя представления> | <псевдоним_таблицы> }.*
| {[{ <имя таблицы> | <имя представления> | <псевдоним_таблицы> }. ]
{ <имя столбца> | $IDENTITY | $ROWGUID }
| <выражение> } };
<исходная таблица> ::=
{ <таблица> | <представление> } [ [ AS ] <псевдоним> ]
[ WITH (<подсказка таблицы> [, <подсказка таблицы>]...) ]
| <функция> [ [ AS ] <псевдоним> ]
| <таблица> <соединение> [ <соединение> ]...};
<соединение> ::=
{ <тип соединения> <таблица> ON <условие>
| CROSS JOIN <таблица>
| { CROSS | OUTER } APPLY <таблица>};
<тип соединения> ::=
{ [ INNER ] JOIN
| { LEFT | RIGHT | FULL } [ OUTER ] } [ <подсказка соединения> ] JOIN};
<условие_поиска> ::=
{ <значение> <операция_сравнения> {<значение1>
| (<скалярный_подзапрос> )
5
| {ALL|SOME|ANY} (<подзапрос_столбца>)}
| <значение> [NOT] BETWEEN <значение1> AND <значение2>
| <значение> [NOT] LIKE 'шаблон' [ESCAPE 'символ_пропуска']
| CONTAINS ( { <столбец> | <список столбцов> | * } ) , <условие CONTAINS>
[ , LANGUAGE <язык> ]
| FREETEXT ( { <столбец> | <список столбцов> | * } ), <строка FREETEXT>
[ , LANGUAGE <язык> ]
| <значение> [NOT] IN ({<значение1> [, <значение2> …] | <подзапрос_столбца>})
| <значение> IS [NOT] NULL
| EXISTS (<табличный_подзапрос>)};
<секция OFFSET> ::=
OFFSET <выражение> ROW[S]
[ FETCH { FIRST | NEXT } <выражение> ROW[S] ONLY ].
Конкретные особенности использования приведенных выше конструкций
поясняются далее в процессе изучения запроса SELECT.
3.2. ЗАПРОСЫ К ОДНОЙ ТАБЛИЦЕ
Применительно к однотабличным запросам SELECT в СУБД Firebird
имеет формат:
SELECT [FIRST m] [SKIP n]
[{DISTINCT | ALL}]
{* | <возвращаемый_элемент1> [[AS] псевдоним_элемента1]
[,<возвращаемый_элемент2>[[AS] псевдоним_элемента2] ]…}
FROM {базовая_таблица | представление} [[AS] псевдоним]
[WHERE <условие_поиска>]
[GROUP BY <элемент_группировки1> [, <элемент_группировки2>]…]
[HAVING <условие_поиска>]
[PLAN <список_пунктов_плана>]
[ORDER BY <элемент_сортировки1> [, <элемент_сортировки 2>]…]
[ROWS k [TO r ]].
Как уже было отмечено, в Oracle отличием является отсутствие
конструкции
FIRST
m
SKIP
n,
а
также
секций
PLAN
<список_пунктов_плана> и ROWS k TO r.
В MS SQL Server применительно к однотабличным запросам SELECT
имеет формат:
SELECT [ ALL | DISTINCT ] [ TOP (<выражение>) [ PERCENT ] [ WITH TIES ] ]
{* | <возвращаемый_элемент1> [[AS] псевдоним_элемента1]
[,<возвращаемый_элемент2> [[AS] псевдоним_элемента2] ]…}
[INTO <новая таблица>]
[FROM {базовая_таблица | представление} [[AS] псевдоним]
[WITH (<подсказка таблицы>)]
| <функция> [[AS] псевдоним]}]
[WHERE <условие_поиска>]
[GROUP BY { <элемент_группировки1>
| { ROLLUP | CUBE | GROUPING SETS } ( <элемент> [, <элемент>]... ) }
6
[, { <элемент_группировки2>
| { ROLLUP | CUBE | GROUPING SETS } ( <элемент> [, <элемент>]... ) } ]
…]
[HAVING <условие_поиска>]
[ORDER BY <элемент_сортировки1> [,<элемент_сортировки 2>] [<секция
OFFSET>]
[FOR { BROWSE | XML }]
[OPTION ( <подсказка запроса> [, <подсказка запроса>]... ) ].
Порядок следования секций и конструкций в запросе SELECT не может
быть изменен.
Логический порядок обработки основных элементов запроса SELECT
определяется такой последовательностью.
1. FROM – определяются имена используемых объектов.
2. WHERE – выполняется фильтрация строк объекта в соответствии с
заданными условиями.
3. GROUP BY – образуются группы строк, имеющих одно и то же
значение в указанном элементе (столбце).
4. HAVING – фильтруются группы строк объекта в соответствии с
указанным условием.
5. SELECT – устанавливается, какие элементы должны присутствовать
в выходных данных.
6. ORDER BY – определяется упорядоченность результатов выполнения
запроса.
Следует отметить, что фактическое физическое выполнение запроса
определяется обработчиком запросов и порядок из приведенного списка
может значительно отличаться.
В большинстве СУБД в SQL-запросе две секции – SELECT и FROM
являются обязательными, все остальные могут быть опущены. При этом
некоторые СУБД, например MS SQL Server, допускают наличие только
одной секции SELECT в определенных запросах.
Ниже перечислены функции каждой из секций.
В секции SELECT указывается список столбцов НД, которые должны
быть возвращены запросом SELECT. Возвращаемые элементы могут
содержать значения, считываемые из столбцов таблицы БД, или значения,
вычисляемые во время выполнения запроса.
Конструкция FIRST…SKIP служит для ограничения возвращаемых
запросом строк. Из рассматриваемых в учебнике СУБД данная конструкция
используется только в Firebird.
В Oracle ограничение на количество возвращаемых строк накладывается с
помощью использования псевдостолбца ROWNUM в секции WHERE.
В MS SQL Server ограничение на количество возвращаемых строк
реализуется конструкцией TOP, которая задает количество выводимых строк
целым значением либо долей в процентах от общего числа строк (если
указана опция PERCENT). Опция WITH TIES используется только в запросах
7
с секцией ORDER BY и указывает, что из базового результирующего набора,
упорядоченного с использованием секции ORDER BY, возвращаются только
первые ТОР строк.
Конструкция DISTINCT | ALL определяет, что делать с повторяющимися
строками результата. При использовании ALL возвращаются все строки,
удовлетворяющие условиям запроса (режим используется по умолчанию).
При использовании DISTINCT возвращаются только неповторяющиеся
строки. При этом вычисление отличий применяется ко всем возвращаемым
элементам. Несмотря на то, что признаки NULL никогда не бывают равны
друг другу (поскольку считаются неизвестными), DISTINCT, напротив,
считает их дубликатами. Поэтому запрос SELECT DISTINCT … вернет
только одно NULL, независимо от того, сколько признаков NULL встретится
при анализе.
В MS SQL Server после секции SELECT может быть указано INTO
<новая таблица> для сохранения результата запроса в новой таблице БД.
В секции FROM указывается список объектов БД, которые содержат
данные, считываемые запросом.
В MS SQL Server указание таблицы-источника данных может быть
дополнено необязательной конструкцией WITH (<подсказка таблицы>). Опция
WITH позволяет определить используемые в выборке данных подсказки.
Подсказки включают варианты оптимизации запроса и виды применяемых
блокировок, используются оптимизатором запросов. Следует учесть, что
оптимизатор запросов SQL Server обычно автоматически выбирает наилучший
план выполнения запроса. Поэтому подсказки рекомендуется использовать
только опытным пользователям и администраторам базы данных в случае
крайней необходимости.
Секция WHERE показывает, что в результаты запроса нужно включать
только некоторые строки. Для отбора строк, включаемых в результаты
запроса, используется условие поиска.
Секция GROUP BY позволяет создать итоговый запрос, который вначале
группирует строки таблицы по определенному признаку, а затем включает в
результаты запроса одну итоговую строку для каждой группы.
В MS SQL Server реализованы расширенные возможности группировки.
Функции CUBE и ROLLUP заставляют SQL Server создавать
дополнительные высокоуровневые агрегаты суммарных категорий и часто
используются при создании отчетов, содержащих подытоги и итоги.
ROLLUP создает промежуточные итоговые значения для категорий, a CUBE
создает сводные итоги для категорий.
Секция HAVING показывает, что в НД следует включать только
некоторые из групп, созданных с помощью GROUP BY. В этой секции, как и
в секции WHERE, для отбора включаемых групп используется условие
поиска.
8
Секция PLAN служит для определения пользователем собственных
способов выполнения запросов [29]. Обычно составлением плана запроса
занимается оптимизатор. Оптимизатор анализирует возможные пути
выполнения запроса, определяет «стоимость» выполнения каждого варианта
и выбирает наилучший (более быстрый) вариант. В основном пользователь
не использует пункт PLAN, и СУБД сама определяет план по умолчанию. Из
рассматриваемых в учебнике СУБД секция PLAN доступна только в СУБД
Firebird. В MS SQL Server аналогом секции PLAN фактически служат
подсказки, используемые в различных частях запроса SELECT.
Секция ORDER BY сортирует результаты запроса на основании данных,
содержащихся в одном или нескольких столбцах НД. Если эта секция не
указана, результаты запроса не будут отсортированы.
Конструкции ROWS…TO, как и FIRST…SKIP, служит для ограничения
возвращаемых запросом строк, но имеет более широкое применение: может
использоваться при объединении результатов нескольких запросов, в любых
видах подзапроса (UPDATE и DELETE). Из рассматриваемых в учебнике
СУБД конструкция ROWS…TO используется только в Firebird.
В MS SQL Server возможности секции ORDER BY расширяются с
помощью конструкции OFFSET (смещение). Использование данной
конструкции позволяет пропустить указанное количество строк перед тем,
как выводить результаты запроса.
Секция FOR может использоваться в запросе MS SQL Server. Она
позволяет задать допустимость обновления данных во время их просмотра, а
также указывает, что результат выборки должен возвращаться в виде XMLдокумента.
Секция OPTION в запросе MS SQL Server может использоваться для
задания подсказок запроса.
В рамках настоящего учебника секции FOR и OPTION подробно не
рассматриваются.
Рассмотрим подробнее описанные основные конструкции SQL-запроса.
3.2.1. Секции SELECT и FROM
В секции SELECT, с которой начинается запрос SELECT, необходимо
указать в нужном порядке элементы данных, которые будут возвращены в
результате запроса. Эти элементы составляют столбцы НД и задаются в виде
списка возвращаемых элементов, разделенных запятыми.
Синтаксис возвращаемых элементов применительно к однотабличным
запросам имеет вид:
<возвращаемый_элемент> :: = {[таблица.]* | [таблица.]столбец | NULL | константа
| переменная | <выражение> |
<скалярный_подзапрос>}.
Из приведенного синтаксиса следует, что возвращаемый элемент может
представлять собой:
звездочку (*), означающую вывод всех столбцов указанной таблицы;
9
имя столбца, идентифицирующее один из столбцов, содержащихся в
таблице, указанной в секции FROM. Когда в качестве возвращаемого
элемента указывается имя столбца таблицы БД, происходит выбор
значения этого столбца для каждой из строк таблицы и помещение его
в соответствующую строку НД. Следует отметить, что в MS SQL Server в
качестве столбца может быть указан идентификатор $IDENTITY или
$ROWGUID. Если задано $IDENTITY, то в список выбора помещается
столбец таблицы со свойством IDENTITY, если в качестве столбца
указано $ROWGUID, в список выбора включается столбец, заданный со
свойством ROWGUIDCOL (определение столбцов с указанными
свойствами в MS SQL Server будет рассмотрено далее в п. 4.2.2). В СУБД
Oracle в качестве столбца может быть указан псевдостолбец, например
ROWID или ROWNUM;
признак NULL;
константу, показывающую, что в каждой строке НД должно содержаться
одно и то же значение;
выражение, показывающее, что необходимо вычислить значение,
помещаемое в результат запроса, по формуле, определенной в выражении.
Выражения, как уже отмечалось, представляют собой комбинацию
идентификаторов, функций, операций, констант. Здесь же могут
использоваться CASE-выражения;
простой подзапрос (его использование в качестве возвращаемого элемента
будет рассмотрено при изучении вложенных запросов).
Столбцы в таблице результатов располагаются в том порядке, в котором
они указаны в списке возвращаемых элементов, и согласно реляционной
модели должны иметь имена.
При использовании символа звездочки (*) в качестве списка возвращаемых
элементов из исходного объекта будут прочитаны все столбцы. В случае,
если выборка производится из нескольких таблиц (многотабличные запросы
будут рассмотрены в разд. 3.3), то перед символом * может указываться имя
таблицы. Использование * считается плохим решением. Вследствие выборки
большего объема данных, чем требуется, снижается производительность изза увеличения нагрузки на сеть, а также из-за ухудшения эффекта от
использования индексов. Если не используется символ *, то для каждого из
возвращаемых элементов из списка в НД будет создан один столбец.
Поэтому рекомендуется явно перечислять требуемые возвращаемые
элементы.
Пусть активной является учебная БД. Например, чтобы получить значения
всех столбцов из таблицы Abonent, необходимо выполнить запрос
SELECT * FROM Abonent;
Результат выполнения запроса представлен на рис. 3.1.
10
ACCOUNTC
D
005488
STREETC
D
3
HOUSEN
O
4
FLATN
O
1
FIO
PHON
E
556893
Аксенов
С.А.
115705
3
1
82
Мищенко
769975
Е.В.
015527
3
1
65
Конюхов
761699
В.С.
443690
7
5
1
Тулупова
214833
М.И.
136159
7
39
1
Свирина
NULL
З.А.
443069
4
51
55
Стародубце 683014
в Е.В.
136160
4
9
15
Шмаков
NULL
С.В.
126112
4
7
11
Маркова
683301
В.П.
136169
4
7
13
Денисова
680305
Е.К.
080613
8
35
11
Лукашина
254417
Р.М.
080047
8
39
36
Шубина
257842
Т. П.
080270
6
35
6
Тимошкина 321002
Н.Г.
Рис. 3.1. Результат выполнения запроса на выборку всех данных
На логическом уровне запрос выполняется путем построчного просмотра
таблицы, указанной в секции FROM. Для каждой строки таблицы берутся
значения столбцов, входящих в список возвращаемых элементов, и создается
одна строка НД. Таблица результатов простого запроса на чтение, подобного
приведенному выше, содержит одну строку данных для каждой строки
исходной таблицы БД. Порядок следования возвращаемых элементов в НД
определяется порядком их перечисления в запросе SELECT.
Рассмотрим пример запроса, когда в качестве возвращаемых элементов
перечислены в определенном порядке имена столбцов базовой таблицы.
Пусть активной является учебная БД. Чтобы вывести ФИО, номера
лицевых счетов и номера телефонов всех абонентов, необходимо выполнить
следующий запрос к таблице Abonent:
SELECT Fio, AccountCD, Phone FROM Abonent;
Здесь в качестве возвращаемых элементов используются имена столбцов
Fio, AccountCD и Phone базовой таблицы Abonent (рис. 3.2).
11
FIO
ACCOUNTCD PHONE
Аксенов С.А.
005488
556893
Мищенко Е.В.
115705
769975
Конюхов В.С.
015527
761699
Тулупова М.И.
443690
214833
Свирина З.А.
136159
NULL
Стародубцев Е.В.
443069
683014
Шмаков С.В.
136160
NULL
Маркова В.П.
126112
683301
Денисова Е.К.
136169
680305
Лукашина Р.М.
080613
254417
Шубина Т. П.
080047
257842
Тимошкина Н.Г.
080270
321002
Рис. 3.2. Результат выполнения запроса к таблице Abonent
В результаты запроса (рис. 3.3) можно включать константы, например,
в таком виде:
SELECT 'Абонент', Fio, 'Номер телефона', Phone FROM Abonent;
CONSTANT
FIO
CONSTANT 2 PHONE
Абонент
Аксенов С.А.
Номер телефона 556893
Абонент
Мищенко Е.В.
Номер телефона 769975
Абонент
Конюхов В.С.
Номер телефона 761699
Абонент
Тулупова М.И.
Номер телефона 214833
Абонент
Свирина З.А.
Номер телефона NULL
Абонент
Стародубцев Е.В. Номер телефона 683014
Абонент
Шмаков С.В.
Номер телефона NULL
Абонент
Маркова В.П.
Номер телефона 683301
Абонент
Денисова Е.К.
Номер телефона 680305
Абонент
Лукашина Р.М.
Номер телефона 254417
Абонент
Шубина Т. П.
Номер телефона 257842
Абонент
Тимошкина Н.Г.
Номер телефона 321002
Рис. 3.3. Результат выполнения запроса с константными выражениями
Как следует из результата предыдущего запроса, СУБД Firebird определяет
по умолчанию системные имена для столбцов НД, содержащих константы –
CONSTANT и CONSTANT2.
В СУБД Oracle для столбцов, содержащих константы, в качестве имен по
умолчанию используются сами константы. При выполнении вышеуказанного
запроса в Oracle столбец CONSTANT будет иметь имя 'АБОНЕНТ', а столбец
CONSTANT2 будет иметь имя 'НОМЕРТЕЛЕФОНА'.
В MS SQL Server при выполнении запроса имена у столбцов, содержащих
константы, будут отсутствовать.
Кроме столбцов, значения которых считываются непосредственно из БД,
SQL-запрос на чтение может содержать вычисляемые (производные)
12
столбцы, значения которых определяются на основании значений столбцов
только той таблицы или запроса, которые указаны в списке секции FROM
соответсвующего запроса. Чтобы получить вычисляемый столбец, в списке
возвращаемых элементов необходимо указать выражение. Выражения могут
включать в себя операции сложения, вычитания, умножения, деления и
операцию конкатенации (склеивания) строк. Операция конкатенации в
различных СУБД может обозначаться по-разному: в Firebird и Oracle
конкатенация обозначается как две вертикальные линии || , а в MS SQL Server
– как знак плюс +. В выражениях можно также использовать функции и
скобки:
<выражение> ::= { [ [+] | – ] { столбец | константа | функция} [ + | – | * | / ] [ || | + ]}…
Например, если требуется вывести в столбце AccountCDRyazan значение
лицевого счета абонента, а в столбце с именем ФИО+телефон – ФИО и номер
телефона абонента с добавлением в начало символов 8–4912, то в Firebird и
Oracle можно построить запрос
SELECT AccountCD AS "AccountCDRyazan",
(Fio || ' имеет телефон ' || '8-4912-'|| Phone) "ФИО+телефон"
FROM Abonent;
Результат выполнения запроса в Firebird представлен на рис. 3.4.
Результат выполнения этого запроса в Oracle будет немного отличаться
(рис. 3.5). Из результата видно, что если какой-либо элемент, участвующий в
соединении строк, не имеет значения, то результат конкатенации все равно
существует и состоит из элементов, значения которых определены.
В MS SQL Server вышеуказанный запрос будет выглядеть:
SELECT AccountCD AS "AccountCDRyazan",
(Fio + ' имеет телефон ' + '8-4912-'+ Phone) "ФИО+телефон"
FROM Abonent;
и иметь результат, аналогичный результату на рис. 3.4.
AccountCDRyazan
005488
115705
015527
443690
136159
443069
136160
126112
136169
080613
080047
080270
ФИО+телефон
Аксенов С.А. имеет телефон 8-4912-556893
Мищенко Е.В. имеет телефон 8-4912-769975
Конюхов В.С. имеет телефон 8-4912-761699
Тулупова М.И. имеет телефон 8-4912-214833
NULL
Стародубцев Е.В. имеет телефон 8-4912-683014
NULL
Маркова В.П. имеет телефон 8-4912-683301
Денисова Е.К. имеет телефон 8-4912-680305
Лукашина Р.М. имеет телефон 8-4912-254417
Шубина Т. П. имеет телефон 8-4912-257842
Тимошкина Н.Г. имеет телефон 8-4912-321002
Рис. 3.4. Результат выполнения запроса с вычисляемыми столбцами
13
AccountCDRyazan
ФИО+телефон
005488
Аксенов С.А. имеет телефон 8-4912-556893
115705
Мищенко Е.В. имеет телефон 8-4912-769975
015527
Конюхов В.С. имеет телефон 8-4912-761699
443690
Тулупова М.И. имеет телефон 8-4912-214833
136159
Свирина З.А. имеет телефон 8-4912443069
Стародубцев Е.В. имеет телефон 8-4912-683014
136160
Шмаков С.В. имеет телефон 8-4912126112
Маркова В.П. имеет телефон 8-4912-683301
136169
Денисова Е.К. имеет телефон 8-4912-680305
080613
Лукашина Р.М. имеет телефон 8-4912-254417
080047
Шубина Т. П. имеет телефон 8-4912-257842
080270
Тимошкина Н.Г. имеет телефон 8-4912-321002
Рис. 3.5. Результат выполнения запроса с вычисляемыми столбцами в
Oracle
В этом примере использованы псевдонимы столбцов, которые задаются
с помощью необязательного ключевого слова AS (как), указываемого после
возвращаемого элемента, и определяют имя, под которым столбец будет
представлен в НД. Так, с помощью псевдонима можно поменять выводимое
имя столбца. Если псевдоним столбца содержит пробелы или символы,
отличные от прописных букв латиницы, то такой псевдоним нужно
заключать в кавычки. Число символов в псевдониме, как и в имени любого
объекта БД, не должно превышать разрешенное число символов (31 либо 30).
Псевдонимы столбцов целесообразно использовать в случае, если
необходимо, чтобы возвращаемый элемент имел имя, отличное от имени
исходного столбца, или когда требуется изменить системное имя по
умолчанию. Особенно удобно использовать псевдонимы для вычисляемых
столбцов, для которых изначально имя не предусмотрено. При этом имена
возвращаемых элементов должны быть различными. Если попытаться
сделать их одинаковыми, например так:
SELECT IncomingDate AS Dat, ExecutionDate AS Dat FROM Request;
или даже так:
SELECT IncomingDate AS "Dat", ExecutionDate AS "Dat" FROM Request;,
то СУБД все равно автоматически переименует такие столбцы.
Следует отметить, что указание в запросе псевдонимов для возвращаемых
элементов, представляющих собой выражения, в Firebird и MS SQL Server не
является обязательным, в то время как в Oracle, например, обязательно.
Объекты и выражения целочисленного типа могут применяться в любых
математических операциях. Примером запроса, возвращающего значения
арифметических выражений, может быть
SELECT AccountCD, Paysum, 15 * Paysum + 20, 15 * (Paysum + 20)
FROM Paysumma;
В СУБД Oracle математические операторы могут применяться и к
столбцам с типами данных DATE или INTERVAL. Например, нужно узнать,
сколько времени прошло между моментом подачи заявки на ремонт и
14
моментом устранения неисправности. Это можно сделать следующим
образом:
SELECT RequestCD, ExecutionDate-IncomingDate AS "Дней",
(ExecutionDate-IncomingDate)/7 AS "Недель"
FROM Request;
Результат выполнения запроса представлен на рис. 3.6.
REQUESTCD Дней
Недель
1
3,0
0,429
2
5,0
0,714
3
9,0
1,286
5
NULL
NULL
6
8,0
1,143
7
4,0
0,571
9
2,0
0,286
…
…
…
Рис. 3.6. Результат выполнения запроса на определение времени
устранения неисправности
СУБД Oracle позволяет использовать в запросах SELECT псевдостолбцы.
Псевдостолбцами в Oracle принято называть столбцы, которые отсутствуют в
таблицах в явном виде, но могут быть использованы в запросах.
Псевдостолбцы подобны системным переменным, но в отличие от них
способны давать в запросах на разных строках разные значения, которые
вычисляются по мере выполнения определенных фаз обработки запроса и
доступны для использования на последующих фазах обработки, образуя как
бы дополнительный "столбец".
Наиболее часто используемые псевдостолбцы – ROWID, который
содержит физический адрес строки или хранимого объекта, и ROWNUM,
который содержит порядковый номер строки запроса.
Например, выбрать все строки из таблицы Abonent, пронумеровав их по
порядку, можно в Oracle с помощью запроса
SELECT ROWNUM, A.* FROM Abonent A;
Однако чаще всего ROWNUM в Oracle применяется не для нумерации, а
для ограничения количества обрабатываемых строк.
Практически в любой СУБД существует возможность управлять
количеством строк, возвращаемых запросом. Рассмотрим, какие средства
существуют для этого в Firebird и MS SQL Server. Данная возможность
применительно к Oracle будет рассмотрена в следующем п. 3.2.2 при
изучении секции WHERE.
В Firebird ограничение на количество возвращаемых строк реализуется в
секции SELECT с использованием конструкции
[FIRST m] [SKIP n] ,
15
где m и n – целочисленные выражения. Здесь после зарезервированного
слова FIRST указывается, что только m строк из возвращаемого набора
данных нужно вывести, а оставшиеся – отбросить. Зарезервированное слово
SKIP определяет параметр n – количество первых строк, которое нужно
пропустить с начала набора данных, сформированного запросом.
Пусть требуется вывести 4 строки из справочника абонентов, начиная со
второй. Для этого можно использовать запрос
SELECT FIRST 4 SKIP 1 * FROM Abonent;
Результат выполнения запроса представлен на рис. 3.7.
3.
ACCOUNTCD STREETC HOUSENO FLATNO
FIO
PHONE
D
115705
3
1
82
Мищенко 769975
Е.В.
015527
3
1
65
Конюхов 761699
В.С.
443690
7
5
1
Тулупова 214833
М.И.
136159
7
39
1
Свирина NULL
З.А.
Рис. 3.7. Результат выполнения запроса на вывод определенных строк
В MS SQL Server ограничение на количество возвращаемых строк
реализуется с использованием опции
[ TOP (<выражение>) [ PERCENT ] [ WITH TIES ],
где <выражение> ограничивает количество выводимых строк заданным
целым значением, если опция PERCENT не задана, либо задает в процентах
долю выводимых строк от общего числа строк результата, если опция
PERCENT задана. Параметр WITH TIES требует включить в результат все
повторения (если они есть) для последней строки, выведенной по
ограничению TOP <выражение> .
Однако с помощью конструкции TOP нельзя ограничить количество
первых строк, которые необходимо пропустить в начале набора даных.
Поэтому в MS SQL Server существует аналог – секция
OFFSET <выражение> ROW[S]
[ FETCH { FIRST | NEXT } <выражение> ROW[S] ONLY ].
Секция OFFSET <выражение> используется в конце запроса SELECT
после секции сортировки ORDER BY (сортировка подробно будет
рассмотрена далее в п. 3.2.6). OFFSET позволяет указать, какое число
начальных строк не будет помещено в результирующий набор данных.
Конструкция FETCH указывает количество возвращаемых строк. Ключевые
слова FIRST и NEXT являются синонимами и используются лишь для
совместимости со стандартом. В этих секциях выражением является
целочисленный
литерал
или
любое
выражение,
возвращающее
16
целочисленное значение. Одновременное использование конструкций TOP и
OFFSET недопустимо.
Предыдущий приведенный запрос в MS SQL Server можно записать так:
SELECT * FROM Abonent
ORDER BY AccountCD OFFSET 1 ROWS FETCH NEXT 4 ROWS ONLY;
Следует отметить, что конструкция SELECT FIRST 0… возвращает
пустой результат. Так же, как и конструкция SELECT TOP 0… в MS SQL
Server.
В Firebird аналогом конструкции FIRST…SKIP является конструкция
ROWS…TO, которая используется для ограничения количества строк,
возвращаемых запросом, и имеет формат
[ROWS k [TO r]].
Целочисленные значения k и r показывают, что строки, начиная с k-й
и заканчивая r-й, будут видны в НД.
Конструкция ROWS…TO была введена в более позднем SQL-стандарте и
поэтому обладает рядом преимуществ по сравнению с конструкцией
FIRST…SKIP [26]. Конструкция ROWS…TO может использоваться при
объединении результатов нескольких запросов, в любых видах подзапроса,
а также в запросах UPDATE и DELETE (будут рассмотрены далее).
Следующий запрос выведет из таблицы Street содержимое строк с третьей
по шестую (рис. 3.8):
SELECT * FROM Street ROWS 3 TO 6;
STREETCD
STREETNM
6
МОСКОВСКАЯ УЛИЦА
8
МОСКОВСКОЕ ШОССЕ
4
ТАТАРСКАЯ УЛИЦА
5
ГАГАРИНА УЛИЦА
Рис. 3.8. Результат выполнения запроса на вывод строк c 3 по 6
Конструкция ROWS…TO всегда может быть заменена эквивалентной
конструкцией FIRST…SKIP. Когда второе значение в конструкции ROWS…
TO отсутствует, тогда конструкции ROWS r эквивалентна конструкция
FIRST r. Когда и первое, и второе значения используются, тогда ROWS k TO
r эквивалентна конструкция FIRST (r – k + 1) SKIP (k – 1).
Если вывести 4 строки из справочника абонентов (начиная со второй),
используя следующий запрос на основе конструкции ROWS…TO:
SELECT * FROM Abonent ROWS 2 TO 5;,
то получится результат, совпадающий с результатом, приведенным на рис. 3.7.
Следует помнить, что хотя разрешено использование и FIRST…SKIP,
и ROWS…TO, при попытке совместного их использования в одной команде
будет выдано сообщение о синтаксической ошибке.
Повторяющиеся строки из НД можно удалить, если в запросе SELECT
перед списком возвращаемых элементов указать ключевое слово DISTINCT
(различный). Например, чтобы выбрать из таблицы Abonent различные
значения кодов улиц, необходимо использовать запрос
17
SELECT DISTINCT StreetCD FROM Abonent;
Этот запрос выполняется следующим образом. Вначале генерируются все
строки результатов (двенадцать строк – по числу строк в таблице Abonent),
а затем удаляются те из них, коды улиц в которых в точности повторяют другие.
4.
Ключевое
слово
STREETCD
DISTINCT
можно
3
указывать независимо от
4
содержимого
списка
6
возвращаемых элементов
7
запроса SELECT. Если
8
ключевое слово DISTINCT
Рис. 3.9. Результат
не
указано,
то
запроса
повторяющиеся строки не
на исключение
удаляются.
Результат
выполнения
запроса повторяющихся строк
представлен на рис. 3.9.
Использование DISTINCT – это полезный способ избежать избыточности
данных, но важно при этом понимать принцип его работы. Не следует
безоглядно использовать DISTINCT, потому что это может скрыть какую-то
проблему или какие-то важные данные. Например, можно ошибочно
предположить, что ФИО всех абонентов различны, использовать запрос
SELECT DISTINCT FIO FROM Abonent;
и попытаться на основании его результатов сделать вывод об общем
количестве абонентов. Если в таблице есть несколько абонентов с
одинаковым ФИО, вывод будет неправильным.
Таким образом, нежелательно использовать DISTINCT, если изначально
не ожидается избыточности данных, полезным он будет только в случаях,
когда избыточность ожидаема и должна быть устранена.
В общем случае секция FROM состоит из ключевого слова FROM, за
которым следует список спецификаторов объектов БД, разделенных запятыми.
Каждый спецификатор идентифицирует объект БД (базовая таблица,
представление), содержащий данные, которые считывает запрос. Такие объекты
называются исходными объектами запроса (и запроса SELECT), поскольку все
данные, содержащиеся в НД, берутся из них. В случае однотабличных запросов
в секции FROM указывается только один исходный объект.
Имя таблицы можно переопределять так, чтобы для ссылок на нее
использовать короткий (чаще всего ограничивающийся одной буквой)
псевдоним (alias):
SELECT A.Fio, A.AccountCD, A.Phone FROM Abonent AS A;
Результат выполнения этого запроса совпадает с результатом,
представленным на рис. 3.2.
Следует учесть, что при объявлении псевдонима нельзя использовать имя
соответствующей таблицы в списке возвращаемых столбцов запроса
SELECT. Так, следующий запрос будет выдавать сообщение об ошибке:
18
SELECT Abonent.AccountCD, Abonent.Fio, Abonent.Phone FROM Abonent A;
В секции FROM запросов, которые возвращают одно вычисляемое
значение или контекстную переменную, часто используется системная
таблица, которая всегда содержит только одну строку. Для Firebird,
например, это таблица RDB$DATABASE (см. приложение Б) со служебной
информацией о БД [29], для Oracle системная таблица DUAL. Например
запрос, возвращающий текущие дату и время, может быть построен на
основе системной таблицы в Firebird следующим образом:
SELECT CURRENT_TIMESTAMP FROM RDB$DATABASE;,
а в Oracle так:
SELECT SYSDATE FROM DUAL;
В MS SQL Server запрос, возвращающий текущие дату и время, может
быть построен вообще без какой-либо таблицы:
SELECT CURRENT_TIMESTAMP;
Также можно получить текущие дату и время с использованием одной из
таблиц учебной БД. Например, в Firebird:
SELECT DISTINCT CURRENT_TIMESTAMP FROM Abonent;,
SELECT CURRENT_TIMESTAMP FROM Request ROWS 1;
SELECT FIRST 1 CURRENT_TIMESTAMP FROM Street;
или в MS SQL Server:
SELECT TOP 1 CURRENT_TIMESTAMP FROM Request;
Примечание. В некоторых СУБД, например в MS SQL Server,
поддерживается запрос SELECT, содержащий только секцию
SELECT без секции FROM, например
SELECT 25 AS St_1, 'RSREU' AS СSt_2;
3.2.2. Секция WHERE
Секция WHERE используется для наложения условий на данные,
выбираемые запросом SELECT. Секция состоит из ключевого слова WHERE,
за которым следует условие поиска, определяющее, какие именно строки
требуется вывести. Секция WHERE содержит набор условий для отбора
строк:
WHERE [NOT] <условие_поиска1> [[AND|OR][NOT] <условие_поиска2>]….
В Firebird условие поиска применительно к однотабличным запросам
определяется следующим образом [29]:
<условие_поиска> ::=
{ <значение> <операция_сравнения> <значение1>
| <значение> IS [NOT] {TRUE | FALSE | UNKNOWN}
| <значение> [NOT] BETWEEN <значение1> AND <значение2>
| <значение> [NOT] LIKE 'шаблон' [ESCAPE 'символ_пропуска']
| <значение> [NOT] IN ( <значение1> [ , <значение2> …] )
| <значение> IS [NOT] NULL
| <значение> [NOT] CONTAINING <значение1>
| <значение> [NOT] STARTING WITH <значение1>
19
| <значение> IS [NOT] DISTINCT FROM <значение1>
| <значение> [NOT] SIMILAR TO 'регулярное_выражение' [ESCAPE
'символ_пропуска'] },
где <значение> ::= {столбец | константа | <выражение> | функция}.
В Oracle условие поиска выглядит так:
<условие_поиска> ::=
{ <значение> <операция_сравнения> <значение1>
| <значение> IS [NOT] NAN
| <значение> IS [NOT] INFINITE
| <значение> [NOT] BETWEEN <значение1> AND <значение2>
| <значение> [NOT] LIKE 'шаблон' [ESCAPE 'символ_пропуска']
| <значение> [NOT] IN ( <значение1> [ , <значение2> …] )
| <значение> IS [NOT] NULL
|[NOT] REGEXP_LIKE (<значение> , 'регулярное_выражение') }.
В MS SQL Server условие поиска применительно к однотабличным
запросам определено в следующем виде:
<условие_поиска> ::=
{ <значение> <операция_сравнения> <значение1>
| <значение> [NOT] BETWEEN <значение1> AND <значение2>
| <значение> [NOT] LIKE 'шаблон' [ESCAPE 'символ_пропуска']
| <значение> [NOT] IN ( <значение1> [ , <значение2> …] )
| <значение> IS [NOT] NULL
| CONTAINS ( { <столбец> | <список столбцов> | * } )
, <условие CONTAINS> [ , LANGUAGE <язык> ]
| FREETEXT ( { <столбец> | <список столбцов> | * } )
, <строка FREETEXT> [ , LANGUAGE <язык> ] }.
Как можно заметить, синтаксис условия поиска в различных СУБД имеет
как схожую часть, так и отличия. Далее рассмотрим подробно сначала общие
условия отбора данных, характерные для всех описываемых СУБД, а затем
специфические возможности отдельных СУБД.
Примечание. В условии поиска нельзя использовать псевдонимы
возвращаемых элементов.
3.2.2.1. Простое сравнение
Наиболее распространенным условием поиска в языке SQL является
сравнение, которое реализуется конструкцией:
<значение> <операция_сравнения> <значение1>.
При простом сравнении происходит вычисление и сравнение двух
значений для каждой строки данных. Значения могут быть простыми,
например содержать одно имя столбца или константу, и сложными –
арифметическими выражениями. Например, простое сравнение используется
в запросе, выводящем все ремонтные заявки, выполненные в 2013 году и
позже:
SELECT * FROM Request WHERE Executiondate >= '01.01.2013';
20
В результате выполнения запроса будет выведено 3 заявки с кодами 11, 14
и 18.
При определении условий поиска необходимо помнить об обработке
NULL. В трехзначной логике, принятой в SQL, условие поиска может иметь
значение TRUE, FALSE или UNKNOWN. А в результаты запроса попадают
только те строки, для которых условие поиска имеет значение TRUE.
При сравнении значений действуют следующие правила:
1) если сравнение истинно, то результат проверки имеет значение TRUE;
2) если сравнение ложно, то результат проверки имеет значение FALSE;
3) если хотя бы одно из двух сравниваемых значений установлено в
NULL, то результатом проверки будет UNKNOWN;
4) применение операции NOT к NULL возвращает в качестве результата
проверки UNKNOWN.
В СУБД Oracle в качестве значения в операции сравнения может быть
указан псевдостолбец. Так, например, с использованием псевдостолбца
ROWNUM реализуется ограничение на количество строк, возвращаемых
запросом. Чтобы отобрать в Oracle первые 5 строк из таблицы Abonent,
необходимо выполнить запрос:
SELECT * FROM Abonent WHERE ROWNUM <= 5;
При использовании ROWNUM следует обратить внимание на очень
важный момент: в ходе выполнения запроса сначала производятся отбор и
нумерация строк, а затем – сортировка. Рассмотрим, что происходит при
использовании ROWNUM <= 5 для возвращения первых пяти строк.
1. Oracle выполняет запрос.
2. Oracle извлекает первую строку и называет ее строкой номер 1.
3. Номер строки больше 5? Если нет, Oracle возвращает строку, потому
что она отвечает критерию: ее порядковый номер меньше или равен 5. Если
да, Oracle не возвращает строку.
4. Oracle извлекает следующую строку и присваивает ей следующий
порядковый номер по возрастанию (2, затем 3, затем 4 и т.д.).
5. Переход к шагу 3.
Как видно из данного процесса, присвоение значений, возвращаемых
функцией ROWNUM, происходит после извлечения очередной строки. Это
очень важно и является ключевым моментом. Многие разработчики на Oracle
пытаются реализовать извлечение только, скажем, пятой возвращенной
запросом строки, задавая ROWNUM = 5. Такое использование условия
равенства в сочетании с ROWNUM является неверным. При попытке
возвратить пятую строку с помощью ROWNUM = 5 происходит следующее.
1. Oracle выполняет запрос.
2. Oracle извлекает первую строку и называет ее строкой номер 1.
3. Номер строки равен 5? Если нет, Oracle отбрасывает строку, потому что
она не отвечает заданному критерию. Если да, Oracle возвращает строку. Но
ответ всегда будет отрицательным!
21
4. Oracle извлекает следующую строку и называет ее строкой номер 1,
поскольку первая возвращенная запросом строка должна быть
пронумерована как первая строка.
5. Переход к шагу 3.
После тщательного разбора этого процесса становится понятно, почему
использование ROWNUM = 5 не обеспечивает возвращения пятой строки.
Невозможно получить пятую строку, не возвратив перед этим строки с
первой по четвертую!
Однако с помощью ROWNUM = 1 можно получить первую строку.
Причина, почему ROWNUM = 1 обеспечивает возвращение первой строки, в
том, что Oracle для определения наличия строк в таблице приходится
извлекать, по крайней мере, одну из них. Если внимательно
проанализировать предыдущий процесс, подставив 1 вместо 5, то можно
понять, почему для возвращения одной строки можно в качестве условия
задавать ROWNUM = 1.
Получить не первую, а другую по порядку строку (строки) в Oracle можно
только с помощью использования ROWNUM и подзапроса (см. п. 3.3.2).
3.2.2.2. Сравнение значений с плавающей запятой в Oracle
СУБД Oracle поддерживает два специальных условия для сравнения
значений с плавающей запятой: проверка на числовое значение и проверка на
равенство бесконечности.
Проверка значения на число выполняется в виде
<значение> IS [NOT] NAN .
Условие IS NAN (is Not a Number) позволяет определить, что значение не
является корректным числом, а получилось в результате какой-нибудь
недопустимой операции, например, деления на 0.
Например, можно проверить, что все значения оплат в таблице PaySumma
являются корректными числовыми значениями:
SELECT * FROM PaySumma WHERE PaySumma IS NOT NAN;
В результате будут выведены все строки таблицы оплат.
Проверка значения на равенство бесконечности (все равно, плюс или
минус) выполняется в виде
<значение> IS [NOT] INFINITE .
Следует отметить, что для значений с плавающей запятой можно
использовать и обычные условия сравнения. Однако всегда нужно помнить,
что при работе с такими значениями возможны потенциальные проблемы,
связанные с округлением, поэтому при возможности значений с плавающей
запятой лучше избегать.
3.2.2.3. Проверка на логическое значение
При работе с СУБД Firebird может возникнуть необходимость выполнить
проверку значения логического типа на соответствие одному из значений
трехзначной логики (TRUE, FALSE или UNKNOWN). Из рассматриваемых в
учебнике СУБД только Firebird поддерживает логический тип данных
BOOLEAN, поэтому проверка на логическое значение актуальна только для
этой СУБД.
22
Логическая проверка выполняется в виде
<значение> IS [NOT] {TRUE | FALSE | UNKNOWN}.
Например, для вывода номеров лицевых счетов абонентов и дат подачи
ими непогашенных ремонтных заявок можно использовать запрос
SELECT AccountCD, IncomingDate FROM Request WHERE Executed IS FALSE;
Результат выполнения запроса представлен на рис. 3.10.
5.
ACCOUNTCD INCOMINGDATE
015527
28.02.2012
080270
31.12.2011
136159
01.04.2011
115705
28.12.2011
Рис. 3.10. Результат выполнения запроса
с простым сравнением
В СУБД Oracle и MS SQL Server отсутствует специальный тип для
логических значений и столбец Executed определен в учебной БД на Oracle
типом SMALLINT, а в учебной БД на MS SQL Server – типом BIT.
Вследствие этого приведенный выше запрос в Oracle и MS SQL Server
реализуется с помощью простого сравнения:
SELECT AccountCD, IncomingDate FROM Request WHERE Executed = 0;
Далее в учебнике запросы, обращающиеся к полю Executed таблицы
Request, будут приведены только в формате реализации для Firebird.
Следует также отметить, что результат выполнения запроса в Oracle и MS
SQL Server будет несколько отличаться от приведенного на рис. 3.10
вследствие разницы в хранении типов дата/время в различных СУБД. В
Oracle в столбец IncomingDate будет выведено "нулевое" время ('28.02.2012
00:00:00' и т.д.), а в MS SQL Server значения столбца IncomingDate будут
выведены в формате 'ГГГГ-ММ-ДД'. При демонстрации результатов
выполнения всех последующих запросов учебника со столбцами
IncomingDate и ExecutionDate, а также PayDate не будут оговариваться
отдельно и приводиться результаты для Oracle и MS SQL Server,
отличающиеся только форматом вывода указанных столбцов.
3.2.2.4. Проверка на принадлежность диапазону значений
Другой формой условия поиска является проверка на принадлежность
диапазону значений, которая реализуется с помощью предиката BETWEEN:
<значение> [NOT] BETWEEN <значение1> AND <значение2>.
При этом проверяется, находится ли значение данных между двумя
определенными значениями. В условие поиска входят 3 выражения. Первое
выражение (слева от ключевого слова BETWEEN) определяет проверяемое
значение; второе (после ключевого слова BETWEEN) и третье (после
ключевого слова AND) выражения определяют соответственно нижний и
верхний пределы проверяемого диапазона. При этом типы данных трех
выражений должны быть сравнимы. BETWEEN чувствителен к порядку, и
первое значение в конструкции должно быть первым по алфавиту, числовому
23
или хронологическому порядку. Например, если необходимо найти номера
лицевых счетов абонентов, у которых значения начислений за оказанные
услуги лежат в диапазоне от 60 до 250, то соответствующий запрос будет
выглядеть таким образом:
SELECT AccountCD, Nachislsum FROM NachislSumma
WHERE NachislSum BETWEEN 60 AND 250;
Результат
выполнения ACCOUNTCD NACHISLSUM
250,00
запроса представлен на рис. 115705
080047
80,00
3.11.
80,00
При
проверке
на 080047
принадлежность
диапазону 115705
250,00
нижний и верхний пределы 443069
80,00
считаются частью диапазона, 005488
62,13
поэтому в результаты запроса 080270
60,10
вошли лицевые счета, для 080613
239,33
которых значение начислений
126112
179,90
за оказанные услуги равно
180,13
250.
Инвертированная 136159
238,80
проверка на принадлежность 136160
237,38
диапазону позволяет выбрать 136160
значения, которые лежат за Рис. 3.11. Результат выполнения
пределами диапазона:
запроса с проверкой диапазона
значений
SELECT AccountCD FROM
NachislSumma
WHERE NachislSum NOT BETWEEN 60 AND 250;
3.2.2.5. Проверка на соответствие шаблону
Проверка на соответствие шаблону, которая осуществляется с помощью
предиката LIKE, позволяет определить, соответствует ли значение данных
некоторому шаблону. Синтаксис использования этого условия:
<значение> [NOT] LIKE 'шаблон' [ESCAPE 'символ_пропуска'].
Шаблон представляет собой строку, в которую могут входить один или
более подстановочных знаков. Подстановочный знак процента (%) совпадает
с любой последовательностью из нуля или более символов. Подстановочный
знак подчеркивания (_) совпадает с любым отдельным символом. При этом
следует помнить, что пробел рассматривается как обычный символ. В
операционной системе Windows знаку процента соответствует символ
звездочки (*), а знаку подчеркивания – знак вопроса (?). Подстановочные
знаки можно помещать в любое место строки шаблона, и в одной строке
может содержаться несколько подстановочных знаков.
При указании шаблона следует учитывать регистр символов. Так,
например, LIKE '%А%' и LIKE '%а%' задают разные условия поиска.
Например, пусть необходимо выбрать из таблицы Abonent абонентов, фамилии
которых начинаются с буквы С. Для условия поиска используется шаблон 'С%':
24
SELECT Fio FROM Abonent
FIO
WHERE Fio LIKE 'С%';
Свирина З.А.
Результат
выполнения
Стародубцев Е.В.
запроса представлен на рис. 3.12.
Рис. 3.12. Результат
выполнения
запроса к таблице
Abonent
Если точно неизвестна фамилия исполнителя ремонтных заявок с ФИО
Шлюков М.К. (Шлюков М.К. или Шлаков М.К.), можно воспользоваться
шаблоном 'Шл_ков М.К.%', чтобы получить информацию об интересующем
исполнителе с помощью запроса
SELECT ExecutorCD, Fio FROM Executor WHERE Fio LIKE 'Шл_ков М.К.%';
Результат выполнения запроса представлен на рис. 3.13.
EXECUTORCD
FIO
4
Шлюков М.К.
Рис. 3.13. Результат выполнения запроса
к таблице Executor
В учебной БД для описания столбца Fio используется тип VARCHAR(30),
из чего следует, что пробелы в конце строки отрезаются автоматически, и
поэтому в предыдущем примере можно было воспользоваться шаблоном
'Шл_ков М.К.' (без знака процента в конце). Однако в случае, если столбец в
таблице БД имеет тип CHAR(n), использование знака процента в конце
строки шаблона необходимо для того, чтобы строки с такими столбцами
(дополненными справа пробелами до общего количества символов n) были
включены в результат выполнения запроса.
При проверке строк на соответствие шаблону может оказаться, что
подстановочные знаки входят в строку символов в качестве литералов.
Например, нельзя проверить, содержится ли знак процента в строке, включив
его в шаблон, поскольку он будет считаться подстановочным знаком. В
стандарте ANSI/ISO определен способ проверки наличия в строке литералов,
использующихся в качестве подстановочных знаков. Для этого применяются
символы пропуска. Когда в шаблоне встречается такой символ, то символ,
следующий непосредственно за ним, считается не подстановочным знаком,
а литералом (т. е. происходит пропуск символа). Непосредственно за
символом пропуска может следовать либо один из двух подстановочных
знаков, либо сам символ пропуска, поскольку он тоже приобретает в шаблоне
особое значение. Символ пропуска определяется в виде строки, состоящей из
одного символа, и фразы ESCAPE. Например, чтобы найти фамилии
абонентов, начинающихся со знака процента, нужно выполнить запрос
SELECT Fio FROM Abonent WHERE Fio LIKE '$%%' ESCAPE '$';
Этот запрос не имеет результатов, так как в таблице Abonent нет
абонентов, фамилии которых начинаются с символа процента. Первый
25
символ процента в шаблоне, следующий за символом пропуска $, считается
литералом, второй считается подстановочным знаком.
3.2.2.6. Проверка на членство во множестве
Еще одним распространенным условием поиска является проверка
на членство во множестве неупорядоченных значений, которая реализуется с
помощью предиката IN:
<значение> [NOT] IN ( <значение1> [ , <значение2> …] ).
В этом случае проверяется, соответствует ли значение данных какомулибо значению из заданного списка. Например, чтобы вывести
неисправности с кодами, равными 12, 1 и 5, можно воспользоваться условием
поиска с проверкой на членство во множестве (12, 1, 5). Соответствующий
запрос к таблице Disrepair будет выглядеть так:
SELECT * FROM Disrepair WHERE FailureCD IN (12,1,5);
Результат выполнения запроса представлен на рис. 3.14.
FAILURECD
FAILURENM
1
Засорилась водогрейная колонка
5
Неисправен газовый счетчик
12
Неизвестна
Рис. 3.14. Результат выполнения запроса
с проверкой вхождения во множество
С помощью NOT IN можно убедиться в том, что значение данных не
является членом заданного множества. Если результатом проверяемого
выражения является NULL, то проверка IN также возвращает NULL. Все
значения в списке заданных значений должны иметь один и тот же тип данных,
который должен быть сравним с типом данных проверяемого выражения.
3.2.2.7. Проверка на NULL
Признак NULL обеспечивает возможность применения трехзначной
логики в условиях поиска. Результатом применения любого условия поиска
может быть TRUE, FALSE или UNKNOWN (если в одном из столбцов
содержится NULL). NULL никогда не равен другому NULL. Иногда бывает
необходимо явно проверять значения столбцов на NULL и непосредственно
обрабатывать их. Предикаты LIKE, BETWEEN и IN не позволяют
обнаружить NULL значения, например запрос
SELECT * FROM Abonent WHERE Phone IN ('556893', NULL);
вернет только одну строку, где Phone = '556893'.
Для выявления NULL значений в SQL имеется специальная проверка IS
NULL, работающая с любым типом данных:
<значение> IS [NOT] NULL.
Например, необходимо вывести номера лицевых счетов абонентов и даты
подачи ими заявок, по которым не выполнены ремонтные работы, т. е.
столбец ExecutionDate содержит NULL. Для этого можно использовать
запрос
SELECT AccountCD, IncomingDate FROM Request
26
WHERE ExecutionDate IS NULL;
Результат выполнения
запроса представлен на
рис. 3.15.
ACCOUNTCD INCOMINGDATE
080270
31.12.2011
115705
28.12.2011
Рис. 3.15. Результат выполнения
запроса
с проверкой значения на NULL
В отличие от условий поиска, описанных выше, проверка на NULL
не может возвратить NULL в качестве результата. Она всегда возвращает
TRUE или FALSE. Следует отметить, что нельзя проверить значение на
равенство NULL с помощью простой операции сравнения, например:
SELECT AccountCD, IncomingDate
FROM Request WHERE ExecutionDate = NULL;
Запрос не будет выдавать синтаксическую ошибку, так как теоретически
литерал NULL может участвовать во всех выражениях (A = NULL, B >
NULL, A + NULL, B || NULL и т. д.). Однако получится неправильный
результат (NULL), так как, если в операции сравнения одно из выражений
установлено в NULL, то и результат будет NULL.
3.2.2.8. Проверка на наличие последовательности символов
В СУБД Firebird и СУБД MS SQL Server, в дополнение к возможностям
предиката LIKE, существует отдельная возможность проверки строкового
значения на наличие последовательности символов.
В Firebird это реализуется с помощью предиката CONTAINING. Предикат
CONTAINING проверяет, содержит ли строковая величина, указанная слева
от него, последовательность символов, указанную справа. Синтаксис
использования этого условия поиска:
<значение> [NOT] CONTAINING <значение1>,
где <значение> – любое строковое выражение; <значение1> – строковая
константа.
Поиск CONTAINING является нечувствительным к регистру. Предикат
CONTAINING может быть использован для алфавитно-цифрового поиска
в числах и датах. Следующий пример выводит информацию обо всех
неисправностях, в названиях которых встречается 'Неисправ' (рис. 3.16):
SELECT * FROM Disrepair WHERE FailureNM CONTAINING 'Неисправ';
FAILURECD
FAILURENM
4
Неисправна печная горелка
5
Неисправен газовый счетчик
Рис. 3.16. Результат работы предиката CONTAINING
NOT CONTAINING используется для отбора строк, в которых заданное
значение не включает указанную строковую константу.
В MS SQL Server возможность проверки строкового значения на наличие
последовательности символов реализуется с помощью предиката CONTAINS
в виде:
27
CONTAINS ( { <столбец> | <список столбцов> | * } , <условие CONTAINS>
[ , LANGUAGE <язык> ] ),
где <условие CONTAINS> – строковое выражение, которое может содержать
подстановочные знаки аналогично шаблонам в предикате LIKE.
CONTAINS позволяет выполнять полнотекстовый поиск в столбцах
строковых типов данных CHAR, VARCHAR, NCHAR, NVARCHAR, TEXT,
NTEXT, XML, VARBINARY, VARBINARY(MAX) [23]. При этом
существуют важные ограничения: на SQL Server должен быть включен
полнотекстовый поиск (установлена компонента Full-text search), и для
столбцов, по которым осуществляется такой поиск, предварительно должен
быть создан полнотекстовый индекс (см. далее п.4.3). Подробно с
организацией полнотекстового поиска и созданием полнотекстовых индексов
в MS SQL Server можно ознакомиться в [23].
Предыдущий запрос, например в MS SQL Server с использованием
предиката CONTAINS, можно реализовать так:
SELECT * FROM Disrepair
WHERE CONTAINS(FailureNM, '"неисправ*"');
Для поиска по префиксному выражению после указания искомой
последовательности символов ставится звездочка, и все выражение
обязательно берется в двойные кавычки.
Если полнотекстовый индекс по столбцу отсутствует, то приведенный
запрос вернет ошибку.
3.2.2.9. Проверка на семантическое совпадение
СУБД MS SQL Server позволяет выполнять проверку не только на
наличие последовательности символов в строке (проверка синтаксиса), но
также выполнять полнотекстовый поиск на основании содержания
(семантики). Другими словами, выполняется поиск совпадения по смыслу, а
не буквального совпадения задаваемых слов, фраз или предложений. Данная
возможность реализуется с помощью предиката FREETEXT в формате:
FREETEXT ( { <столбец> | <список столбцов> | * } , <строка FREETEXT>
[ , LANGUAGE <язык> ] ).
Использование предиката FREETEXT, как и предиката CONTAINS,
требует наличия полнотекстового индекса для столбцов поиска. При наличии
индекса можно, например, составить запрос
SELECT * FROM Disrepair
WHERE FREETEXT(FailureNM, '"неисправ*"');
Соответствие регистрируется, если в полнотекстовом индексе указанного
столбца найден любой из терминов заданной строки в любой форме.
Полнотекстовые запросы с использованием FREETEXT являются менее
точными, нежели полнотекстовые запросы с использованием CONTAINS.
3.2.2.10. Проверка на совпадение с началом строки
В СУБД Firebird существует возможность проверки строкового
выражения на совпадение с началом строки путем использования предиката
28
STARTING WITH. В СУБД Oracle и СУБД MS SQL Server аналогичных
возможностей не предусмотрено.
Предикат STARTING WITH проверяет, совпадают ли начальные символы
строкового выражения, стоящего слева от него, с оговоренной строкой
символов, указанной справа. Синтаксис использования этого условия поиска
таков:
<значение> [NOT] STARTING WITH <значение1>,
где <значение> – любое строковое выражение; <значение1> – строковая
константа.
Предикат STARTING WITH является чувствительным к регистру.
Следующий запрос выводит данные обо всех абонентах, фамилия которых
начинается с буквы Т (рис. 3.17):
SELECT * FROM Abonent WHERE Fio STARTING WITH 'Т';
ACCOUNTC
D
443690
080270
STREETC
D
7
HOUSEN
O
5
FLATN
O
1
FIO
PHONE
Тулупова
214833
М.И.
6
35
6
Тимошкин 321002
а Н.Г.
Рис. 3.17. Результат работы предиката STARTING WITH
Следует отметить, что следующий запрос c проверкой на принадлежность
диапазону значений даст тот же результат:
SELECT * FROM Abonent WHERE Fio BETWEEN 'Т' AND 'Тя';
3.2.2.11. Проверка двух значений на отличие
Для проверки значений на отличие в Firebird используется синтаксис
<значение> IS [NOT] DISTINCT FROM <значение1>.
Предикат DISTINCT аналогичен предикату равенства с тем лишь
различием, что считает 2 признака NULL не различающимися (возвращает
TRUE при NULL=NULL). Поскольку предикат DISTINCT считает, что 2
признака NULL не различаются, то он никогда не возвращает неизвестное
значение. Подобно предикату IS [NOT] NULL предикат DISTINCT в качестве
результата возвращает только TRUE или FALSE. Например, требуется
вывести всю информацию о ремонтных заявках, даты выполнения которых
отличаются от 20.12.2011:
SELECT * FROM Request WHERE ExecutionDate IS DISTINCT FROM '20.12.2011';
В СУБД Oracle и MS SQL Server нет специальных предикатов для
проверки двух значений на отличие, и аналогичная проверка реализуется с
помощью одного из операторов сравнения.
Например, в MS SQL Server предыдущий запрос может быть записан так:
SELECT * FROM Request WHERE ExecutionDate != '20.12.2011';
Первые 3 строки НД представлены на рис. 3.18, из которого следует, что в
НД включена невыполненная заявка (признак NULL).
29
REQUES ACCOU EXECUT FAILUR INCOMING EXTCUTIO EXECU
TCD
NTCD
ORCD
ECD
DATE
NDATE
TED
2
115705
3
1
07.08.2011 12.08.2011
True
3
015527
1
12
28.02.2012 08.03.2012
False
5
080270
4
1
31.12.2011 NULL
False
…
…
…
…
…
…
…
Рис. 3.18. Результат выполнения запроса на проверку отличия
3.2.2.12. Проверка на соответствие регулярному выражению
Регулярные выражения (regular expressions) – формальный язык поиска и
осуществления манипуляций с подстроками в тексте, основанный на
использовании метасимволов. По сути, это строка-образец (шаблон, маска),
состоящая из символов и метасимволов и задающая правило поиска.
Регулярные выражения поддерживаются многими современными СУБД.
В СУБД Firebird для проверки текстовой строки на соответствие
регулярному выражению используется синтаксис [42]
<значение> [NOT] SIMILAR TO 'регулярное_выражение' [ESCAPE
'символ_пропуска'] ,
где <значение> – любое строковое выражение, а регулярное_выражение –
формальное выражение, состоящее из символов и метасимволов и задающее
правило проверки. В отличие от некоторых других языков для успешного
выполнения шаблон должен соответствовать всей строке – соответствие
подстроки не достаточно. Если один из операндов имеет значение NULL, то
и результат будет NULL, иначе результатом является TRUE или FALSE.
Основное отличие предиката SIMILAR от рассмотренного ранее
предиката LIKE состоит в существенно расширенных возможностях задания
шаблона, основанных на использовании правил построения регулярных
выражений. Как и в предикате LIKE, символ, определенный в разделе
ESCAPE, поставленный перед любым специальным символом, отменяет
специальную интерпретацию этого символа. Символы % и _ имеют точно
такой же смысл, что и в LIKE, однако добавлены POSIX-подобные
метасимволы:
символ | обозначает выбор одной либо другой альтернативы;
cимвол ? обозначает повторение предыдущего элемента 0 или 1 раз;
cимвол * обозначает повторение предыдущего элемента 0 или более раз;
cимвол + обозначает повторение предыдущего элемента 1 или более раз;
символ запятая (,) после числа обозначает повторение предыдущего
элемента как минимум это число раз;
символ обозначает отсутствие последующих элементов;
круглые скобки () могут быть использованы для группировки элементов в
один логический атом;
фигурные скобки {} используются для повторения элементов нужное
число раз. Если символ или класс сопровождаются единственным числом,
заключённым в фигурные скобки, то для соответствия нужно повторение
элемента точно в это число раз. Если фигурные скобки содержат два числа
30
(m и n), разделённых запятой, и второе число больше первого, то для
соответствия элемент должен быть повторен как минимум m раз и не
больше m+1 раз;
квадратные скобки [] определяют класс символов в точности так, как это
сделано в POSIX-совместимых регулярных выражениях. Символ в строке
соответствует классу в шаблоне, если символ является элементом класса.
Два символа, соединённых дефисом, в определении класса определяют
диапазон. Диапазон для активного сопоставления включает в себя эти два
конечных символа и все символы, находящиеся между ними. Диапазоны
могут быть помещены в любом месте в определении класса без
специальных разделителей, чтобы сохранить в классе и другие символы.
Если определение класса содержит знак вставки (), то все, что следует за
ним, исключается из класса. Все остальные символы проверяются.
Классом символов может быть:
- ALPHA: все латинские буквы (a-z, A-Z);
- UPPER: все прописные латинские буквы (A-Z);
- LOWER: все строчные латинские буквы (a-z);
- DIGIT: все арабские цифры (0-9);
- SPACE: пробел (ASCII 32);
- WHITESPACE: все символы-разделители [горизонтальная табуляция (9),
перевод строки (10), вертикальная табуляция (11), возврат каретки (13),
перевод страницы (12), пробел (32)];
- ALNUM: все латинские буквы (ALPHA) и арабские цифры (DIGIT).
В СУБД Oracle для проверки на соответствие регулярному выражению
используется функция
[NOT] REGEXP_LIKE (<значение> , 'регулярное_выражение').
В дополнение к приведенным выше POSIX-подобным метасимволам в
Oracle могут использоваться такие:
символ обозначает привязку выражения к началу строки;
символ $ обозначает привязку выражения к концу строки;
символ . обозначает один любой символ, но не символ новой строки.
Допустим, необходимо вывести информацию об абонентах, чьи ФИО
начинаются с буквы «М» или «Ш», за ней есть буква «к» (необязательно
непосредственно) и заканчиваются на «В.». В Firebird построим запрос:
SELECT * FROM Abonent WHERE Fio SIMILAR TO '(М|Ш)%к%В.';
или
SELECT * FROM Abonent WHERE Fio SIMILAR TO '[МШ]%к%В.';
Во втором запросе в скобках использовано явное перечисление отдельных
элементов. Для перечисления всех элементов из упорядоченного диапазона
класса следует использовать символ минус (–), например [М–Ш], что
означает перечисление всех заглавных букв кириллицы от М до Ш.
В Oracle предыдущие запросы можно записать так:
SELECT * FROM Abonent WHERE REGEXP_LIKE( Fio, '(М|Ш).*к*В.$');
или
31
SELECT * FROM Abonent WHERE REGEXP_LIKE( Fio, '^[МШ].*к.*В\.$');
Символ \ в запросе используется в качестве ESCAPE-символа (аналог
конструкции [ESCAPE 'символ_пропуска'] в предикате LIKE).
Рассмотрим еще один пример. Допустим, необходимо найти всех
абонентов, фамилии которых начинаются с заглавной буквы, а далее
записаны в нижнем регистре символов. Запрос будет выглядеть так:
SELECT * FROM Abonent WHERE Fio SIMILAR TO '[А-Я]%[а-я]%';
Регулярные выражения, помимо использования в секции WHERE, могут
применяться в ограничении CHECK запросов на создание домена (в Firebird)
и таблицы БД и в логическом условии операторов ветвления IF. Также,
например в Firebird, регулярные выражения могут использоваться в качестве
аргументов функции SUBSTRING.
Следует отметить, что регулярные выражения фактически не реализованы
в MS SQL Server и функции для проверки на соответствие регулярным
выражениям могут быть созданы только как определенные пользователем
функции CLR (Common Language Runtime).
3.2.2.13. Составные условия поиска
Рассмотренные в предыдущих пунктах условия поиска являются
простыми. С помощью правил логики эти простые условия можно
объединять в более сложные.
СУБД предоставляют 3 основных вида логических операций [29]:
NOT задает отрицание условия поиска, к которому применяется, и имеет
наивысший приоритет:
NOT <условие_поиска>;
AND создает сложный предикат, объединяя 2 или более условий поиска,
каждое из которых должно быть истинным, чтобы был истинным и весь
предикат. Данная операция является следующей по приоритету после
NOT. Используется синтаксис
<условие_поиска1> AND <условие_поиска2> …;
OR создает сложный предикат, объединяя 2 или более условий поиска,
из которых хотя бы одно должно быть истинным, чтобы был истинным
и весь предикат. Является последней по приоритету из трех логических
операций и имеет синтаксис
<условие_поиска1> OR <условие_поиска2> ….
Вычисления логических значений в составных условиях поиска задаются
таблицей истинности (табл. 3.1). В разных СУБД таблицы истинности могут
несколько отличаться, в основном из-за того, что поведение неопределенных
значений в логических операциях может быть различным. Возможность
сравнивать не только конкретные значения атрибутов с неопределенным
значением, но и результаты логических выражений, появилась в стандарте
SQL2, и для этого введена специальная логическая константа UNKNOWN.
Следует обратить внимание на то, что условия поиска, объединенные
с помощью ключевых слов AND, OR и NOT, сами могут быть составными.
32
Таблица 3.1. Логические результаты условий поиска AND и OR
У1
У2
У1 AND У2 У1 OR У2
(условие_поиска1 (условие_поиска2
)
)
TRUE
TRUE
TRUE
TRUE
TRUE (FALSE)
FALSE (TRUE)
FALSE
TRUE
TRUE
UNKNOWN
UNKNOWN TRUE
(UNKNOWN)
(TRUE)
FALSE
FALSE
FALSE
FALSE
FALSE
UNKNOWN
FALSE
UNKNOWN
(UNKNOWN)
(FALSE)
UNKNOWN
UNKNOWN
UNKNOWN UNKNOWN
Допустим, что необходимо найти ФИО всех абонентов, которые
проживают на улицах с кодами от 3 до 6 или фамилии которых содержат
букву «л». Для вывода требуемой информации (рис. 3.19) нужно выполнить
запрос:
SELECT Fio FROM Abonent
WHERE (StreetCD BETWEEN 3 AND 6) OR (Fio LIKE '%л%');
6.
Например,
необходимо
FIO
извлечь все данные об
Аксенов С.А.
Мищенко Е.В.
оплатах,
которые
были
Конюхов В.С.
произведены после 13 июня
Тулупова М.И.
2013 г. и значения которых
Стародубцев Е.В.
превышают
60.
Шмаков С.В.
Одновременно
с
этим
Маркова В.П.
вывести все данные об
Денисова Е.К.
оплатах,
которые
были
Тимошкина Н.Г.
сделаны
до
2012
г.
абонентом с лицевым счетом Рис. 3.19. Результат
выполнения
'005488'.
Для
решения
запроса к таблице
данной задачи в любой из
Abonent
рассматриваемых
СУБД
можно использовать запрос
SELECT * FROM PaySumma
WHERE (PayDate > '13.06.2013' AND PaySum>60) OR
(PayDate < '01.01.2012' AND AccountCD = '005488');
Результат выполнения запроса представлен на рис. 3.20.
33
PAYFAC ACCOUN SERVIC PAYSU PAYDAT PAYMONTH PAYYEA
TCD
TCD
ECD
M
E
R
2
005488
2
40,00
06.01.2011 12
2010
29
005488
1
65,00
03.05.2010 4
2010
52
015527
3
345,00 15.12.2013 11
2013
54
080270
3
278,00 06.12.2013 11
2013
59
136159
3
180,13 21.10.2013 9
2013
66
015527
4
611,30 03.11.2013 10
2013
74
136169
4
528,44 26.11.2013 10
2013
76
443069
4
444,45 16.11.2013 10
2013
Рис. 3.20. Результат выполнения запроса к таблице PaySumma
34