
ЗКИ 4 ПрПр(2) / Потменский пособие по ПРПР
.pdf
различными записями внутри единственной таблицы, например осуществлять поиск пар строк с общими значениями поля.
Синтаксис команды соединения с ее же копией тот же, что и для различных таблиц. Чтобы сослаться на столбцы запроса, нужно иметь два различных имени для одной и той же таблицы. Для этого надо определить временные имена, называемые переменными области определения, переменными корреляции, или алиасами. Они определяются в предложении запроса FROM. Для этого указывается имя таблицы, ставится пробел, а затем указывается имя алиаса для данной таблицы.
SELECT acname, b.cname, first.rating FROM Customers a, Customers b WHERE a.rating = b.rating;.
В приведенном примере SQL ведет себя так, как будто в операции соединения участвуют две таблицы, называемые «а» и «b». Обе они в действительности являются таблицей Customers, но алиасы позволяют рассматривать ее как две независимые таблицы. Получив две копии таблицы Customers, SQL выполняет операцию JOIN как для двух разных таблиц: выбирает очередную строку из одного алиаса и соединяет ее с каждой строкой из другого алиаса.
Выявление ошибок
Если каждому покупателю (customer) может быть назначен только один продавец (sales people), то ошибки можно выявить при помощи следующего запроса:
SELECT aonum, acnum, b.onum, b.cnum, b.snum
FROM Orders a, Orders b WHERE acnum = b.cnum
AND first.snum <> second.snum;.
Можно конструировать соединения (joins), которые содержат различные таблицы и алиасы единственной таблицы. Следующий запрос соединяет таблицу Customer с ее же копией для нахождения всех пар покупателей, обслуживаемых одним и тем же продавцом.
SELECT sname, Salespeople.snum, acname, b.cname, FROM Customers a, Customers b, Salespeople WHERE asnum = b.snum and
Salespeople.snum = a.snum AND acnum < b.cnum;.
В результате получаем данные в виде таблицы:
sname |
snum |
cname |
cname |
|
|
|
|
Serres |
1002 |
Liu |
Grass |
|
|
|
|
Peel |
1001 |
Hoffman |
Clammy |
|
|
|
|
SQL позволяет вкладывать запросы друг в друга. Обычно внутренний запрос генерирует значения, которые тестируются на предмет истинности
111
предиката:
SELECT * FROM Order
WHERE snum = (SELECT snum FROM Salespeople
WHERE sname = 'Motika'); SELECT *
FROM Order WHERE snum IN (SELECT Snum FROM Salespeople
WHERE city = 'London').
Можно формулировать подзапросы, в результате выполнения которых получается любое количество строк, применяя специальный оператор IN. IN определяет множество значений, которые тестируются на совпадения с другими значениями для определения истинности предиката. Когда IN применяется в подзапросе, SQL просто строит это множество из выходных данных подзапроса.
Использование оператора EXISTS
EXISTS — оператор, генерирующий значение «истина» или «ложь».
При применении связанных подзапросов предложение EXISTS, как и другие предикатные операторы, оценивается отдельно для каждой строки таблицы, на которую есть ссылка во внутреннем запросе.
Например, можно сделать запрос на поиск тех продавцов, которые имеют несколько покупателей:
SELECT DISTINCT Snum FROM Customers outer WHERE EXISTS (SELECT *
FROM Customers inner
WHERE inner.snum = outer.snum AND inner.cnum <> outer.cnum);.
Для каждой строки — кандидата внешнего запроса (представляющей рассматриваемого в настоящий момент покупателя) — внутренний запрос находит строки, имеющие соответствующие значения Snum (имеет того же продавца), но не значение Сnum (соответствует другому покупателю). Если строка, удовлетворяющая подобному критерию, найдена во внутреннем запросе, это означает, что различные покупатели обслуживаются данным продавцом (т.е. продавцом, обслуживающим покупателя, указанного в строке кандидата внешнего запроса). Следовательно, предикат EXISTS истинен для текущей строки и номер поля продавца (Snum) из таблицы внешнего запроса включается в состав выходных данных. Если бы не был задан DISTINCT, каждый из таких продавцов выбирался бы один раз для каждого покупателя, которого он обслуживает.
112
Специальный оператор ANY: SELECT *
FROM Salespeople WHERE city = ANY (SELECT city FROM Customers);.
Оператор ANY берет все значения поля city таблицы Customers, полученные в подзапросе, и оценивает результаты как истину, если какое-либо ANY-значение совпадает со значением поля city из текущей строки внешнего запроса. Это означает, что подзапрос должен выбирать значения того же типа, которые сравнивались в основном предикате. В этом отношении ANY отличается от EXISTS. Любой запрос, сформулированный в ANY (или с ALL), можно сформулировать и с EXISTS, хотя обратное утверждение неверно. Различия записываются в обработке NULL-значений (IS NULL).
SELECT * |
SELECT * |
FROM Salespeople |
FROM Salespeople outer |
WHERE Sname < ANY |
WHERE EXISTS |
(SELECT cname |
(SELECT * |
FROM Customers); |
FROM Customers inner |
|
WHERE outer.sname < inner.cname); |
|
|
Две эквивалентные формы:
«Найти всех продавцов, имеющих покупателей, имена которых следуют в алфавитном порядке за именем продавца».
Специальный оператор ALL
Предикат с ALL принимает значение «истина», если каждое (every) значение, выбранное в процессе выполнения подзапроса, удовлетворяет условию, заданному в предикате внешнего запроса.
Если было бы нужно, чтобы в состав выходных данных включались только те покупатели, рейтинг которых превышает рейтинг каждого покупателя в Rome, то необходимо было бы ввести команду:
SELECT * FROM Customers
WHERE rating > ALL (SELECT rating FROM Customers
WHERE city = 'Rome');.
Результат представлен в виде таблицы:
cnum |
cname |
city |
rating |
Snum |
|
|
|
|
|
2004 |
Grass |
Berlin |
300 |
1002 |
|
|
|
|
|
2008 |
cisneros |
San Jose |
300 |
1007 |
|
|
|
|
|
ANY и ALL могут быть приближенно заменены на EXISTS, тогда как обратное неверно. Верно и то, что подзапросы с EXISTS и NOT EXISTS могут
113
быть заменены теми же самыми подзапросами с COUNT (*) в предложении подзапроса SELECT. Если в состав выходных данных входит более чем 0 строк, то это эквивалентно ситуации EXISTS, в противном случае это то же самое, что
NOT EXISTS.
Рассмотрим примеры. 1. SELECT *
FROM Customers outer WHERE NOT EXISTS (SELECT *
FROM Customers inner
WHERE outer.rating < = inner.rating AND inner.city = Rome).
2. SELECT *
FROM Customers outer WHERE 1 >
(SELECT COUNT (*) FROM Customers inner
WHERE outer.rating < = inner.rating AND inner.city = 'Rome').
Результат представлен в виде таблицы:
cnum |
cname |
city |
rating |
snum |
|
|
|
|
|
2004 |
Grass |
Berlin |
300 |
1002 |
|
|
|
|
|
2008 |
cisneros |
San Jose |
300 |
1007 |
|
|
|
|
|
Использование предложения UNION
Можно задать множество запросов одновременно и комбинировать их выходные данные с использованием предложения UNION. UNION объединяет выходные данные двух или более SQL-запросов в единое множество строк и столбцов.
Для того чтобы получить сведения обо всех продавцах (Salespeople) и покупателях (Customers) Лондона в виде выходных данных одного запроса, следует ввести:
SELECT snum,
sname FROM Salespeople WHERE city - 'London' UNION SELECT cnum, cname
FROM Customers WHERE city = 'London'.
Результат представлен в таблице:
114
snum |
sname |
cnum |
cname |
1001 |
Peel |
|
|
1004 |
Motika |
|
|
2001 |
Hoffman |
|
|
2007 |
Pereira |
|
|
Для того чтобы более одного запроса можно было объединить (выполнить команду UNION), их столбцы, входящие в состав выходных данных, должны быть совместимы по объединению. Это значит, что в каждом из запросов может быть указано одинаковое количество столбцов, причем они должны быть сравнимы в некотором смысле.
UNION автоматически исключает из выходных данных дублирующие строки.
Внешнее соединение
Часто бывает полезна операция объединения двух запросов, в которой второй запрос выбирает строки, исключенные первым.
Обычно это приходится делать при исключении строк, не удовлетворяющих предикату, при выполнении операции соединения таблиц. Это называется внешним соединением.
Рассмотрим случай, когда необходимо найти список всех продавцов и пометить тех, кто не имеет покупателей, находящихся в их городе, также как и тех, кто таких покупателей имеет.
SELECT Salespeople.snum, sname, cname, comm FROM Salespeople, Customers
WHERE Salespeople.city = Customers.city UNION
SELECT snum, sname, 'NO MATCH', comm FROM Salespeople
WHERE NOT city - ANY (SELECT city
FROM Customer Order by 2 desc);.
1002 |
Serres |
Cisneros |
01300 |
|
|
|
|
1002 |
Serres |
Liu |
01300 |
|
|
|
|
1007 |
Rifkin |
No match |
01500 |
|
|
|
|
1001 |
Peel |
Clemens |
01200 |
|
|
|
|
1001 |
Peel |
Hoffman |
01200 |
|
|
|
|
1004 |
Motika |
Clemens |
01100 |
|
|
|
|
115

