
- •Введение
- •Общая схема банка данных в системе
- •Основные понятия
- •Базы данных
- •Банк данных как система управления основные понятия
- •Банк данных как автоматизированная система
- •Субд с включающим языком
- •Информационные системы
- •Документальные аис основные понятия дескриптор
- •Фактографические аис
- •Основные понятия
- •Основные данные
- •Уровни моделей
- •Классификация моделей
- •Роль подсхемы
- •Этапы проектирования базы данных
- •Архитектура банка данных
- •Последовательность действий при чтении записи
- •Инфологическое проектирование базы данных
- •Модели данных и подъязыки данных
- •Иерархическая модель данных
- •Сетевая модель данных
- •Реляционная модель данных
- •Реляционные базы данных
- •Алгебра отношений
- •Преимущества реляционных бд
- •Отношения
- •Нормализация отношений
- •Функциональная зависимость
- •Полная функциональная зависимость.
- •Проектирование баз данных.
- •Специальные операции над отношениями
- •Операции над отношениями.
- •Централизация и децентрализация процессов обработки данных.
- •Традиционный набор операций
- •Нормализация отношений
- •Исчисление отношений
- •Вторая и третья нормальные формы.
- •26. Язык запросов sql
- •1 Основы sql
- •Многотабличные запросы на чтение (объединения)
- •Сортировка результатов запроса (предложение order by)
- •Объединение результатов нескольких запросов (union)*
- •Запрос на объединение и сортировка *
- •Многотабличные запросы на чтение (объединения)
- •Простое объединение таблиц (объединение по равенству)
- •Запросы с использованием отношения предок/потомок
- •Объединения с условием для отбора строк
- •Несколько связанных столбцов
- •Запросы на чтение к трем и более таблицам
- •Чтение всех столбцов
- •Самообъединения
- •Псевдонимы таблиц
- •Правила выполнения многотабличных запросов
- •Внешнее объединение таблиц *
- •Итоговые запросы на чтение
- •Агрегатные функции
- •Агрегатные функции в списке возвращаемых столбцов
- •Запросы с группировкой (предложение group by)
- •Несколько столбцов группировки
- •Ограничения на запросы с группировкой
- •Вложенные запросы на чтение
- •Внешние ссылки
- •Вложенные запросы и объединения
- •Связанные вложенные запросы
- •Однострочный оператор insert
- •В интерактивном режиме удобно не включать в оператор insert список столбцов, так как это уменьшает длину оператора. В случае программного
- •Многострочный оператор insert
- •Удаление существующих данных
- •Удаление всех строк
- •Оператор delete с вложенным запросом *
- •Обновление существующих данных
Правила выполнения многотабличных запросов
Правила выполнения SQL-запроса расширенны для случая многотабличных запросов. Эти правила раскрывают смысл любого многотабличного оператора select, в точности определяя процедуру, которая всегда позволяет получить правильный набор результатов запроса.
Таблица результатов запроса на чтение генерируется следующим образом:
1. Если запрос представляет собой запрос на объединение операторов select, для каждого из этих операторов выполнить действия 2—5 и получить отдельную таблицу результатов.
2. Сформировать произведение таблиц, перечисленных в предложении from. Если в предложении from указана только одна таблица, то произведением будет она сама.
3. Если имеется предложение where, применить заданное в нем условие поиска к каждой строке таблицы произведения и оставить в ней только те строки, для которых это условие выполняется, т.е. имеет значение true; строки, для которых условие поиска имеет значение false или NULL, — отбросить.
4. Для каждой из оставшихся строк вычислить значение каждого элемента в списке возвращаемых столбцов и создать одну строку таблицы результатов запроса. При каждой ссылке на столбец используется значение столбца для текущей строки.
5. Если указано ключевое слово distinct, удалить из таблицы результатов запроса все повторяющиеся строки.
-
6. Если оператор является запросом на объединение операторов select, объединить результаты выполнения отдельных операторов в одну таблицу результатов запроса. Удалить из нее повторяющиеся строки, если не указано ключевое слово all.
7. Если имеется предложение order by, отсортировать результаты запроса.
Строки, полученные в результате выполнения перечисленных действий, составляют таблицу результатов запроса.
Выполним действия:
1. Из таблицы customers (21 строка) и таблицы orders (30 строк) сформируем таблицу произведения, состоящую из 630 строк (все возможные комбинации строк из двух таблиц).
2. Применяя условие поиска, определенное в предложении where, отберем только те строки таблицы произведения, в которых идентификаторы клиентов одинаковые (CUST_NUM = cust) и равны заданному идентификатору (cust == 2103). Останется только четыре строки, остальные 626 будут отброшены.
3. Из таблицы произведения выберем три столбца (company, order_Num и ord_amount), указанных в предложении select, и получим таблицу результатов запроса, состоящую из четырех строк.
4. В соответствии с предложением order by отсортируем четыре строки по столбцу order_num и получим окончательный результат. Очевидно, что ни одна реляционная СУБД не будет выполнять запрос подобным образом.
-
Внешнее объединение таблиц *
Операция объединения в SQL соединяет информацию из двух таблиц, формируя пары связанных строк из этих двух таблиц. Объединенную таблицу образуют пары тех строк из различных таблиц, у которых в связанных столбцах содержатся одинаковые значения. Если строка одной из таблиц не имеет пары, то объединение может привести к неожиданным результатам. Это иллюстрируют следующие далее запросы.
На первый взгляд, эти два запроса должны давать одинаковое количество строк; но результаты первого запроса насчитывают десять строк, а второго — только девять. Почему? Потому что Том Снайдер (Torn Snyder) в настоящий момент еще не получил назначение ни в один офис и его строка имеет значение null в столбце rep_office (это связанный столбец для данного объединения). Значение null не совпадает ни с одним идентификатором офиса в таблице offices, поэтому строка для Тома Снайдера в таблице salesreps остается без пары. В результате она "исчезает" из объединения. Таким образом, стандартное SQL-объединение может привести к потере информации, если объединяемые таблицы содержат несвязанные строки.
Опираясь на словесную версию второго запроса, можно предположить, что требуется получить результаты, которые возвращает следующий запрос:
Такие результаты запроса получаются с помощью другой операции объединения, называемой внешним объединением таблиц (в предложении where оно обозначается символом "*=="). Внешнее объединение является расширением стандартного объединения, называемого внутренним объединением таблиц. В стандарте SQL1 дано определение только внутреннего объединения; понятие внешнего объединения в нем отсутствует. Ранние программные продукты фирмы IBM также поддерживают только внутреннее объединение. Однако внешнее объединение является понятной и полезной частью реляционной модели базы данных и реализовано во многих СУБД, включая SQL Server, Oracle и SQLBase. Внешнее объединение — это наиболее естественный способ для выражения запросов определенного типа.
Чтобы понять смысл внешнего объединения, будет полезно отвлечься от учебной базы данных и рассмотреть две простые таблицы. В таблице girls находится список пяти девочек и городов, в которых они живут; в таблице boys содержится список пяти мальчиков и городов, в которых они живут. Чтобы найти пары девочек и мальчиков, живущих в одном и том же городе, можно использовать следующий запрос, формирующий внутреннее объединение двух таблиц:
Внутреннее объединение дает четыре строки в таблице результатов запроса. Обратите внимание, что две девочки (Анна и Нэнси) и два мальчика (Джеймс и Джордж) не представлены в таблице результатов запроса. Эти строки не имеют пары в другой таблице и поэтому отсутствуют в таблице результатов внутреннего объединения. Две несвязанные строки (Анна и Джеймс) имеют действительные значения в столбцах city, но они не совпадают ни с одним городом в противоположной таблице. Две другие несвязанные строки (Нэнси и Джордж) имеют в столбцах city значение null, а по правилам SQL значение null не равно никакому другому значению (даже другому значению null).
Предположим, что вы хотите вывести список пар девочка/мальчик живущих в одних и тех же городах, и включить в него девочек и мальчике без пары. Этот результат дает внешнее объединение таблиц girls и boy;
Оператор SQL, дающий в результате внешнее объединение:
Внешнее объединение двух таблиц содержит восемь строк. Четыре строки идентичны строкам внутреннего объединения этих таблиц. Две других строки, для Анны и Нэнси, являются несвязанными строками таблицы girls.
Эти строки были расширены значениями null, то есть приравнены к воображаемой строке таблицы boys, содержащей только значения null, и добавлены в результаты запроса. Две последние строки, для Джеймса и Джорджа, являются несвязанными строками таблицы boys. Эти строки также были расширены значениями null (приравнены к воображаемой строке таблицы girls, содержащей только значения null) и добавлены в результаты запроса.
Как видно из этого примера, внешнее объединение является объединением, "сохраняющим информацию". Каждая строка таблицы boys представлена в таблице результатов запроса (некоторые более одного раза). Аналогично, каждая строка таблицы girls представлена в таблице результатов (некоторые, опять таки, более одного раза).
1. Создать внутреннее объединение двух таблиц обычным способом.
2. Каждую строку первой таблицы, которая не имеет связи ни с одной строкой второй таблицы, добавить в результаты запроса, присваивая всем столбцам второй таблицы значение null.
3. Каждую строку второй таблицы, которая не имеет связи ни с одной строкой первой таблицы, добавить в результаты запроса, присваивая всем столбцам первой таблицы значение null.
4. Результирующая таблица является внешним объединением двух таблиц.
ЛЕВОЕ И ПРАВОЕ ВНЕШНИЕ ОБЪЕДИНЕНИЯ *
Внешнее объединение, полученное в предыдущем запросе, называется полным внешним объединением двух таблиц. Оно симметрично по отношению к обеим таблицам. Однако существуют еще два типа внешних объединений, которые не симметричны относительно двух таблиц.
Левое внешнее объединение двух таблиц получается, если выполнить пункт 1 и пункт 2, а пункт 3 пропустить. Таким образом, левое внешнее объединение включает все несвязанные строки первой (левой) таблицы с расширением null, но не включает несвязанные строки второй (правой) таблицы. Вот левое внешнее объединение таблиц GIRLS и BOYS:
Таблица результатов этого запроса содержит шесть строк: все пары девочка/мальчик из одних и тех же городов и девочки без пары. Мальчики, не имеющие пары, в этой таблице отсутствуют.
Правое внешнее объединение двух таблиц получается, если выполнить пункт 1 и пункт 3, а пункт 2 пропустить. Таким образом, правое внешнее объединение включает все несвязанные строки второй (правой) таблицы со значениями null, но не включает несвязанные строки первой (левой) таблицы. Вот правое внешнее объединение Таблиц GIRLS и BOYS:
Этот запрос дает таблицу результатов из шести строк: все пары девочка/мальчик из одних и тех же городов и мальчики без пары. На этот раз в таблицу не вошли девочки, не имеющие пары.
На практике левое и правое внешние объединения более полезны, чем полное внешнее объединение, особенно если таблицы связаны через внешний и первичный ключи. В таком объединении столбец внешнего ключа может содержать значения null, в результате чего таблица-потомок (таблица, содержащая внешний ключ) будет иметь несвязанные строки. Асимметричное внешнее объединение включит эти несвязанные строки в результаты запроса, не включая, однако, несвязанные строки таблицы-предка.
СИСТЕМА ЗАПИСИ ВНЕШНЕГО ОБЪЕДИНЕНИЯ *
Так как понятие внешнего объединения не вошло в стандарт SQL1 и не было реализовано в ранних программных продуктах фирмы IBM, поставщики тех СУБД, в которых это понятие поддерживалось, использовали различные системы записи в своих диалектах SQL. Система записи "*=*", использованная в примерах, применяется в SQL Server
В этой системе записи внешнее объединение обозначается добавлением звездочки (*) к операции сравнения в предложении where, задающем условие объединения. Для обозначения полного внешнего объединения двух таблиц tbli и TBL2 через связанные столбцы coli и COL2 звездочка (*) ставится слева и справа от стандартного оператора объединения. В результате операция сравнения, задающая полное внешнее объединение, выглядит следующим образом:
WHERE COL1 *==* COL2
Для обозначения левого внешнего объединения звездочка ставится только слева, и операция сравнения выглядит так:
WHERE COL1 *= COL2
Для обозначения правого внешнего объединения звездочка ставится справа, и операция сравнения имеет следующий вид:
WHERE COL1 =* COL2
Та же самая нотация используется и с другими операторами сравнения. Например, операция сравнения с оператором "больше чем или равно" (>=), задающая левое внешнее объединение, имеет такой вид:
WHERE COL1 *>== COL2
В СУБД Oracle и SQLBase также поддерживается операция внешнего объединения, но используется другая нотация. Внешнее объединение в предложении where обозначается знаком плюс в скобках, стоящим справа от названия столбца той таблицы, в которую добавляются строки со значениями null. Условие поиска, определяющее левое внешнее объединение, выглядит таким образом:
WHERE COL1 = COL2 (+)
а определяющее правое внешнее объединение — так:
WHERE COL1 (+) = COL2
Обратите внимание на то, что знак плюс находится на стороне оператора, противоположной той, на какой находится звездочка, применяемая в нотации SQL Server. СУБД Oracle и SQLBase не поддерживают полное внешнее объединение.
Хотя обе описанные системы записи внешнего объединения относительно удобны, они, тем не менее, несколько обманчивы. Сначала формируется произведение двух таблиц, а затем из него исключаются строки, не удовлетворяющие условию поиска в предложении where. Но произведение не содержит строк со значением null, входящих во внешнее объединение! Как они попадают в результаты запроса? Ответ состоит в том, что при формировании произведения необходимо обращаться к предложению where, чтобы выяснить, следует ли включать в произведение строки со значением null. Кроме того, две таблицы могут объединяться с помощью более чем одной пары связанных столбцов» и не ясно, как система записи должна использоваться, если имеются две или три пары связанных столбцов.
Проблемы с записью внешних объединений возникают также при расширении объединения до трех и более таблиц.
Понятие внешнего объединения можно легко расширить на три таблицы:
TBLl OUTER -JOIN TBL2 OUTER-JOIN TBL3
Но результат зависит от порядка выполнения операций внешнего объединения. Результат объединения
(TBLl OUTER-JOIN TBL2) OUTER-JOIN TBL3
в общем случае отличается от объединения
TBLl OUTER-JOIN (TBL2 OUTER-JOIN TBL3)
С помощью систем записи SQL Server или Oracle/SQLBase невозможно определить порядок выполнения внешних объединений. Из-за этого результаты внешнего объединения трех или более таблиц непредсказуемы.
ВНУТРЕННИЕ ОБЪЕДИНЕНИЯ В СТАНДАРТЕ SQL2
Изучить все варианты легче всего, рассматривая по очереди каждый тип объединения. Например, стандартное внутреннее объединение таблиц girls и boys на языке SQL1 можно выразить так:
В стандарте SQL2 это по-прежнему допустимый оператор, но его можно также записать следующим образом:
Обратите внимание на то, что две объединяемые таблицы соединяются явно посредством операции join, а условие поиска, описывающее объединение, находится теперь в предложении on внутри предложения from. В условии поиска, следующем за ключевым словом on, могут быть заданы любые критерии сравнения строк двух объединяемых таблиц. Предположим, например, что таблицы boys и girls были расширены путем добавления столбца age. Вот объединение, в котором связываются пары девочка/мальчик из одного города, а также требуется, чтобы мальчик и девочка в каждой паре были одного возраста:
В этих простых двухтабличных объединениях все содержимое предложения where просто перешло в предложение on, и предложение on не добавляет ничего нового в язык SQL. Вспомните, однако, что во внешних объединениях трех и более таблиц результат запроса зависит от порядка, в котором производятся объединения.
Стандарт SQL2 допускает еще один вариант запроса на простое внутреннее объединение таблиц girls и boys. Так как связанные столбцы этих таблиц имеют одинаковые имена и сравниваются на предмет равенства (что делается довольно часто), то можно использовать альтернативную форму предложения on, в которой задается список имен связанных столбцов:
В предложении using перечисляются через запятую имена связанных столбцов; они должны быть идентичными в обеих таблицах. Это предложение полностью эквивалентно предложению on, в котором каждая пара связанных столбцов задается явно, но намного компактнее и, следовательно, легче для понимания. Конечно, если связанные столбцы имеют разные имена в таблицах boys и girls, то необходимо использовать предложение on или where со знаком равенства. Предложение on требуется использовать также в том случае, если объединение не производится по равенству связанных столбцов. Например, если вы хотите выбрать пары девочка/мальчик, в которых девочка старше мальчика, то должны задать объединение с помощью предложения on:
Наконец, имеется еще один, последний вариант этого простого запроса, иллюстрирующий одну особенность предложения from в стандарте SQL2. Объединение двух таблиц, в котором связанные столбцы имеют идентичные имена, называется естественным объединением, так как обычно это действительно самый "естественный" способ объединения двух таблиц. Запрос на выборку пар девочка/мальчик, живущих в одних и тех же городах и имеющих тот же самый возраст, можно выразить как естественное объединение следующим образом:
Если задано ключевое слово natural, предложения on и using могут отсутствовать в запросе на объединение, так как в естественном объединении точно определено условие поиска для объединения двух таблиц — сравниваются все столбцы с идентичными именами в обеих таблицах.
В стандарте SQL2 определено, что объединение двух таблиц по умолчанию является внутренним объединением. Во всех предыдущих примерах можно опустить ключевое слово inner, и полученные в результате запросы по-прежнему будут действительными операторами стандарта SQL2, имеющими тот же самый смысл.
Внешние объединения в стандарте SQL2
Стандарт SQL2 обеспечивает полную поддержку внешних объединений, расширяя языковые конструкции, используемые для внутренних объединений. Например, полное внешнее объединение таблиц girls и boys (без столбцов age) создается следующим запросом:
Таблица результатов запроса будет содержать по одной строке для каждой связанной пары девочка/мальчик, а также по одной строке для каждой несвязанной записи для девочки или мальчика, расширенной значениями null в столбцах другой таблицы. В стандарте SQL2 для внешних объединений допустимы те же самые вариации, что и для внутренних объединений. Данный запрос можно было бы записать так:
Ключевое слово outer, так же как и ключевое слово inner, в стандарте SQL2 не является обязательным. Поэтому предыдущий запрос можно было бы переписать следующим образом:
По слову full СУБД сама определяет, что запрашивается внешнее объединение.
Вполне естественно, что в стандарте SQL2 левое и правое внешние объединения обозначаются словами left и right вместо слова full. Вот вариант того же запроса, определяющий левое внешнее объединение:
В результаты запроса войдут строки связанных пар девочка/мальчик и все несвязанные строки, содержащие null, из таблицы girls, но не войдут несвязанные строки из таблицы boys. И наоборот, вот вариант этого запроса, задающий правое внешнее объединение:
В данном случае в таблице результатов будут представлены пары мальчик/девочка и несвязанные строки из таблицы boys ("правая" таблица объединения); но будут отсутствовать несвязанные строки из таблицы girls.
ПЕРЕКРЕСТНЫЕ ОБЪЕДИНЕНИЯ И ЗАПРОСЫ НА ОБЪЕДИНЕНИЕ В SQL2
Расширенное предложение from в стандарте SQL2 поддерживает также два других способа соединения данных из двух таблиц — декартово произведение и запросы на объединение. Строго говоря, ни один из них не является операцией "объединения", но они поддерживаются в стандарте SQL2 с помощью тех же самых предложений, что и внутренние и внешние объединения. Вот запрос, создающий полное произведение таблиц girls и boys:
По определению, декартово произведение (иногда называемое "перекрестным объединением"; отсюда и название "cross join") содержит все возможные пары строк из двух таблиц. Оно является результатом "умножения" двух таблиц, превращая таблицы трех девочек и двух мальчиков в таблицу шести пар мальчик/девочка (3*2=6). Перекрестным объединениям не сопутствуют никакие "связанные столбцы" или "условия отбора", поэтому предложения on и using не допускаются.
Если декартово произведение таблиц girls и boys являете'; результатом их "умножения", то запрос на объединение двух таблиц является результатом их "сложения". В стандарте SQL2 запрос на объединение двух таблиц записывается следующим образом:
Результатом является таблица из пяти строк (3+2=5) и двух столбцов, в которой перечислены имена и города всех девочек и мальчиков.
Многотабличные объединения в стандарте SQL2
Одно из крупных преимуществ расширенного предложения From заключается в том, что оно дает единый стандарт для определения как внутренних и внешних объединений, так и произведений и запросов на объединение. Другим, даже еще более важным преимуществом этого предложения является то, что оно обеспечивает очень ясную и четкую спецификацию объединений трех и четырех таблиц, а также произведений и запросов на объединение. Для построения этих сложных объединений любые выражения объединения могут быть заключены в круглые скобки. Результирующее выражение, в свою очередь, можно использовать для создания других выражений объединения, как если бы оно было простой таблицей. Точно так же, как SQL позволяет с помощью круглых скобок комбинировать различные арифметические операции (+, - , * и /) и строить сложные выражения, стандарт SQL2 дает возможность создавать сложные выражения для объединений.
Чтобы привести пример многотабличного объединения, предположим, что к таблицам girls и boys добавлена новая таблица parents, которая имеет три столбца:
child Соответствует столбцу name в таблицах girls и boys type Принимает значение "father "(отец) или "mother "(мать) pname Имя родителя
Строка в таблице girls или boys может иметь две связанные строки в таблице parent, одна из которых определяет мать, а другая — отца, или может иметь только одну из этих строк, или может совсем не иметь связанных строк, если отсутствуют данные о родителях ребенка. В таблицах girls, boys и parents в совокупности содержится достаточно богатый набор данных, чтобы обеспечить несколько примеров многотабличных запросов.
Предположим, например, что вы хотите составить список всех детей и их родителей. Вот запрос, создающий такой список:
Так как это внутреннее объединение, то девочки и мальчики, не имеющие связанных строк в таблице parents, в таблицу результатов запроса не попадут. Модифицируя этот запрос в левое внешнее объединение, можно включить соответствующие этим детям строки (с расширением null) в результаты запроса:
Если по каким-либо причинам вы хотите включить в результаты запроса только несвязанные строки девочек, то для этого можно переделать данный запрос в запрос на объединение двух объединений, одного внутреннего и одного внешнего:
В качестве еще одного примера предположим, что вы опять, как в предыдущих примерах, хотите найти пары мальчик/девочка из одного и того же города, но на этот раз вы хотите еще и включить в таблицу результатов имя отца мальчика и имя матери девочки. То, что в объединениях данного примера могут присутствовать несвязанные строки, означает несколько возможных "правильных" ответов на запрос. Например, предположим, что вы хотите включить в результаты запроса все пары мальчик/девочка из одних и тех городов, даже те, в которых либо мальчик, либо девочка имеют строки, не связанные с таблицей parents. В этом запросе вам придется использовать два внешних объединения — (boys join parents) и (girls join parents) — и одно внутреннее: (boys join girls). В результате этот запрос в стандарте SQL2 будет выглядеть следующим образом:
Как видно из примера, даже запрос с тремя объединениями в соответствии со стандартом SQL2 может иметь весьма сложный вид. Однако, несмотря на эту сложность, запрос по стандарту SQL2 точно и однозначно определяет то, что должна выполнить СУБД. Нет никакой неясности в отношении порядка объединения таблиц или в отношении того, какие объединения являются внешними, а какие — внутренними. Возможность произвольного сочетания операций union и join обеспечивает гибкость предложения from. В общем, новые возможности стоят дополнительных сложностей расширенного предложения from стандарта SQL2.