- •ЧАСТЬ I. Введение в реляционные базы данных
- •1. Структура реляционной базы данных
- •2. Целостность реляционных данных
- •2.3. Правила внешних ключей
- •3. Обработка данных
- •4. Проектирование РБД
- •4.4. Категоризация сущностей
- •4.5. Этапы проектирования
- •4.5.1. Логическое проектирование
- •4.5.2. Физическое проектирование
- •4.6. Условные обозначения, применяемые при проектировании РБД
- •4.7. Примеры проектов РБД
- •ЧАСТЬ И. Введение в язык SQL
- •5. Язык определения схемы (SDL)
- •5.1. Таблицы
- •6. Язык манипулирования данными (DML)
- •6.2. Запросы
- •Слисок литература
Следует отметить, что некоторые СУБД сразу после выполнения команд CREATE TABLE автоматически создают индексы для первичных ключей таблиц. В таких случаях отпадает необходимость в создании индексов для первичных ключей с помощью команды CREATE INDEX.
Синтаксис команды удаления индекса:
DROP INDEX <имя индекса>
Например:
DROP INDEX Фирма_индекс_пк
6. Язык манипулирования данными (DML)
Язык манипулирования данными содержит команды, предназначенные для добавления, удаления и изменения данных, а также команды запросов.
6.1. Команды добавления, удаления и изменения данных
Синтаксис команды добавления записи в таблицу:
INSERT INTO <имя таблицы> [(<список столбцов>)]
VALUES (<значение>,...)
значение может включать null.
Например, для внесения в таблицу "Деятельность" в РБД "Партнеры" (рис. 9 и 10) информации о деятельности фирмы "Спецстрой" необходимо выполнить следующую команду:
INSERT INTO Деятельность VALUES (5, 2, "Строительство")
Синтаксис команды удаления записей из таблицы:
DELETE FROM <имя таблицы> [WHERE <предикат>]
Например, если фирма "Квант" перестанет заниматься производством, то для удаления этой информации из таблицы "Деятельность" необходимо выполнить команду:
DELETE FROM Деятельность WHERE номер_деятельности = 4
Если же фирма "Квант" прекратит всякую деятельность, то для удаления этой информации из таблицы "Деятельность" необходимо выполнить команду:
DELETE FROM Деятельность WHERE номер_фирмы = 3 Синтаксис команды изменения значений полей в записях таблицы:
UPDATE <имя таблицы>
SET <имя столбца>=<значение>у...
[WHERE <предикат>]
значение может включать null.
Например, если у фирмы "Эрнест" сменится директор, то для изменения данных в таблице "Сотрудник" необходимо выполнить следующую команду:
UPDATE |
Сотрудник |
SET |
ФИО = "Александров А.А." |
WHERE |
номер_фирмы = 1 |
AND |
должность = "директор" |
6.2.Запросы
Запросы - наиболее часто используемое средство SQL. Запросы предназначены для поиска данных, с возможностью их сортировки и группировки. Запросы не изменяют ни объектов РБД, ни данных в ней.
Синтаксис запроса:
SELECT [DISTINCT | ALL] <список столбцов>
FROM <имя таблицы> [<алиас],...
[<имя таблицы> [алиас] LEFT OUTER JOIN <имя таблицы> [алиас]
ON <предикат> ...],...
[WHERE <предикат>]
[GROUP BY <список столбцов>] [HAVING <предикат>]
[ORDER BY <список имен столбцов \ список номеров столбцов по порядку> [DESC | ASC]]
Опция DISTINCT исключает дублирующиеся значения из результата выполнения запроса. Опция ALL имеет противоположное действие. Чаще всего по умолчанию используется ALL.
В предложении SELECT вместо списка столбцов может быть использован символ обозначающий "все столбцы". Например, для выбора всей информации из таблицы "Фирма" (рис. 9) достаточно написать следующий запрос:
SELECT *
FROM Фирма
Данный пример и все примеры запросов, приведенные ниже, относятся к РБД "Партнеры" (рис. 9 и 10).
6.2.1. Агрегатные функции
В запросах могут быть использованы скалярные выражения и константы, а также следующие агрегатные функции:
COUNT([DISTINCT|ALL] <имя столбца>) - количество выбранных записей (без учета записей со значением null, если аргумент не *);
SUM(<w*m столбца>) - сумма;
AVG(<UMJI столбцам) - среднее значение; ЫАХ(<имя столбца>) - максимальное значение; MIN(<гшя столбца>) - минимальное значение.
6.2.2.Предложение FROM
Предложение FROM указывает, из каких таблиц необходимо выбирать данные. Например, для выбора названий всех видов деятельности наших партнеров необходимо выполнить запрос из таблицы "Деятельность":
SELECT DISTINCT название
FROM Деятельность
Результат выполнения данного запроса:
название
Торговля
Производство
Аудит
6.2.3.Предложение WHERE
Предложение WHERE определяет условия выбора или соединения таблиц. В этом предложении могут быть использованы следующие операторы:
=, >, >=, <=, о - операторы сравнения; AND, OR, NOT - булевы операторы;
IN (<значение1>, <значение2>, ...| SELECT ...) - вхождение в множество; EXISTS (SELECT ...) - квантор существования результата выполнения
подзапроса;
BETWEEN <значение1> AND <значение2> - вхождение в интервал; LIKE <значение> - поиск символьных вхождений (подстрочек);
IS [NOT] NULL - проверка на неопределенное значения.
При поиске и сравнении символьных строчек могут быть использованы шаблоны:
% - любое количество любых символов, _ - любой один символ.
Примеры:
1. Выбрать фирмы, которые находятся в Москве и имеют капитал более 2 000 000 условных единиц.
SELECT название
FROM Фирма
WHERE город-'Москва"
AND капитал>2000000
название
Эрнест
Вега
2. Выбрать фирмы, которые находятся в Москве, Воронеже или
Мурманске. |
|
SELECT |
название |
FROM |
Фирма |
WHERE |
город IN ("Москва","Воронеж","Мурманск") |
название |
|
Эрнест |
|
Квант |
|
Вега |
|
3. Выбрать фирмы с капиталом от 500 000 до 3 000 000 условных един включая границы.
SELECT |
название |
FROM |
Фирма |
WHERE |
капитал BETWEEN 500000 AND 3000000 |
или |
|
SELECT |
название |
FROM |
Фирма |
WHERE |
капитал>=500000 |
AND |
капитал<=3000000 |
название |
|
Квант |
|
Вега |
|
4. Выбрать фирмы, которые находятся в городах, начинающихся на бук
•М".
SELECT |
название |
FROM |
Фирма |
WHERE |
город LIKE "М%" |
название
Эрнест
Квант
Вега
5. |
Выбрать |
деятельность фирм, для которых имеется информация |
директорах. |
|
|
SELECT |
Д.название |
|
FROM |
Деятельность Д |
|
WHERE |
Д.номер_фирмы IN |
|
|
( |
|
|
SELECT |
С.номер_фирмы |
|
FROM |
Сотрудник С |
|
WHERE |
С.должность = "директор" |
|
) |
|
название
Производство
Аудит
Аналогично, но с использованием оператора EXISTS:
SELECT |
Д.название |
|
FROM |
Деятельность Д |
|
WHERE |
EXISTS |
|
|
( |
С.номер_фирмы |
|
SELECT |
|
|
FROM |
Сотрудник С |
|
WHERE С.номер_фирмы=Д.номер_фирмы |
|
|
AND |
С.должность = "директор" |
|
) |
|
название
Производство
Аудит
6.2.4. Предложение GROUP BY
Предложение GROUP BY используется для группировки строк результата запроса. Предложение SELECT в этом случае применяется уже не к каждой строке таблицы, а к каждой группе строк. Поэтому каждое выражение в предложении SELECT должно принимать единственное значение для группы, т.е. оно может быть либо самим столбцом, указанным в предложении GROUP BY, либо арифметическим выражением, включающим этот столбец, либо константой, либо агрегатной функцией, например SUM, которая оперирует всеми значениями данного столбца в группе и сводит эти значения к единственному значению.
Пример:
Определить суммарный капитал фирм в каждом городе.
SELECT |
город, SUM(KanHTam) |
FROM |
Фирма |
GROUP |
BY город |
город |
SUM |
Москва |
6200000 |
Омск |
null |
Мурманск |
500000 |
6.2.5. Предложение HAVING
Предложение HAVING играет ту же роль для групп, что и предложение WHERE для строк, и используется только совместно с предложением GROUP BY. Поэтому в предикате предложения HAVING можно использовать только соответствующие агрегатные функции и столбцы, по которым проводилась группировка.
Пример:
Выбрать города, в которых только одна фирма.
SELECT город
FROM Фирма
GROUP BY город
HAVING COUNT(*)=l
город
Омск
Мурманск
6.2.6. Предложение ORDER BY
Предложение ORDER BY используется для упорядочивания результата запроса, при этом могут быть использованы опции:
DESC - сортировка по убыванию,
ASC - сортировка по возрастанию (действует по умолчанию).
Пример:
Выбрать фирмы в порядке убывания их капитала.
SELECT |
название, |
|
капитал |
FROM |
Фирма |
ORDER |
BY капитал DESC |
название |
капитал |
Эрнест |
4000000 |
Вега |
2200000 |
Квант |
500000 |
Спецстрой |
null |
6.2.7.Объединение результатов выполнения запросов. Оператор UNION
В математике объединением двух множеств называется множество всех элементов, принадлежащих какому-либо одному или сразу обоим исходным множествам. В результате выполнения запросов получаются таблицы, представляющие собой множества строк. Для этих множеств можно построить объединение. В результате будет получено множество строк, входящих в какуюлибо одну или сразу в обе исходных таблицы. При этом две первоначальных таблицы должны быть совместимы по объединению. В языке SQL две таблицы совместимы по объединению [4], т.е. к ним может быть применен оператор объединения UNION, тогда и только тогда, когда:
а) они имеют одинаковое число столбцов, например т\
б) для всех /(/ = /, т) /-й столбец первой таблицы и i-й столбец второй таблицы имеют в точности одинаковый тип данных:
-для типа данных decimal(p, q) р и q должны быть одинаковыми для обоих столбцов;
-для типа данных char(n) п должно быть одинаковым для обоих столбцов;
-если NOT NULL специфицировано для какого-либо из этих столбцов, то такая же спецификация должна быть для другого столбца.
Пример:
Выбрать фирмы, которые либо находятся в Москве, либо имеют капитал более 400000, либо то и другое и упорядочить по алфавиту.
SELECT |
название |
FROM |
Фирма |
WHERE |
город-'Москва" |
UNION |
|
SELECT |
название |
FROM |
Фирма |
WHERE |
капитал>400000 |
ORDER BY 1
название
Вега
Квант
Эрнест
Из этого простого примера следует несколько соображений:
1) дубликаты всегда исключаются из результата UNION. Поэтому, хотя в рассматриваемом примере фирма "Эрнест" выбирается обеими из двух составляющих предложений SELECT, в окончательном результате она появляется только один раз;
2) любое число предложений SELECT может быть соединено оператором UNION. Например, к полученному списку можно добавить те фирмы, у которых не указан вид деятельности, дополнив приведенный выше запрос еще одним:
SELECT |
название |
|
FROM |
Фирма |
|
WHERE |
город="Москва" |
|
UNION |
|
|
SELECT |
название |
|
FROM |
Фирма |
|
WHERE |
капитал>400000 |
|
UNION |
|
|
SELECT |
Ф.название |
|
FROM |
Фирма Ф |
|
WHERE |
NOT EXISTS |
|
|
( |
* |
|
SELECT |
|
|
FROM |
Деятельность Д |
WHERE Д.номер_фирмы=Ф.номер_фирмы
)
ORDER BY 1
название
Вега
Квант
Спецстрой
Эрнест
3) предложение ORDER BY в запросе должно входить как часть только в последнее предпожение SELECT. При этом ORDER BY должно определять столбцы, по которым осуществляется упорядочение, путем указания их порядковых номеров;
4) в связи с оператором UNION часто оказывается полезной возможность включения констант в предложение SELECT, например:
SELECT |
название, |
|
"город Москва" причина |
FROM |
Фирма |
WHERE |
города"Москва" |
UNION |
название, |
SELECT |
|
|
"капитал больше 400000" причина |
FROM |
Фирма |
WHERE |
капитал>400000 |
UNION |
|
|
SELECT |
Ф.название, |
|
|
"нет деятельности" причина |
|
FROM |
Фирма Ф |
|
WHERE |
NOT EXISTS |
|
|
( |
* |
|
SELECT |
|
|
FROM |
Деятельность Д |
|
WHERE Д.номер_фирмы=Ф.номер__фирмы |
|
|
) |
|
ORDER BY 1,2 |
|
|
название |
|
причина |
Вега |
|
город Москва |
Вега |
|
капитал больше 400000 |
Квант |
|
капитал больше 400000 |
Спецстрой |
|
нет деятельности |
Эрнест |
|
город Москва |
Эрнест |
|
капитал больше 400000 |
6.2.8. Соединение таблиц
Пусть требуется выбрать всех сотрудников из таблицы "Сотрудник" с указанием фирм, в которых они работают. Для этого достаточно выполнить следующий запрос:
SELECT |
ФИО, |
|
название |
FROM |
Сотрудник С, |
|
Фирма Ф, |
WHERE |
Ф.номер_фирмы = С.номер_фирмы |
ФИО |
название |
Иванов И.И. |
Эрнест |
Сидорова М.Н. |
Эрнест |
Петров П.П. |
Вега |
Антонов А.А. |
Спецстрой |
Вэтом запросе использована реляционная операция соединения таблиц "Сотрудник" и "Фирма" (более точное название - прямое соединение таблиц). Эту операцию можно осуществить, последовательно выполняя реляционные операции произведения (декартова), выборки и проекции (см. п. 3).
Врезультате произведения таблиц "Сотрудник" и "Фирма", указанных в предложении FROM, будет получена таблица, содержащая все столбцы из обеих исходных таблиц. Строки в этой таблице-произведении будут представлять собой все возможные комбинации пар строк из двух исходных таблиц (всего 16 комбинаций):
Таблица-произведение |
|
ФИО |
Номер |
|
Номер |
Название |
Номер |
||
фирмы |
|
сотрудника |
|
фирмы |
1 |
Эрнест |
1 |
Иванов И.И. |
1 |
1 |
Эрнест |
2 |
Сидорова М.Н. |
1 |
1 |
Эрнест |
3 |
Петров П.П. |
4 |
1 |
Эрнест |
4 |
Антонов А.А. |
2 |
2 |
Спецстрой |
1 |
Иванов И.И. |
1 |
2 |
Спецстрой |
2 |
Сидорова М.Н. |
1 |
2 |
Спецстрой |
3 |
Петров П.П. |
4 |
2 |
Спецстрой |
4 |
Антонов А.А. |
2 |
3 |
Квант |
1 |
Иванов И.И. |
1 |
3 |
Квант |
2 |
Сидорова М.Н. |
1 |
3 |
Квант |
3 |
Петров П.П. |
4 |
3 |
Квант |
4 |
Антонов А.А. |
2 |
4 |
Вега |
1 |
Иванов И.И. |
1 |
4 |
Вега |
2 |
Сидорова М.Н. |
1 |
4 |
Вега |
3 |
Петров П.П. |
4 |
4 |
Вега |
4 |
Антонов А.А. |
2 |
Далее, в результате выборки из таблицы-произведения в соответствии с условием, указанным в предложении WHERE, в таблице-выборке останутся только те строки, в которых значения крайних столбцов совпадают:
Таблица-выборка |
Номер |
|
Номер |
|
Номер |
Название |
ФИО |
||
фирмы |
|
сотрудника |
|
фирмы |
1 |
Эрнест |
1 |
Иванов И.И. |
1 |
1 |
Эрнест |
2 |
Сидорова М.Н. |
1 |
2 |
Спецстрой |
4 |
Антонов А.А. |
2 |
4 |
Вега |
4 |
Петров П.П. |
4 |
И, наконец, после выполнения проекции, в результирующей таблице будут оставлены только те столбцы, которые указаны в предложении SELECT:
Результирующая таблица
Название |
ФИО |
Эрнест |
Иванов И.И. |
Эрнест |
Сидорова М.Н. |
Спецстрой |
Антонов А.А. |
Вега |
Петров П.П. |
Итак, получена таблица с точностью до порядка строк и столбцов совпадающая с результатом выполнения запроса.
Теперь необходимо сделать два замечания.
1. На практике при выполнении запросов операция соединения таблиц осуществляется по гораздо более эффективным алгоритмам [3], в которых громоздкая операции произведения не используется.
2. Для получения приведенной выше таблицы-произведения достаточно выполнить запрос
SELECT *
FROM Сотрудник, Фирма
т.е. произведение таблиц осуществляется всякий раз, когда в предложении WHERE для них не указано условие соединения. Более общий пример:
SELECT |
Т1.название, |
|
|
Т4.название |
|
FROM |
Таблица1 |
Т1, |
|
Таблица2 |
Т2, |
|
ТаблицаЗ |
ТЗ, |
|
Таблица4 |
Т4 |
WHERE |
Т2.номер = Т1 .номер |
|
AND |
Т4.номер = Т2.номер |
Так как в предложении WHERE отсутствует условие ТЗ.номер = Т2.номер AND Т4.номер = ТЗ.номер, то в результате выполнения данного запроса таблица, образованная соединением таблиц "ТаблицаГ, " Таблица2" и " Таблица4", будет умножена на таблицу "ТаблицаЗ" В итоге вместо ожидаемых нескольких десятков строк пользователь может получить несколько миллионов строк, а сам запрос вместо нескольких секунд может выполняться несколько часов и даже суток. Подобные ошибки достаточно часто совершают начинающие пользователи языка SQL.
6.2.9. Внешнее соединение таблиц
Пусть требуется выбрать все фирмы из таблицы "Фирма" (Tj) вместе с именами сотрудников из характеристической таблицы "Сотрудник" (Г?).
При обычном соединении таблиц Tj и Т2
SELECT |
название, |
|
ФИО |
FROM |
Фирма Ф, |
|
Сотрудник С |
WHERE |
С.номер_фирмы = Ф.номер_фирмы |
из Т] будут выбраны только те фирмы, для которых указаны сотрудники в Т2:
название |
ФИО |
Эрнест |
Иванов И.И. |
Эрнест |
Сидорова М.Н. |
Спецстрой |
Антонов А.А. |
Вега |
Петров П.П. |
Такой результат не является удовлетворительным, т.к. в нем отображены не все фирмы - нет информации о фирме "Квант".
Для решения подобного рода задач, когда нет гарантии того, что в характеристической таблице есть данные для всех записей из характеризуемой таблицы, можно воспользоваться предложением для внешнего соединения таблиц LEFT OUTER JOIN (левое внешнее соединение), которое записывается в предложении FROM:
SELECT название, ФИО
FROM Фирма Ф LEFT OUTER JOIN Сотрудник С ON С.номер_фирмы = Ф.номерфирмы
Теперь из Гу будут выбраны все фирмы независимо от того, указаны для них сотрудники в Г? или нет:
название |
ФИО |
Эрнест |
Иванов И.И. |
Эрнест |
Сидорова М.Н. |
Спецстрой |
Антонов А.А. |
Квант |
null |
Вега |
Петров П.П. |
При этом возможны три случая:
1)если в Гз сотрудник для некоторой фирмы из Г/ не указан, то результат выполнения запроса будет содержать одну строку с названием этой фирмы и значением null для столбца "ФИО";
2)если в Г? указан только один сотрудник для некоторой фирмы из Г/, то результат выполнения запроса будет также содержать одну строку с названием этой фирмы и соответствующим значением для столбца "ФИО";
3)если в Т2 указано п сотрудников для некоторой фирмы из Гу, то результат выполнения запроса тоже будет содержать п строк с названием этой фирмы и соответствующими значениями для столбца "ФИО"
Следует отметить важное свойство: LEFT OUTER JOIN всегда сохраняет записи из таблицы, указанной слева от этого предложения ("Фирма"), а для таблицы, указанной справа от этого предложения ("Сотрудник"), действует принцип "как получится", т.е. данные из правой таблицы могут и не быть получены, тогда вместо них подставляется значение null.
Вобщем случае таблица Гу может иметь внешнее соединение сразу с несколькими таблицами, например:
SELECT Ф.название, ФИО, Д.название
FROM Фирма Ф LEFT OUTER JOIN Сотрудник С ON С.номер_фирмы = Ф.номер_фирмы LEFT OUTER JOIN Деятельность Д
ON Д.номер^фирмы = Ф.номер_фирмы
название |
ФИО |
название |
Эрнест |
Иванов И.И. |
Аудит |
Эрнест |
Сидорова М.Н. |
Аудит |
Спецстрой |
Антонов А.А. |
null |
Квант |
null |
Торговля |
Квант |
null |
Производство |
Вега |
Петров П.П. |
Производство |
В данном случае таблица "Фирма" соединяется внешним образом сразу с двумя таблицами: "Сотрудник" и "Деятельность"
6.2.10.Подзапросы в предложении SELECT
Как уже было сказано выше, в результате выполнения запроса получается таблица, например
SELECT название
FROM Фирма
название
Эрнест
Спецстрой
Квант
Вега
При необходимости для каждой строки этой таблицы можно выбрать дополнительные данные с помощью одного или нескольких подзапросов в предложении SELECT. Например, для каждой фирмы можно выбрать ФИО директора:
SELECT |
название, |
|
|
( |
|
|
SELECT ФИО |
|
|
FROM |
Сотрудник С |
|
WHERE |
С.номер фирмы = Ф.номерфирмы |
|
AND |
Сложность = "директор" |
|
) директор |
|
FROM |
Фирма Ф |
|
название |
|
директор |
Эрнест |
|
Иванов И.И. |
Спецстрой |
|
null |
Квант |
|
null |
Вега |
|
Петров П.П. |
Аналогичный результат можно получить с помощью подзапроса:
SELECT |
название, |
|
|
ФИО директор |
|
FROM |
Фирма Ф LEFT OUTER JOIN Сотрудник С |
|
|
ON |
С.номер_фирмы = Ф.номерфирмы |
|
AND |
Сложность = "директор" |
название |
|
директор |
Эрнест |
|
Иванов И.И. |
Спецстрой |
|
null |
Квант |
|
null |
Вега |
|
Петров П.П. |
Однако, в общем случае, выбор данных с помощью подзапросов в предложении SELECT существенно отличается от выбора данных с помощью LEFT OUTER JOIN. Дело в том, что подзапрос в предложении SELECT может вернуть только единственное значение или null. В частности, неверным будет запрос:
SELECT |
название. |
|
|
( |
|
|
SELECT ФИО, |
|
|
|
номер_сотрудника |
|
FROM |
Сотрудник С |
|
WHERE |
С.номер_фирмы = Ф.номер фирмы |
|
AND |
Сложность = "директор" |
|
) директор |
|
FROM |
Фирма Ф |
|
В предложении SELECT подзапроса нельзя выбирать значения сразу из двух столбцов. При этом абсолютно корректным будет запрос:
SELECT |
название, |
|
|
ФИО директор, |
|
|
номерсотрудника номер |
|
FROM |
Фирма Ф LEFT OUTER JOIN Сотрудник С |
|
|
ON |
С.номер_фирмы = Ф.номер_фирмы |
|
AND |
Сложность = "директор" |
название |
директор |
номер |
|
Эрнест |
Иванов |
И.И. |
1 |
Спецстрой |
null |
|
null |
Квант |
null |
|
null |
Вега |
Петров |
П.П. |
3 |
Также некорректным будет запрос:
SELECT |
название, |
|
|
( |
ФИО |
|
SELECT |
|
|
FROM |
Сотрудник С |
|
WHERE |
С.номер_фирмы = Ф.номер_фирмы |
|
) сотрудник |
|
FROM |
Фирма Ф |
|
Подзапрос не может возвращать более одного значения, а для фирмы "Эрнест" подзапрос вернет два значения Иванов И.И. и Сидорова М.Н. При этом вполне корректным будет запрос:
SELECT название, ФИО
FROM Фирма Ф LEFT OUTER JOIN Сотрудник С ON С.номерфирмы = Ф.номер_фирмы
название |
ФИО |
Эрнест |
Иванов И.И. |
Эрнест |
Сидорова М.Н. |
Спецстрой |
Антонов А.А. |
Квант |
null |
Вега |
Петров П.П. |
Таким образом, подзапросы в предложении SELECT следует использовать только тогда, когда есть гарантия того, что эти подзапросы вернут не более одного значения.
6.2.11. Трехзначная логика и null-значения
Вреальном мире существует проблема недостатка информации. В результате, весьма типичными являются ситуации, когда, например, "дата рождения сотрудника неизвестна", "имя оратора будет объявлено дополнительно", "место нахождения объекта в данный момент не определено" и т.п. Поэтому должен существовать механизм обработки подобных ситуаций в формальных моделях данных. Наиболее часто в качестве такого механизма используется трехзначная логика [3], которая, в отличие от обычной двухзначной логики, кроме значений true (истина) и false (ложь) также использует значение null (не определено).
Вработе [3] утверждается, что null-значения и трехзначная логика являются ошибочными понятиями и им нет места в чисто формальных системах,
вчастности в реляционной модели. При этом выражается согласие с тем, что проблема отсутствующей информации еще не полностью исследована и пока не существует какого-либо удовлетворительного решения этой проблемы. Таким образом, на сегодняшний день использование трехзначной логики в реляционной модели и, следовательно, в языке SQL является вынужденной мерой, порождающей целый ряд особенностей. Опишем некоторые из них:
1.Значение null не имеет однозначного смысла. Например, в таблице "Фирма" для фирмы "Спецстрой" значение в столбце "Капитал" не указано (в базе данных будет храниться null). С одной стороны, это можно истолковать как отсутствие у пользователя информации о капитале фирмы "Спецстрой", с другой - это может быть отражением некоммерческого статуса организации "Спецстрой", у которой капитала нет по определению.
2.Для поиска в таблицах записей с неопределенными значениями в какихлибо столбцах используется специальный оператор IS NULL. Например для поиска фирм, у которых капитал не определен, необходимо выполнить запрос:
SELECT |
название |
FROM |
Фирма |
WHERE |
капитал IS NULL |
название
Спецстрой С другой стороны, чтобы найти фирмы с известным капиталом,
необходимо выполнить запрос:
SELECT |
название |
FROM |
Фирма |
WHERE |
капитал IS NOT NULL |
название |
|
Эрнест |
|
Квант |
|
Вега |
|
3. Результатом выполнения запроса являются те табличные данные, для которых в предложении WHERE предикат принимает значение true. Если в предикате хотя бы одно из условий, связанных булевыми операторами AND, примет значение null, а все остальные условия при этом примут значение true, то в целом предикат примет значение null и соответствующие табличные данные в результат выполнения запроса не попадут. Например:
SELECT название
FROM Фирма
WHERE капитал>0
название
Эрнест
Квант
Вега
Фирмы "Спецстрой" в полученном списке нет, т.к. для нее условие капитал>0 имеет вид null>0 и, следовательно, принимает значение null, а не true.
4.Если на какой-либо столбец таблицы наложено ограничение уникальности значений, то в этой таблице не может более одной строки со значением null в указанном столбце, т.е. при проверке уникальности значения null ничем не отличаются от других определенных значений.
5.После выполнения команды
UPDATE |
Фирма |
SET |
город = null |
WHERE |
город = "Москва" |
запрос |
|
SELECT |
город, SUM(Kanjmui) |
FROM |
Фирма |
GROUP |
BY город |
ORDER |
BY 2 |
вернет следующий результат: |
|
город |
SUM |
Мурманск |
500000 |
null |
6200000 |
Омск |
null |
Из данного примера следуют два соображения:
-при выполнении предложения GROUP BY значения null ничем не отличаются от других определенных значений;
-при выполнении предложения ORDER BY независимо от опций DESC и
ASC значения null всегда располаг аются в конце списка (некоторые СУБД при выполнении запросов значения null всегда располагаются в начале списка).
6. При выполнении агрегатных функций значения null игнорируютс Например:
SELECT SUM(KanHTan) сумма
FROM ФирмИ
сумма
6700000
Однако, если аргументами агрегатной функции являются только значения null, то агрегатная функция также возвращает значение null:
SELECT |
город, БиМ(капитал) |
FROM |
Фирм0 |
GROUP |
BY город |
город |
SUM |
Москва |
6200000 |
Омск |
null |
Мурманск |
500000 |
В данном случае для фирм, находящихся в Омске, суммировались только значения null.
7. |
Пустая строка не равносильна значению null. Так, после выполнен |
команды |
|
UPDATE |
Фирма |
SET |
город ="" |
WHERE |
город = "Мурманск" |
запрос |
|
SELECT |
SUM(KanHTan) сумма |
FROM |
Фирма |
WHERE |
город = |
вернет следующий результат:
сумма
500000
Упражнения
1.В запросе в предикате предложения WHERE может быть записано сразу несколько условий выбора или соединения таблиц, связанных булевыми операторами AND и OR. Как вы думаете, может ли измениться скорость выполнения запроса от перемены мест названных условий?
2.Пересечение двух множеств представляет собой множество всех элементов, принадлежащих обеим исходным множествам. В языке SQL оператор пересечения INTERSECTION не поддерживается, однако он может быть смоделирован с помощью квантора существования EXISTS. Как это можно сделать? Приведите примеры запросов.
3.Разность двух множеств - это множество элементов, принадлежащих первому исходному множеству, но не принадлежащих второму. В языке SQL оператор разности DIFFERENCE не поддерживается, однако он может быть смоделирован с помощью квантора существования EXISTS. Как это можно сделать? Приведите примеры запросов.
4.Как вы думаете, можно ли с помощью запроса языка SQL извлечь из какой-либо таблицы последние к строк, если в качестве первичного ключа этой таблицы используется столбец со значениями типа integer?
5.Найдите две ошибки в запросе
SELECT |
Ф.город, |
|
|
ЗиМ(Ф.капитал), |
|
|
Ф.название, |
|
|
( |
Д.название |
|
SELECT |
|
|
FROM |
Деятельность Д |
|
WHERE |
Д.номер фирмы = Ф. номер_фирмы |
FROM |
) |
|
Фирма Ф |
|
|
GROUP |
BY Ф.город |
Как и с какими последствиями для результата их можно исправить.?
6.Ниже представлена РБД "Валютные документы"
Документ |
|
|
|
|
Валюта |
|
|
Номер |
Дата |
Сумма |
Номер |
|
Номер |
Код |
Название |
документа |
валюты |
|
валюты |
||||
0010 |
01.08.01 |
500.00 |
1 |
|
USD |
Доллар США |
|
ООП |
05.08.01 |
1200.00 |
2 |
|
2 |
DM |
Немецкая марка |
0012 |
14.08.01 |
800.00 |
1 |
|
|
|
|
|
|
Курс валюты |
|
|
|
|
|
|
|
Номер |
Дата |
Курс в руб. |
|
||
|
|
валюты |
|
||||
|
|
|
|
|
|
|
|
|
|
1 |
30.07.2001 |
29.05 |
|
|
|
|
|
2 |
03.08.2001 |
13.75 |
|
|
|
|
|
1 |
06.08.2001 |
29.10 |
|
|
|
|
|
2 |
06.08.2001 |
13.80 |
|
|
|
|
|
1 |
20.08.2001 |
29.20 |
|
|
|
|
|
|
|
Валюта |
|
|
|
|
|
номео валюты |
<рк> |
integer |
|
|
|
|
|
код |
|
<ак> |
char(10) |
|
|
|
|
название |
<ак> |
char(50) |
|
|
|
|
Документы |
|
|
Курс валюты |
номер документа |
<рк> |
chaW’20'1 |
номео валюты |
дата |
|
date |
дата |
сумма |
|
decimal(15,2) |
курс в руб. |
номер валюты |
<fk> |
integer |
|
< D k .fk > |
integer |
< р к > |
date |
|
decimal(15,2) |
Напишите один запрос, возвращающий список документов, в котором для каждого документа будут указаны номер документа, дата документа, код валюты, суммы в валюте, сумма в рублях.
7.В упр. 7 4.1 было предложено создать проект РБД для хранения древовидной структуры с неограниченным количеством уровней вложенности. Как вы думаете, можно ли одним запросом языка SQL извлечь все уровни такого дерева, если количество уровней заранее не известно?
8.Язык SQL обладает весьма ограниченным количеством команд. Как вы думаете, связано ли это с целостностью и обработкой данных? Ответ поясните.