1004 |
Motika |
Hoffman |
01100 |
|
|
|
|
1003 |
Axelrod |
No match |
01000 |
|
|
|
|
Результат представлен в следующей таблице:
Ввод
Общий вид оператора ввода:
INSERT INTO <имя таблицы>
VALUES (<значение>, < значение>...). Пример:
INSERT INTO Customers (city, cname, cnum) VALUES ('London', 'Hoffman', 2001);
(в другие столбцы значения вводятся по умолчанию).
Допустим, у нас имеется таблица LondonStaff с такими же столбцами, как
Salespeople.
INSERT INTO LondonStaff SELECT *
FROM Salespeople WHERE city = 'London'.
Исключение строк из таблицы
Для исключения всех строк таблицы:
DELETE FROM Salespeople.
Можно удалить определенные строки:
DELETE FROM Salespeople WHERE snum =1003.
Редактирование значений полей
UPDATE Salespeople
SET sname = 'Gibson', city = 'Boston', comm = .10 WHERE snum = 1004;.
Предположим, назначено вознаграждение для каждого продавца, имеющего максимальный заказ на каждый день. Сведения о них можно сформировать в таблицу Bonus, содержащую значения поля snum для продавца, дату (odate) и объем заказа (amt). Эту таблицу можно заполнить информацией, хранящейся в таблице Orders, используя команду:
INSERT INTO Bonus SELECT snum, odate, amt FROM Orders a
WHERE amt = (SELECT MAX (amt) FROM Orders b
WHERE aodate = b.odate);.
116

8.5. Основы реляционной алгебры
В основу создания баз данных была положена реляционная модель данных, предложенная сотрудником компании IBM И.Ф. Коддом в 1969 г.
Пусть имеются множества А и В. Отношение А к В указывает на связь между отдельными элементами этих множеств.
Множества могут соответствовать атрибутам или типам записей. Связи могут быть функциональными, т.е. удовлетворяющими определению математической функции. Кардинальные числа связей используются для определения типа отображения между парами множеств. Существуют отображения: «один — к — одному» (1:1), «один — ко — многим» (1 : М) и «многие — ко — многим» (М : N).
Рассмотрим примеры. В этих примерах имеются разные типы множеств. Один из них — это множество аналогичных сущностей:
множество номеров |
множество номеров |
страховых свидетельств; |
служащих; |
множество служащих |
множество домов, в которых |
|
они проживают. |
Рис. 8.7. Примеры связей кардинальности М : N
Для всех функциональных связей справедливо, что атрибут (или сущность), который является областью определения, однозначно определяет атрибут (или сущность) области значений. Говорят, что атрибут области определения однозначно определяет атрибут области значений, или иначе — последний зависит от первого. Это приводит к понятию функциональной зависимости в теории баз данных. В теории реляционных баз данных были выделены некоторые свойства функциональных зависимостей и сформулированы в виде аксиом. Эти аксиомы называются также правилами вывода, т.к. используя их, можно вывести или получить из известных функциональных зависимостей ряд других.
Прежде всего несколько замечаний о математических функциях.
Пусть D И R множества. Математическая функция f: D R есть отображение множества D на (или во) множество R, Множество D называется областью определения, а множество R — областью значений функции f. Отображение может быть инъективным, сюръективным или биективным. Множество объектов и операций называется категорией.
Функция является подмножеством декартова произведения (D х R) множеств DnR, причем если (х, у) и (х, z) упорядоченные пары в f то у и z должны быть равны друг другу, т.е. элемент из D всегда отображается в единственную точку в Q. Функция f называется всюду определенной или
117
полной, если {х | (х, у) f } = D, т.е. каждому элементу из D соответствует некоторый элемент в Q. Функция f называется частичной, если f определена на некотором подмножестве D.
Основные правила вывода функциональных зависимостей
1. Рефлективность. Пусть задано множество X и Y X тогда Х Х или Х
Y. Это тривиальные функциональные зависимости, означающие, что множество определяет любое свое подмножество.
2.Транзитивность. Если X Y и X Z, то X Z.
3.Дополнительность. ЕслиX Y, X W, то W Y.
Следствие из основных правил
1.Аддитивность (объединение). Если X Y и W Z, то XW YZ или X Y и X Z, то X YZ.
2.Проективность (декомпозиция). Если X YZ, то X Y и Х Z.
3.Псевдотранзитивность. Если Х У и YW Z, то XW Z.
Вреляционных базах данных схема содержит как структурную, так и семантическую информацию. Структурная информация связана с объявлением отношений, а семантическая выражается множеством известных функциональных зависимостей между атрибутами отношений, объявленных в схеме. Однако некоторые функциональные зависимости могут быть нежелательными из-за небольших эффектов или аномалий, которые они вызывают. Нормализация устраняет нежелательные функциональные зависимости.
Нормализация
Формально процесс нормализации делится на пять шагов или этапов от первой нормальной формы до пятой. Выполнение каждого последующего этапа возможно лишь в том случае, если предыдущий этап завершился успешно. Последние две формы обычно пропускаются, т.к. для применения в проектировании типичных баз данных они являются слишком узкоспециализированными.
Атрибут, входящий в ключ, называется первичным, в противном случае он называется не первичным. Функциональная зависимость А В называется полной функциональной зависимостью, если В зависит от всей группы атрибутов А, а не от ее части (подмножества). Например, А =А1, А2, ...Ап и A1, A2B, то функциональная зависимость В от А неполная.
Первая нормальная форма (1НФ)
Отношения находятся в первой нормальной форме, если значение всех его атрибутов атомарные, т.е. значение атрибутов не должно быть множеством или повторяющейся группой.
Для того чтобы таблица соответствовала первой нормальной форме, каждый столбец этой таблицы должен быть полностью атомарным и не
118
содержать повторяющихся групп. Например, столбец «Адрес», содержащий не только название улицы, но и название города, страны и почтовый индекс, атомарным не является. Такие столбцы нужно разбивать на несколько столбцов, для того чтобы таблица полностью соответствовала первой нормальной форме.
Повторяющаяся группа — это столбцы, которые повторяются в пределах одной и той же строки для хранения значения одного и того же атрибута. Использование повторяющихся групп является плохой практикой, т.к. неоправданно расходуется дисковое пространство и не все элементы заполнены.
Вторая нормальная форма (2НФ)
Рассмотрим отношение: поставки (П#, товар, цена).
Предположим, что поставщик может поставлять различные товары, а один и тот же товар могут поставлять разные поставщики. Таким образом, ключ отношения выделен полужирным (П#, товар). Известно, что цена одинакового товара одинакова у всех поставщиков.
(П#, товар) -» ЦЕНА (по определению ключа), ТОВАР ЦЕНА.
Можно отметить неполную функциональную зависимость атрибута ЦЕНА от ключа.
Это приводит к следующим аномалиям:
—включения. Если у поставщика появляется новый товар, информация о нем и его цене не сможет хранится в базе данных до тех пор, пока поставщик не начнет поставлять его;
—удаления. Если поставки некоторого товара прекращаются, из базы данных придется удалить сведения о товаре и его цене, даже если он имеется в наличии у поставщика;
—обновления. При изменении цены товара необходим полный просмотр отношений с целью найти все поставки товара, чтобы изменение цены было отражено для всех поставщиков. Таким образом, изменения значения атрибута одного объекта влечет необходимость изменений в нескольких кортежах отношения: в противном случае база данных окажется несогласованной.
Разложение отношения ПОСТАВКИ на два отношения устраняет неполную функциональную зависимость.
Отношение находится во второй нормальной форме, если оно находится в 1НФ и каждый не первичный атрибут функционально полно зависит от ключа (ключей). Следующее разложение приводит к отношению в 2НФ:
ПОСТАВКИ (П#, ТОВАР), ЦЕНА ТОВАРА (ТОВАР, ЦЕНА).
Для того чтобы таблица соответствовала второй нормальной форме, каждый из ее столбцов должен зависеть от первичного ключа или от каждого атрибута первичного ключа, если такой атрибут состоит из нескольких
119
столбцов. Это означает, что все неключевые столбцы должны однозначно определяться с помощью первичного ключа таблицы.
Рассмотрим таблицу INVOICE. Если первичный ключ состоит из столбцов
LocationNo и InvoiceNo, то хранение адреса (Location) в столбце LocationName
этой же таблицы может привести к нарушению второй нормальной формы. Причины этого заключаются в том, что содержимое столбца LocationName для строк, содержащих один и тот же адрес, не будет однозначно идентифицировано первичным ключом. Однозначная идентификация будет проходить только по значению поля LocationNo, а значение InvoiceNo никак не повлияет на нее. Поэтому столбец LocationName нужно получать при необходимости из отдельной таблицы с помощью объединения, а не хранить в таблице INVOICE.
Третья нормальная форма
Рассмотрим транзитивную зависимость следующего типа: Если А В, В А (В не является ключом) и В С, то А С.
Пусть имеется отношение ХРАНЕНИЕ (фирма, склад, объем), которое содержит информацию о фирмах, получающих товары со складов, и об объемах этих складов. В отношении имеются функциональные зависимости:
ФИРМА СКЛАД, СКЛАД ОБЪЕМ.
Аномалии. Если на данный момент отсутствует фирма, получающая товар со склада, то в базу данных нельзя ввести информацию об объеме склада (аномалия включения). Если последняя фирма перестает получать товар со склада, данные о складе и его объеме нельзя сохранять в базе данных (аномалия удаления). Транзитивная зависимость (аналогично неполной функциональной зависимости в предыдущем примере) вызвана наличием в отношении двух семантически различных фактов.
Преобразование отношения в ЗНФ устраняет рассмотрение аномалии. Отношение находится в 3НФ, если оно находится в 2НФ и если в нем отсутствуют транзитивные зависимости непервичных атрибутов от ключа (ключей). Следующее разложение приводит к 3НФ:
ХРАНЕНИЕ (ФИРМА, СКЛАД), С_ОБЪЕМ (СКЛАД, ОБЪЕМ).
В таблице, соответствующей третьей нормальной форме, каждый столбец должен полностью зависеть только от первичного ключа, и все неключевые столбцы не должны зависеть друг от друга. Иными словами, неключевые столбцы таблицы, соответствующей третьей нормальной форме, должны не только однозначно определяться первичным ключом, но и не зависеть друг от друга.
Снова рассмотрим пример таблицы INVOICE. Пусть ключ таблицы состоит из столбцов LocationNo и InvoiceNo. Один из неключевых столбцов будет, по видимому, столбец CustomerNo. Если кроме столбца CustomerNo в
120