РУКОВОДСТВО ПО РЕЛЯЦИОННОЙ СУБД DB2

         

СПРЕДЛОЖЕНИЯ МАНИПУЛИРОВАНИЯ ДАННЫМИ


предложение

: : =         предложение — select

| предложение — update

| предложение — delete  

| предложение — insert

предложение — select

: : =   выражение — union [фраза — упорядочения];

выражение — union

: : =         выражение — селекции [UNION выражение — union]

фраза — упорядочения

: : =         ORDER BY список — элемент — упорядочения

элемент — упорядочения

: : =         упорядочиваемый — столбец [ASC ] DESC]

упорядочиваемый — столбец

: : =         имя — столбца | целое

предложение — update

: : =         UPDATE имя — таблицы [псевдоним]

SET список — присваивание — столбцу [фраза — where];

присваивание — столбцу

: : =         имя — столбца = скалярное — выражение



| имя — столбца = NULL

предложение — delete

: : =         DELETE FROM имя — таблицы [псевдоним] [фраза — where]

предложение — insert

: : =         INSERT INTO имя — таблицы (список — имя — столбца)

исходные — значения;

исходные — значения

: : =         VALUES (список — элемент — вставки)

| выражение — селекции

элемент — вставки

: : =         константа | NULL




СРЕДСТВО DATA EXTRACT (DXT)


DATA EXTRACT (извлечение данных)—DXT—не является частью ни QMF, ни DB2. Это другой, поставляемый за отдельную плату, программный продукт. Однако на практике установка, на которой DXT используется для извлечения данных, будет, вероятно, использовать также и QMF для того, чтобы запрашивать и обновлять эти извлеченные данные, а также формировать по ним отчеты. Поэтому удобно включить в данную главу краткое описание DXT.

Задача DXT заключается в том, чтобы извлечь некоторую копию специфицированных данных из базы данных, управляемой языком DL/1, или из наборов данных SAM или VSAM и построить файл, содержащий эту извлеченную копию, в формате, который требуется утилитой загрузки системы DB2. (Примечание. DXT может генерировать также файлы в формате, необходимом для SQL/DS. Однако в этой книге мы имеем дело с DB2.) Тогда эти данные могут быть загружены в какую-либо таблицу базы данных системы DB2, где они могут далее использоваться в качестве основы деятельности, связанной с запросами, обновлениями и/или генерацией отчетов, адекватной конкретному приложению. Поэтому задача состоит, по существу, в том, чтобы обеспечить в интерактивном режиме доступ средствами SQL или QBE к данным, которые первоначально хранились в некоторой нереляционной форме. Поскольку такой доступ в интерактивном режиме направлен на извлечение данных, т. е. на формирование копии, он не является помехой другому использованию этих данных. В частности, он не влияет на эффективность любых запланированных, регулярно выполняемых по расписанию работ, оперирующих этими данными.

Примечание. Для обеспечения эффективности или по другим причинам даже для базы данных системы DB2 может оказаться целесообразным осуществлять в интерактивном режиме некоторые или все работы, связанные с запросами и генерацией отчетов, над извлеченными данными, а не над самой базой данных. Однако в таком случае процесс извлечения данных может быть реализован с помощью обычных средств самой системы DB2—фактически, предложений CREATE TABLE и INSERT для множества записей; не требуется никаких средств, подобных DXT.


DXT состоит из двух основных компонентов. Один из них дает пользователю возможность создавать запросы на извлечение данных, а другой фактически выполняет эти запросы. Первый компонент, называемый the User Input Manager (средство управления пользовательским вводом), может исполняться в интерактивном режиме под управлением TSO (более простой метод) или как обычное пакетное задание MVS. При этом средство управления диалогом, которое управляет интерактивным исполнением в среде TSO, поставляется фактически как часть продукта QMF, а не самого DXT. Второй компонент, the Data Extraction Manager (средство управления извлечением данных), исполняется одним из следующих способов:

— как пакетное приложение IMS — для извлечения данных из пакетных баз данных DL/1 и, по желанию, из наборов данных SAM или VSAM

— как приложение «пакетной обработки сообщений» (BMP — batch message processing) системы IMS — для извлечения данных из баз данных DL/1, используемых в интерактивном режиме, и, по желанию, из наборов данных SAM или VSAM

— как пакетное задание

MVS — для извлечения данных из наборов данных SAM или VSAM.

Необязательный третий компонент DXT, the Dictionary Access Program (программа доступа к словарю данных) может оказывать помощь в процессе построения запросов на извлечение данных благодаря получению описаний исходных данных из словаря данных IBM DB/DC Data Dictionary, если это средство установлено.

В случае базы данных DL/1 данные можно извлекать из любого или из всех сегментов, принадлежащих одному иерархическому пути, и загружать их в одну таблицу системы DB2. При этом можно включать или исключать конкретные экземпляры сегментов в соответствии с предикатом, специфицированным в запросе на извлечение данных. Можно также по потребности включать или исключать конкретные поля сегментов.


СТАНДАРТНЫЕ ФУНКЦИИ


Хотя и весьма мощное во многих отношениях, предложение SELECT в том виде, как оно было до сих пор описано, остается все еще неадекватным для многих практических задач. Например, даже настолько простой запрос как «Сколько имеется поставщиков?» нельзя выразить, используя только введенные до сих пор конструкции. Для того чтобы усилить его основные возможности по выборке данных, в SQL предусматривается ряд специальных стандартных функций. В настоящее время доступны функции COUNT (число значений), SUM (сумма), AVG (среднее), МАХ (максимум) и MIN (минимум)[15]. Кроме специального случая «COUNT (*)» (см. ниже) каждая из этих функций оперирует совокупностью значений в одном столбце некоторой таблицы, возможно, производной,

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

COUNT    — число значений в столбце

SUM         — сумма значений по столбцу

AVG         — среднее значение в столбце

MAX        — самое большое значение в столбце

MIN          — самое малое значение в столбце

Для функций SUM и AVG рассматриваемый столбец должен содержать числовые значения. В общем случае аргументу функции может факультативно предшествовать ключевое слово DISTINCT (различный), указывающее, что избыточные дублирующие значения должны быть исключены перед тем, как будет применяться функция. Однако для функций МАХ и MIN ключевое слово DISTINCT не имеет отношения к делу и должно быть опущено. Для функции COUNT ключевое слово DISTINCT должно быть специфицировано. Специальная функция COUNT (*), для которой использование DISTINCT не допускается, предусмотрена для подсчета всех строк в таблице без исключения каких-либо дубликатов. Если DISTINCT специфицируется, то аргумент должен состоять только из имени столбца, например ВЕС. Если DISTINCT не специфицировано, аргумент может представлять собой арифметическое выражение, например ВЕС х 454.

В столбце-аргументе всегда перед применением функции исключаются все неопределенные значения, независимо от того, специфицировано ли DISTINCT, за исключением случая COUNT (*), при котором неопределенные значения обрабатываются точно так же, как и значения, не являющиеся неопределенными. Если оказывается, что аргумент — пустое множество, функция COUNT принимает значение нуль. Все другие функции принимают в этом случае неопределенное значение.



СВЫРАЖЕНИЯ СЕЛЕКЦИИ


выражение — селекции : : =   фраза — select

фраза — from

[фраза — where]

[фраза — группирования [фраза — having]]

фраза — select : : ==   SELECT [DISTINCT] спецификация — селекции

спецификация — селекции : : =   * | список — элемент — селекции

элемент — селекции : : =   имя — таблицы.*

| скалярное выражение

фраза — from : : =   FROM список — элемент — from

элемент — from : : =   имя — таблицы [псевдоним]

фраза — where : : =   WHERE предикат

фраза — группирования : : =   GROUP BY список — имя — столбца

фраза — having : : =   HAVING предикат



ТАБЛИЧНЫЕ ПРОСТРАНСТВА


Табличное пространство может рассматриваться как логическое адресное пространство во внешней памяти, используемое для размещения одной или нескольких хранимых таблиц («логическое» постольку, поскольку оно не является обычно множеством физически смежных областей). По мере того как растет объем данных в этих таблицах, для адаптации к такому росту из соответствующей группы памяти будет выделяться дополнительная память, которая добавляется к этому адресному пространству. Размер одного табличного пространства может достигать примерно 64 гигабайт, и нет никаких ограничений на число табличных пространств в базе данных, а также на количество баз данных[23]. Все страницы в заданном табличном пространстве имеют размер либо 4К, либо 32Кбайт (К=1024).

Существенно отметить, что табличное пространство является единицей памяти для целей реорганизации и восстановления. Это означает, что табличное пространство может быть восстановлено после отказов, связанных с носителями информации, или реорганизовано по команде с консоли оператора. Если, однако, табличное пространство очень велико, его реорганизация или восстановление потребовали бы очень много времени. Поэтому в DB2 предусматривается факультативная возможность сегментирования большого табличного пространства на более мелкие части. Для сегментированного табличного пространства единицей реорганизации и восстановления является отдельный его сегмент, а не полное табличное пространство.

Таким образом, различаются две разновидности табличных пространств — сегментированные и простые (несегментированные). Рассмотрим каждую из них.

Простые табличные пространства

Простое табличное пространство может содержать более одной таблицы, хотя обычный случай—это одна таблица. Возможность размещать в табличном пространстве более одной таблицы полезна тем, что хранимые записи могут группироваться в кластеры таким образом, чтобы улучшать времена доступа к логически связанным записям. Например, если таблицы S и SP хранились бы в одном и том же табличном пространстве, то было бы возможно (благодаря разумному использованию утилиты загрузки) хранить все записи поставок для поставщика S1 близко (т. е. на той же самой странице) к записи поставщика S1, все записи поставок для поставщика S2 близко к записи поставщика S2 и т. д. Тогда могут эффективно отрабатываться запросы вида «Выдать детали поставщика S1 и все соответствующие поставки», поскольку будет сокращаться число операций ввода-вывода.


3аметим, однако, что нелегко поддерживать такую кластеризацию в ситуации, когда произвольным образом осуществляются обновления. Кроме того, об этой кластеризации не имеют никакого понятия ни оптимизатор, ни утилита реорганизации. К тому же вполне возможно, что будет замедляться последовательный доступ, так как система должна будет просмотреть не только записи, относящиеся к данной таблице, но также и записи других таблиц, которые оказываются смешанными с первой таблицей. Вероятно, в большинстве ситуаций наиболее удовлетворительным является все-таки вариант организации, предусматривающей по одной таблице в каждом табличном пространстве.

Для каждой таблицы в данном табличном пространстве может иметься один или более индексов. Если таблица вообще имеет какие-либо индексы, то ровно один из них является индексом кластеризации для этой таблицы. Индексы кластеризации подробно обсуждаются в разделе 13.6. Поэтому ограничимся здесь следующим кратким пояснением. Индекс кластеризации, по существу,— это такой индекс, который используется для управления физическим размещением индексируемых записей таким образом, чтобы физическая последовательность записей в памяти была близка к логической последовательности этих записей, определяемой данным индексом. Если для таблицы имеется индекс кластеризации, то записи должны первоначально загружаться в эту таблицу в порядке кластеров с помощью утилиты загрузки. Они будут запоминаться в табличном пространстве в порядке поступления слева направо, т. е. по возрастанию последовательности адресов, с периодическими промежутками, которые позволят в будущем производить вставки. Заметим, что промежутки часто обусловливаются системой, а не пользователем. Если таблица не имеет индексов, то записи первоначально могут загружаться в произвольном порядке. И снова они будут запоминаться слева направо, но без каких-либо промежутков. Вставляемые впоследствии в эту таблицу записи будут запоминаться в каком-либо промежутке, если существует индекс кластеризации, и записи могут физически запоминаться вблизи их логических позиций. В противном случае они запоминаются в правом конце пространства.



Сегментированные табличные пространства

Сегментированное табличное пространство содержит в точности одну таблицу. Эта таблица сегментируется в соответствии с диапазоном значений поля или комбинаций полей сегментирования. Если, например, таблица поставок SP хранилась бы в сегментированном табличном пространстве, то она могла бы сегментироваться по значениям поля НОМЕР_ПОСТАВЩИКА таким образом, чтобы все поставки поставщика S1 запоминались в сегменте номер один, все поставки поставщика S2 — в сегменте номер два и т. д. Для поля или комбинации полей сегментирования нужен индекс кластеризации. Дополнительные индексы необязательны. Поле или комбинацию полей сегментирования нельзя обновлять. Записи первоначально должны загружаться в порядке кластеров с помощью утилиты загрузки. Они будут запоминаться слева направо в соответствующем сегменте с промежутками.

Как уже указывалось, отдельные сегменты сегментированного табличного пространства независимы друг от друга в том смысле, что их можно независимо восстанавливать и реорганизовывать. Они также могут быть связаны с различными группами памяти. Поэтому можно, например, хранить одни сегменты на более быстрых устройствах, а другие—на более медленных (различные группы памяти могут соответствовать различным типам устройств).


ТРИ ПРОБЛЕМЫ, СВЯЗАННЫЕ С ПАРАЛЛЕЛИЗМОМ


DB2 представляет собой совместно используемую систему, т. е. это система, позволяющая любому числу транзакций одновременно осуществлять доступ к одной и той же базе данных. Для каждой такой системы требуется некоторого рода механизм управления параллельными процессами, который бы обеспечивал, чтобы параллельно используемые транзакции не мешали действию друг друга и, конечно, система DB2 включает такой механизм (по существу, механизм блокирования). Для читателей, возможно, незнакомых с проблемами, которые могут возникнуть при отсутствии такого механизма (другими словами, с проблемами, которые способен решать такой механизм), эти проблемы в общих чертах поясняются в данном разделе. Обсуждению возможностей указанного механизма специально в системе DB2 будут посвящены разделы 11.5–11.7. Читатели, уже хорошо знакомые с основными идеями управления параллельными процессами, могут сразу же обратиться к этим разделам.

Имеется, по существу, три случая ошибочного исполнения (И соответственно три связанные с ними проблемы (см. ниже).—Примеч. пер.), т. е. три ситуации, когда транзакция, корректная сама по себе, может продуцировать тем не менее ошибочный результат из-за вмешательства со стороны некоторой другой транзакции, конечно, при отсутствии подходящего механизма управления. Заметим, между прочим, что транзакция, осуществляющая вмешательство, также может быть сама по себе корректна. Речь идет, таким образом, о чередовании операций из двух корректных транзакций, которое продуцирует в целом некорректный результат.

К указанным выше проблемам относятся:

1. Проблема утраченного обновления.

             2. Проблема зависимости от незафиксированных обновлений.

             3. Проблема анализа на противоречивость.

Рассмотрим поочередно каждую из них.

Проблема утраченного обновления

Рассмотрим ситуацию, показанную на рис. 11.1. Предполагается, что этот рисунок читается следующим образом: транзакция А осуществляет выборку некоторой записи R в момент времени t1.


Транзакция А

Время

Транзакция В









FETCH R

t1









t2

FETCH R





UPDATE R

t3









t4

UPDATE R





Рис. 11.1. Транзакция А утрачивает обновление в момент t4

Транзакция В осуществляет выборку той же самой записи R в момент времени t2. Транзакция А обновляет эту запись в момент t3 исходя из значений, «увиденных» в момент времени t1, а транзакция В обновляет ту же запись в момент времени t4, исходя из значений, «увиденных» в момент t2, являющихся теми же самыми, что и значения, «увиденные» в момент t1. Обновление, осуществляемое транзакцией А, утрачивается в момент t4, поскольку транзакция В перекрывает его своим обновлением, даже на него «не глядя».

Проблема зависимости от незафиксированных обновлений

Проблема зависимости от незафиксированных обновлений возникает в случае, если одной транзакции разрешается осуществлять выборку или, хуже того, обновление записи, которая уже была обновлена другой транзакцией, но это обновление еще не было зафиксировано этой другой транзакцией. Поскольку оно еще не было зафиксировано, всегда существует возможность, что оно никогда не будет зафиксировано, и вместо этого произойдет откат. В результате первая транзакция «увидит» некоторые данные, которые теперь больше не существуют, и в некотором смысле «никогда» не существовали. Рассмотрим рис. 11.2 и 11.3.

Транзакция А

Время

Транзакция В











t1

UPDATE R





FETCH R

t2









t3

ROLLBACK



Рис. 11.2. Транзакция А становится зависимой от незафиксированных изменений в момент t2

Транзакция А

Время

Транзакция В













t1

UPDATE R





UPDATE R

t2









t3

ROLLBACK



Рис. 11.3. Транзакция А обновляет незафиксированное изменение в момент t2 и утрачивает это обновление в момент t3

В первом из этих примеров (рис. 11.2) транзакция А «видит» незафиксированное обновление (или незафиксированное изменение) в момент t2. Затем это обновление в момент t3 аннулируется. Следовательно, транзакция А выполняется при ошибочном предположении, а именно при предположении, что запись R имеет значение, «увиденное» в момент t2, тогда как на самом деле она вообще имеет значение, которое имела до момента t1. В результате вполне возможно, что транзакция А будет продуцировать некорректный результат. Отметим, между прочим, что откат транзакции В (по команде ROLLBACK) может и не являться следствием каких-либо ошибок в В. Он может быть, например, результатом отказа системы. (И транзакция А уже может завершиться к этому времени. В результате отказ системы не вызовет необходимости издать команду ROLLBACK также и для А.)

Второй пример (рис. 11.3) еще хуже. Транзакция А не только становится зависимой от незафиксированного изменения данных в момент t2, но и фактически утрачивает обновление в момент t3, поскольку операция ROLLBACK в момент t3 заставляет восстановить для записи R ее значение, которое она имела в момент t1. Это другой вариант проблемы утраченного обновления.

Проблема анализа на противоречивость

Рассмотрим рис. 11.4, на котором показаны две транзакции А и В, оперирующие записями счетов. Транзакция А суммирует остатки на счетах, транзакция В переносит сумму 10 со счета 3 на счет 1. Продуцируемый А результат 110, очевидно, некорректен, и если бы А должна была записать этот результат в базу данных, она оставила бы фактически базу данных в противоречивом состоянии. Будем говорить, что А «видела» противоречивое состояние базы данных и поэтому провела анализ на противоречивость. Отметим различие между данным и предыдущим примером. Здесь нет проблемы зависимости А от незафиксированных изменений, поскольку В фиксирует все произведенные ею обновления прежде, чем А «увидит» запись СЧЕТА 3.



СЧЕТ 1

СЧЕТ 2

СЧЕТ 3

40

50

30

Транзакция А

Время

Транзакция В









FETCH СЧЕТ 1 (40):

СУММА == 40

t1







FETCH СЧЕТ 2 (50): СУММА = 90



t2









t3

FETCH СЧЕТ 3 (30)







t4

UPDATE СЧЕТ 3: 30®20







t5

FETCH СЧЕТ 1 (40)







t6

UPDATE СЧЕТ 1: 40®50







t7

COMMIT



FETCH СЧЕТ 3 (20): СУММА=110, а не 120

t8

Рис.

11.4. Транзакция А осуществляет анализ на противоречивость


ТУПИКОВАЯ СИТУАЦИЯ


Выше было показано, каким образом блокирование может использоваться для решения трех основных проблем параллельных процессов. Однако мы видели также, что, к сожалению, блокирование порождает свои собственные проблемы, прежде всего проблему тупиковых ситуаций. В разделе 11.5 были приведены два примера тупиковых ситуаций. Ниже на рис. 11.10 показан несколько более общий случай этой проблемы.

Примечание.

Имеется в виду, что приведенные на этом рисунке операции блокировки обозначают любые операции, устанавливающие блокировки, а совсем не обязательно предложения SQL LOCK TABLE.

Транзакция А

Время

Транзакция В

LOCK R1 IN X MODE

t1

t2

LOCK R2 IN X MODE

LOCK1R2 IN X MODE

t3

ждать

ждать

t4

LOCK R1 IN X MODE

ждать

ждать

ждать

ждать

Рис. 11.10. Пример тупиковой ситуации

 

Тупиковая ситуация — это такая ситуация, при которой две или более транзакции одновременно находятся в состоянии ожидания, и каждая из них ожидает, пока одна из других транзакций снимет блокировку, прежде чем ее исполнение сможет продолжаться. На рис. 11.10 показана тупиковая ситуация, вовлекающая две транзакции, но возможны также, по крайней мере теоретически, тупиковые ситуации, вовлекающие три, четыре и более транзакций. На практике, однако, тупиковые ситуации почти никогда не вовлекают более двух транзакций.

Если возникает тупиковая ситуация, система обнаруживает и ликвидирует ее. Для того чтобы ликвидировать тупиковую ситуацию, одна из вовлеченных в нее транзакций выбирается в качестве жертвы и, в зависимости от обстановки, либо автоматически производится ее откат, либо от нее требуется произвести откат самостоятельно. Между прочим на этот запрос не может последовать отказа. В любом случае данная транзакция снимет свои блокировки и, таким образом, позволит продолжить исполнение некоторой другой транзакции. Следовательно, в общем случае любая операция, требующая блокировки, в частности любая операция манипулирования данными языка SQL, может быть отвергнута с отрицательным значением SQLCODE, указывающим, что эта транзакция только что была выбрана жертвой в тупиковой ситуации, и либо уже был произведен ее откат, либо требуется его выполнить. Тупиковые ситуации представляют собой, таким образом, важную проблему, когда речь идет о прикладном программисте, поскольку может потребоваться включить в прикладные программы явные средства, имеющие с ними дело, если они возникают. Например:

ЕХЕС       SQL . . . ;

IF SQLCODE = значение, указывающее ”жертву тупиковой ситуации”

THEN       DO;

ROLLBACK;

повторно инициализировать переменные с помощью

начальных входных данных;

GO TO начало программы;

END;

Здесь предполагается, что программа где-либо сохранила свои начальные входные параметры (не в базе данных! — почему?) для подготовки как раз к таким возможным случаям.



УДАЛЕНИЕ ЕДИНСТВЕННОЙ ЗАПИСИ


Удалить поставщика S1.

DELETE

FROM       S

WHERE    НОМЕР_ПОСТАВЩИКА = 'S1’.

И снова, если таблица

SP в настоящее время содержит какие-либо поставки для поставщика S1, это удаление нарушит непротиворечивость базы данных (сравните с примером 6.2.4; как и в случае предложения UPDATE, нет операций DELETE, воздействующих на несколько таблиц). См. главу 11, а также Приложения А и В.



УДАЛЕНИЕ МНОЖЕСТВА ЗАПИСЕЙ


Удалить всех поставщиков из Лондона.

DELETE

FROM              S ,

WHERE           ГОРОД = 'Лондон';



УДАЛЕНИЕ С ПОДЗАПРОСОМ


Удалить все поставки для поставщиков из Лондона.

delete

FROM       SP

WHERE    'Лондон' =

(SELECT         ГОРОД

FROM              S

WHERE           S. НОМЕР_ПОСТАВЩИКА =

 SP. НОМЕР_ПОСТАВЩИКА);



В чем смысл утверждения, что


1.1. В чем смысл утверждения, что DB2 — реляционная система?
1.2. При условии, что приняты данные из примера на рис. 1.3, найдите результат
каждого из следующих предложений SQL.
а)SELECT                    ФАМИЛИЯ
FROM                               S
WHERE                СОСТОЯНИЕ = 30;
б)    SELECT               НОМЕР_ПОСТАВЩИКА, НОМЕР_ДЕТАЛИ
FROM                   SP
WHERE                КОЛИЧЕСТВО > 200;
в) UPDATE                 SP
SET                       КОЛИЧЕСТВО = КОЛИЧЕСТВО + 300
WHERE                КОЛИЧЕСТВО < 300;
г)    DELETE
FROM                   P
WHERE                ЦВЕТ = 'Голубой'
OR                        ГОРОД = 'Париж';
д)    INSERT
INTO                    SP (НОМЕР_ПОСТАВЩИКА, НОМЕР—ДЕТАЛИ,
КОЛИЧЕСТВО)
VALUES              ('S3', 'Р1’, 500);
1.3. Постройте диаграмму, иллюстрирующую различные категории прикладных программ системы DB2 и различные варианты операционной обстановки, в которых они могут исполняться.
1.4. Что обозначают следующие акронимы:
SQL, DB2, DB2I, QMF, DXT?
1.5. Что такое повторяющаяся группа?
1.6. Определите термины отношение и реляционная база данных.
1.7. Приведите возможное предложение CREATE TABLE для таблицы ВИННЫЙ— ПОГРЕБ (рис. 1.1). Запишите встроенное предложение SQL для программы на языке ПЛ/1, которое обеспечит выборку числа бутылок цинфанделя 1977 г. из этой таблицы.
1.8. Определите термины базовая таблица и представление.

2.1. Укажите четыре основных компонента системы DB2. Начертите диаграмму, показывающую полный процесс подготовки и исполнения программы в DB2.
2.2. Перечислите четыре главных функции генератора планов прикладных задач.
2.3. Дайте определение физической независимости данных.
Объясните, как DB2 обеспечивает такую независимость. Почему желательна физическая независимость данных?


3.1. На рис. 3. 1 приведены некоторые примеры значений данных для базы данных, содержащей информацию, касающуюся поставщиков (таблица S), деталей (таблица Р) и проектируемых изделий (таблица J). Поставщики, детали и изделия уникально идентифицируются при этом соответственно номером поставщика, номером детали и номером изделия. Смысл записей таблицы SPJ состоит в том, что специфицированый поставщик поставляет специфицированную деталь для специфицированного проектируемого изделия в специфицированном количестве. Комбинация НОМЕР_ПОСТАВЩИКА, НОМЕР_ДЕТАЛИ и НОМЕР_ИЗДЕЛИЯ уникально идентифицирует такие записи. Напишите для этой базы данных соответствующее множество предложений CREATE TABLE.
Примечание. Эта база данных будет использоваться в ряде упражнений в последующих главах.
3.2. Запишите множество предложений CREATE INDEX для базы данных из упражнения 3.1 таким образом, чтобы привести в действие требуемые ограничения уникальности.
3.3. В чем состоят основные достоинства индексов? В чем их основные недостатки?
3.4. «Уникальность» поля или комбинации полей — логическое свойство, но оно реализуется в системе DB2 с помощью индекса, который является физической конструкцией. Выскажите Ваше мнение по этому вопросу.


Все последующие упражнения к данной главе основываются на базе данных поставщиков_деталей_изделий (см. упражнения к главе 3). В каждом из них требуется записать предложение SELECT для указанного запроса. Для удобства ниже вновь приводится структура рассматриваемой базы данных:
S(HOMEP_ ПОСТАВЩИКА, ФАМИЛИЯ, СОСТОЯНИЕ, ГОРОД)
Р(НОМЕР_ДЕТАЛИ, НАЗВАНИЕ, ЦВЕТ, ВЕС, ГОРОД)
J (НОМЕР_ИЗДЕЛИЯ, НАЗВАНИЕ, ГОРОД)
SPJ (НОМЕР_ПОСТАВЩИКА, НОМЕР_ДЕТАЛИ, НОМЕР_ИЗДЕЛИЯ КОЛИЧЕСТВО)
Простые запросы
4.1. Выдать полный список деталей для всех изделий.
4.2. Выдать полный список деталей для всех изделий, изготавливаемых в Лондоне.
4.3. Выдать упорядоченный список номеров поставщиков, поставляющих детали для изделия номер J1.
4.4. Выдать список всех поставок, в которых количество деталей находится в диапазоне от 300 до 750 включительно.
4.5. Выдать список всех комбинаций «цвет детали—город, где хранится деталь», исключая дубликаты пар (цвет—город).
4.6. Выдать список всех поставок, в которых количество не является неопределенным значением.
4.7. Выдать номера изделий и города, где они изготавливаются, такие, что второй буквой названия города является «О». (Англоязычные названия городов, используемых в рассматриваемой базе данных — London, Paris, Rome, Athens, Oslo.— Примеч. пер.)
Соединения
4.8. Выдать все триплеты «номер поставщика, номер детали и номер изделия», такие, что образующие каждый из них поставщик, деталь и изделие являются соразмещенными.
4.9. Выдать все триплеты «номер поставщика, номер детали и номер изделия», такие, что образующие каждый из них поставщик, деталь и изделие не являются соразмещенными
4.10. Выдать все триплеты «номер поставщика, номер детали и номер изделия», такие, что в каждом триплете указанные поставщик, деталь и изделие не являются попарно соразмещенными.
4.11. Выдать номера деталей, поставляемых каким-либо поставщиком из Лондона, для изделия, изготавливаемого также в Лондоне.
4.12. Выдать номера деталей, поставляемых каким-либо поставщиком из Лондона.
4.13. Выдать все пары названий городов, таких, что какой-либо поставщик из первого города поставляет детали для некоторого изделия, изготавливаемого во втором городе.
4.14. Выдать номера деталей, поставляемых для какого-либо изделия поставщиком, находящимся в том же городе, где изготавливается это изделие.
4.15. Выдать номера изделий, для которых детали поставляются по крайней мере одним поставщиком не из того же самого города.
4.16. Выдать все пары номеров деталей, таких, что некоторый поставщик поставляет обе указанные детали.


Как и в предыдущей главе. Все следующие упражнения основаны на базе данных поставщиков-деталей-изделий (см. упражнения в главе 3). В каждом из них требуется записать предложение
SELECT для указанного запроса, за исключением упражнений 15—18 и 26. Для удобства повторим здесь структуру рассматриваемой базы данных:
S               (НОМЕР_ПОСТАВЩИКА, ФАМИЛИЯ, СОСТОЯНИЕ, ГОРОД)
Р               (НОМЕР_ДЕТАЛИ, НАЗВАНИЕ, ЦВЕТ, ВЕС, ГОРОД)
J                (НОМЕР_ИЗДЕЛИЯ, НАЗВАНИЕ, ГОРОД)
SPJ            (НОМЕР_ПОСТАВЩИКА, НОМЕР_ДЕТАЛИ, НОМЕР_ИЗДЕЛИЯ,
КОЛИЧЕСТВО)
В каждом разделе упражнения упорядочены приблизительно в порядке возрастания их сложности. Необходимо попытаться выполнить по крайней мере некоторые из легких упражнений в каждой группе. Упражнения 12—18 являются весьма трудными.
Подзапросы
5.1. Выдать названия изделий, для которых поставляются детали поставщиком S1.
5.2. Выдать цвета деталей, поставляемых поставщиком S1.
5.3. Выдать номера деталей, поставляемых для какого-либо изделия в Лондоне.
5.4. Выдать номера изделий, использующих по крайней мере одну деталь, поставляемую поставщиком S1.
5.5. Выдать номера поставщиков, поставляющих по крайней мере одну деталь, поставляемую по крайней мере одним поставщиком, который поставляет по крайней мере одну красную деталь.
5.6. Выдать номера поставщиков, имеющих состояние меньшее, чем у поставщика S1.
5.7. Выдать номера поставщиков, поставляющих детали для какого-либо изделия с деталью Р1 в количестве, большем, чем средний объем поставок детали Р1 для этого изделия. Примечание.
В этом упражнении нужно использовать стандартную функцию AVG.
Квантор EXISTS
5.8. Повторите упражнение 5.3 и используйте в Вашем решении EXISTS.
5.9. Повторите упражнение 5.4 и используйте в Вашем решении EXISTS.
5.10. Выдать номера изделий, для которых не поставляет какой-либо красной детали поставщик из Лондона.
5.11. Выдать номера изделий, для которых детали полностью поставляет поставщик S1.
5.12. Выдать номера деталей, поставляемых для всех изделий в Лондон.


Как обычно, все следующие упражнения основаны на базе данных поставщиков-деталей-изделий:
S               (НОМЕР_ПОСТАВЩИКА, ФАМИЛИЯ, СОСТОЯНИЕ, ГОРОД)
Р               (НОМЕР_ДЕТАЛИ, НАЗВАНИЕ, ЦВЕТ, ВЕС, ГОРОД)
J                (НОМЕР_ИЗДЕЛИЯ, НАЗВАНИЕ, ГОРОД)
SPJ            (НОМЕР_ПОСТАВЩИКА, НОМЕР_ДЕТАЛИ, НОМЕР_ИЗДЕЛИЯ, КОЛИЧЕСТВО)
Запишите подходящее предложение INSERT, DELETE или UPDATE для каждой из следующих задач.
6.1. Измените цвет всех красных деталей на оранжевый.
6.2. Удалите все изделия, для которых нет поставок деталей.
6.3. Увеличьте размер поставки на 10 процентов для всех поставок тех поставщиков, которые поставляют какую-либо красную деталь.
6.4. Удалите все изделия из Рима и все соответствующие поставки.
6.5. Вставьте в таблицу S нового поставщика S10. Его фамилия и город — 'Уайт' и 'Нью-Йорк' соответственно, а состояние еще неизвестно.
6.6. Постройте таблицу, содержащую список номеров деталей, которые поставляются либо каким-нибудь поставщиком из Лондона, либо для какого-либо изделия в Лондоне.
6.7. Постройте таблицу, содержащую список номеров изделий, которые либо находятся в Лондоне, либо для них поставляются детали каким-нибудь поставщиком из Лондона.
6.8. Добавьте 10 к состоянию всех поставщиков, состояние которых в настоящее время меньше, чем состояние поставщика S4.
6.9. Постройте внешнее естественное соединение изделий и поставок по номерам изделий.
6.10. Постройте внешнее естественное соединение деталей и изделий по городам.
6.11. Постройте таблицу, содержащую полную информацию о поставщиках, деталях и изделиях, с указанием объема поставок для каждой поставки вместе с «сохраненной» информацией для каждого поставщика, детали и изделия, которые не входят в таблицу поставок (о смысле понятия «сохраненная информация» в этом контексте см. пример 6.4.5).


7.1. Сделайте набросок элементов каталога для базы данных поставщиков-деталей-изделий.
Напишите теперь предложения SELECT для следующих запросов (упражнения 7 2—7.8).
7.2. В какие таблицы входит столбец ГОРОД?
7.3. Сколько имеется столбцов в таблице поставок?
7.4. Составьте список имен всех таблиц каталога;
7.5. Составьте список фамилий всех пользователей, которыми были созданы таблицы со столбцом ГОРОД, вместе с именами этих таблиц.
7.6. Составьте список фамилий всех пользователей, которыми была создана по крайней мере одна таблица, вместе с числом таблиц, созданных каждым из них.
7.7. Составьте список всех таблиц, для которых имеется по крайней мере один индекс.
7.8. Составьте список имен всех таблиц, для которых имеется более одного индекса.
7.9. Запишите предложения для того, чтобы сделать следующее:
а) Создать подходящий комментарий для таблицы SPJ.
б) Заменить этот комментарий на «Игнорировать предыдущий комментарий».
в) Создать подходящий комментарий для столбца НОМЕР_ДЕТАЛИ в таблице SPJ.
г) Создать подходящий комментарий для индекса XS.
д) Создать подходящий синоним для таблицы SYSCOLUMNS.
е) Уничтожить этот синоним.


8.1. Определите отношение SP из базы данных поставщиков и деталей как представление отношения SPJ из базы данных поставщиков, деталей и изделий.
8.2. Создайте для базы данных поставщиков, деталей и изделий представление. состоящее из всех изделий (включающее только поля номера изделия и города), которые поставляются поставщиком S1 и используют деталь Р1.
8.3. Является ли Ваше решение упражнения 8 2 обновляемым представлением?
а) Если да, то можно ли для него специфицировать вариант CHECKS
б) Если нет, найдите обновляемую версию представления и повторите это упражнение.
8.4. Создайте представление, состоящее из номеров поставщиков и номеров деталей, для таких поставщиков и деталей, которые не «соразмещены».
8.5. Создайте представление, состоящее из записей поставщиков, только для тех поставщиков, которые находятся в Лондоне
8.6. При условии, что задано определение представления:
CREATE   VIEW              СВОДКА (НОМЕР_ПОСТАВЩИКА, НОМЕР_ДЕТАЛИ,
МАКС_КОЛИЧЕСТВО, МИН_КОЛИЧЕСТВО,
СРЕДНЕЕ_КОЛИЧЕСТВО)
AS       SELECT           НОМЕР_ПОСТАВЩИКА, НОМЕР_ДЕТАЛИ, MAX
(КОЛИЧЕСТВО), MIN (КОЛИЧЕСТВО),
AVG (КОЛИЧЕСТВО)
FROM              SPJ
GROUP           BY НОМЕР_ПОСТАВЩИКА, НОМЕР_ДЕТАЛИ
HAVING         SUM (КОЛИЧЕСТВО) > 50;
установите, какие из следующих операций корректны и приведите для них полученный в результате трансляции эквивалент.
а) SELECT            *
FROM              СВОДКА;
б) SELECT           *
FROM              СВОДКА
WHERE           НОМЕР_ПОСТАВЩИКА Ø= ‘S1';
в) SELECT
FROM              СВОДКА
WHERE           МАКС_КОЛИЧЕСТВО > 250;
г) SELECT            МАКС_КОЛИЧЕСТВО - МИН_КОЛИЧЕСТВО,
НОМЕР_ПОСТАВЩИКА, НОМЕР_ДЕТАЛИ
FROM              СВОДКА
WHERE           НОМЕР_ПОСТАВЩИКА ='S1'
AND                НОМЕР_ДЕТАЛИ = 'Р1';
д) SELECT           НОМЕР_ПОСТАВЩИКА
FROM              СВОДКА
GROUP           BY НОМЕР_ПОСТАВЩИКА;
e) SELECT            НОМЕР_ПОСТАВЩИКА, МАКС_КОЛИЧЕСТВО
FROM              СВОДКА
GROUP           BY НОМЕР_ПОСТАВЩИКА, МАКС_КОЛИЧЕСТВО;
ж) SELECT           S.НОМЕР_ПОСТАВЩИКА, СВОДКА. СРЕДНЕЕ_КОЛИЧЕСТВО
FROM              S,CBOДKA
WHERE           S.HOMEP_ПОСТАВЩИКА = СВОДКА. НОМЕР_ПОСТАВЩИКА;
з) UPDATE           СВОДКА
SET                  НОМЕР_ПОСТАВЩИКА = 'S2'
WHERE           НОМЕР_ПОСТАВЩИКА = ‘S1';
и) UPDATE          СВОДКА
SET                  МАКС_КОЛИЧЕСТВО = 1000
WHERE           НОМЕР_ПОСТАВЩИКА = 'S1';
к)DELETE
FROM              СВОДКА
WHERE           НОМЕР_ПОСТАВЩИКА = 'S1';
8.7. Сформулируйте правила, касающиеся обновляемости представлений в системе DB2.
8.8. Сформулируйте правила, касающиеся спецификации CHECK.
8.9. Предположим, что база данных реструктуризуется таким образом, что таблицы А и В заменяются их естественным соединением С. В какой степени механизм представлений может скрыть эту реструктуризацию от существующих пользователей?

1.9. Как Вы понимаете термин "автоматическая навигация”?

УТИЛИТЫ


Это меню дает пользователю возможность вызывать утилиты системы DB2. В состав этих утилит наряду с другими входят следующие:

LOAD. Утилита LOAD загружает данные из набора данных SAM в одну или более таблиц DB2. Примечание.

Такой набор данных SAM может состоять из данных, разгруженных из набора данных VSAM или из базы данных системы IMS, из таблицы DB2 или SQL/DS (см. раздел 15.4).

COPY. Утилита COPY создает полную или инкрементную копию содержимого табличного пространства или сегмента. Инкрементная копия — это копия именно тех данных, которые были изменены с тех пор, когда была создана предыдущая полная или инкрементная копия.

MERGE COPY. Утилита MERGE COPY производит объединение полной копии и одной или более инкрементных копий для заданного табличного пространства или его сегмента с тем, чтобы продуцировать текущую полную копию. Она позволяет также объединять множество инкрементных копий и продуцировать текущую инкрементную копию.

RECOVER. Утилита RECOVER служит для восстановления табличного пространства или его сегмента после разрушения относящейся к ним информации на носителях. При этом используется самая поздняя полная копия, последующие инкрементные копии, а также журнал.

REORG. Утилита REORG осуществляет реорганизацию табличного пространства или его сегмента, в результате которой появляется возможность использовать ранее остававшееся бесполезным пространство. Если это необходимо, осуществляется также восстановление последовательности кластеризации.

RUNSTATS. Утилита RUNSTATS вычисляет различные статистические характеристики, касающиеся таких вещей, как число записей в каждой таблице, и записывает их в системный каталог. Эти характеристики используются генератором планов прикладных задач в осуществляемом им процессе оптимизации.



В.ЗПЕРВИЧНЫЕ И ВНЕШНИЕ КЛЮЧИ


Единственным и самым важным аспектом сущностей в реальном мире является их отличимость.

Следовательно, при рассмотрении проблемы представления сущностей в базе данных нужно ответить на единственный самый важный вопрос, каким образом представители этих сущностей отличаются друг от друга, т. е. каким образом идентифицируются сущности в базе данных.

В последующем, в процедуре проектирования, которая в общих чертах рассматривается в следующем разделе, каждый тип сущностей (поставщики, служащие, поставки, заказы на закупки и т. д.) независимо от того, являются ли они стержневыми, характеристическими или ассоциативными, будет отображаться в базовую таблицу системы DB2. Свойства типа сущностей будут отображаться в поля этой базовой таблицы. Вследствие того что функцию идентификации в реляционной модели выполняют первичные ключи (см. определение этого термина в Приложении А), каждая такая базовая таблица должна иметь первичный ключ, представляющий идентифицирующее свойство рассматриваемого типа сущностей Ниже приведены первичные ключи для базы данных поставщиков и деталей:

— таблица S        : поле S НОМЕР_ПОСТАВЩИКА

— таблица Р        : поле Р. НОМЕР_ДЕТАЛИ

— таблица SP      : составное поле SP.(НОМЕР_ПОСТАВЩИКА, НОМЕР_ДЕТАЛИ)

Таким образом, для каждой базовой таблицы в проекте проектировщик базы данных должен специфицировать поле или комбинацию полей, образующих первичный ключ для этой базовой таблицы. Ниже, в разделе В.5 приводятся некоторые предложения относительно способа записи такой спецификации.

Далее, если сущности представляются базовыми таблицами, то соединения между сущностями представляются с помощью внешних ключей в этих базовых таблицах (определение этого термина см. опять таки в Приложении А). Более строго:

— Если сущности типа В обозначают сущность типа А и если эти типы сущностей представлены базовыми таблицами соответственно ТВ и ТА, то ТВ будет включать внешний ключ, соответствующий первичному ключу ТА.

— Подобным же образом, если сущности типа С являются ассоциациями между сущностями типа А и сущностями типа В, и эти типы сущностей представлены базовыми таблицами соответственно ТС, ТА и ТВ, то ТС будет включать внешний ключ, соответствующий первичному ключу ТА, и внешний ключ, соответствующий первичному ключу ТВ. Примером для этого последнего случая могут служить поставки, где внешними ключами являются SP.НОМЕР_ПОСТАВЩИКА, соответствующий первичному ключу НОМЕР_ПОСТАВЩИКА таблицы S, и SP.НОМЕР_ДЕТАЛИ, соответствующий первичному ключу НОМЕР_ДЕТАЛИ таблицы Р. Рассмотрим теперь пример, иллюстрирующий предыдущий случай. Снова предположим, что служащие обозначают отделы. Тогда таблица служащих (например, СЛУЖАЩИЕ) будет включать внешний ключ (к примеру, СЛУЖАЩИЕ.НОМЕР_ОТДЕЛА), соответствующий первичному ключу (например, НОМЕР_ОТДЕЛА) таблицы отделов (например, ОТДЕЛЫ).


Таким образом, при рассмотрении проблемы выбора способа представления ассоциаций и обозначений в базе данных основной вопрос, на который следует получить ответ: «Каковы внешние ключи?». Но на этом дело не заканчивается. Для каждого внешнего ключа необходимо решить три дальнейших вопроса:

1. Может ли данный внешний ключ принимать неопределенные значения? Иными словами, может ли существовать некоторый экземпляр сущности данного типа, для которого неизвестна целевая сущность, указываемая внешним ключом? В случае поставок это, по всей вероятности, невозможно — поставка, осуществляемая неизвестным поставщиком, или поставка неизвестной детали не имеют смысла. Но в случае со служащими такая ситуация однако могла бы иметь смысл — вполне возможно, что какой-либо служащий в данный момент не зачислен вообще ни в какой отдел. Заметим для ясности, что ответ на рассматриваемый вопрос (допускаются ли неопределенные значения для заданного внешнего ключа) зависит не от прихоти проектировщика базы данных, а от фактического образа действий, принятого в той части реального мира, которая должна быть представлена в рассматриваемой базе данных. Подобные замечания имеют, конечно, отношение и к вопросам 2 и 3, обсуждаемым ниже.

2.       Что должно случиться при попытке удаления целевой сущности, на которую ссылается внешний ключ? Например, может быть предпринята попытка удаления поставщика, для которого существует по крайней мере одна соответствующая поставка. Для определенности рассмотрим этот случай подробнее. Вообще говоря, существуют три возможности:

— CASCADES (КАСКАДИРУЕТСЯ)

Операция удаления «каскадируется» с тем, чтобы удалить также эти соответствующие поставки..

— RESTRICTED (ОГРАНИЧИВАЕТСЯ)

Операция удаления «ограничивается» случаями, где нет таких соответствующих поставок. В противном случае она отвергается

— NULLIFIES (УСТАНАВЛИВАЕТСЯ НЕОПРЕДЕЛЕННОЕ ЗНАЧЕНИЕ)

Для всех таких соответствующих поставок внешний ключ устанавливается в неопределенное значение, а затем этот поставщик удаляется. Такая возможность, конечно, неприменима, если данный внешний ключ не должен принимать неопределенных значений.



3. Что должно происходить при попытке обновления первичного ключа целевой сущности, на которую ссылается некоторый внешний ключ? Например, может быть предпринята попытка обновить номер такого поставщика, для которого имеется по крайней мере одна соответствующая поставка. Этот случай для определенности снова рассмотрим подробнее. Имеются, вообще говоря, те же самые три возможности, как и в случае операции DELETE:

— CASCADES (КАСКАДИРУЕТСЯ)

Операция обновления «каскадируется» с тем, чтобы обновить также и внешний ключ в этих соответствующих поставках.

— RESTRICTED (ОГРАНИЧИВАЕТСЯ)

Операция обновления «ограничивается» случаями, где нет таких соответствующих поставок. В противном случае она отвергается.

— NULLIFIES (УСТАНАВЛИВАЕТСЯ НЕОПРЕДЕЛЕННОЕ ЗНАЧЕНИЕ)

Для всех таких соответствующих поставок внешний ключ устанавливается в неопределенное значение, а затем обновляется этот поставщик. Такая возможность, конечно, неприменима, если данный внешний ключ не может принимать неопределенных значений.

Таким образом, для каждого внешнего ключа в проекте проектировщик базы данных должен специфицировать не только поле или комбинацию полей, составляющие этот внешний ключ, и целевую таблицу, которая идентифицируется этим ключом, но также и ответы на три указанных выше вопроса, т. е. три ограничения, которые относятся к этому внешнему ключу. Некоторые предложения о способе записи таких спецификаций опять-таки можно найти ниже в разделе В.5.

Завершим этот раздел кратким замечанием относительно характеристик. По определению характеристика является обозначающей сущностью, существование которой зависит от типа сущностей, которые она обозначает. Обозначение будет, конечно, представляться внешним ключом в таблице, соответствующей этой характеристике. Но три рассмотренные выше ограничения на внешний ключ для данного случая должны

специфицироваться следующим образом:

NULLS     NOT ALLOWED

DELETE   (цель) CASCADES

UPDATE (первичный ключ целевой сущности) CASCADES

Указанные спецификации представляют зависимость по существованию характеристических сущностей. Здесь использован синтаксис, рассматриваемый ниже в разделе В.5.


с тремя другими подсистемами MVS


Система управления базами данных DB2 сконструирована для совместной работы с тремя другими подсистемами MVS — IMS, CICS и TSO[2]. На рис 1.2 показана эта совокупность программных компонентов.



Рис. 1.2. Варианты операционной обстановки системы DB2

Этот рисунок можно интерпретировать следующим образом:

1. Любое заданное приложение (прикладная задача) DB2, т. е. любая прикладная программа, которая осуществляет доступ к одной или более базам данных DB2, будет исполняться под управлением в точности одной из трех подсистем IMS, CICS или TSO Иначе говоря, в точности одна из трех подсистем будет ответственной за обеспечение определенных необходимых системных услуг (которые обсуждаются в главе 11). Следовательно, можно разделить приложения DB2 на три непересекающиеся категории, а именно—на приложения IMS, CICS и TSO соответственно.

2. Вообще, любое заданное приложение (DB2 или иное) может факультативно использовать средства передачи данных IMS, CICS или TSO, когда они применимы, для связи с одним или более терминалами. Если это имеет место, такое приложение называется интерактивным (работающим в режиме On-line), в противном случае—пакетным (работающим в пакетном режиме). Приложения, исполняемые под IMS или CICS, должны быть интерактивными (см. п. 4 ниже). Приложения DB2, исполняемые под TSO, могут быть либо интерактивными, либо пакетными[3].

3. Приложение DB2, исполняемое под IMS или CICS (но не TSO), может, помимо базы (баз) данных DB2, факультативно осуществлять доступ к одной или более базам данных IMS.

4. Пакетные приложения, исполняемые не под TSO, вообще не могут осуществлять доступа к базам данных DB2, как уже отмечалось выше в п. 2.

5. Приложения TSO вообще не могут осуществлять доступ к базам данных IMS, как уже отмечалось выше в п. 3.

6. Все приложения IMS, CICS и TSO могут исполняться параллельно и даже могут совместно использовать одну и ту же базу данных (одни и те же базы данных) DB2.

Читателей, не знакомых с IMS и/или с CICS и/или с TSO, мы хотим ободрить следующим: для того чтобы понимать возможности DB2, нет необходимости в знакомстве с этими подсистемами. Достаточно понимать, что программа, использующая возможности DB2, должна функционировать под управлением в точности одного из компонентов — IMS, CICS или TSO, а не их совокупности. Заметим, однако, что приложение TSO может исполняться как пакетное приложение TSO в одном случае и как интерактивное приложение TSO — в другом. Предложения ввода/ вывода в программе могут быть связаны с обычными наборами данных в одном случае и с терминалом — в другом, если, конечно, программа записана таким образом, что она готова к любой из этих возможностей.


ВНОРМАЛИЗАЦИЯ


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

Каждая таблица состоит из:

а) первичного ключа, представляющего уникальный идентификатор некоторого конкретного типа сущностей,

а также:

б) нуля или более дополнительных полей, представляющих дополнительные свойства типа сущностей, идентифицируемого данным первичным ключом, а не некоторым другим типом сущностей.

Такой проект является чистым

в том смысле, что каждая таблица содержит информацию об одном и только об одном типе сущностей. Проект такого рода будет легче понимать, легче использовать и, что более важно, легче расширять, когда позднее новая информация будет добавляться к этой базе данных, чем проект, в котором информация о многих типах сущностей перемешана в одной таблице. Иными словами, данный проект будет стабилен и будет хорошей основой для будущего развития.

Другой способ выражения критерия чистоты проекта таков:

«Каждый факт в одном месте».

Каждый факт, например, тот факт, что определенный поставщик имеет определенное состояние, появляется в таком проекте в точности в одном месте. Еще один, очень неформальный, способ выражения того же свойства: «Каждое поле представляет некоторый факт о ключе, полном ключе и ни о чем более, кроме ключа», где «ключ» означает «сущность, идентифицируемую первичным ключом таблицы, которую содержит рассматриваемое поле».

Создание чистых проектов является целью дисциплины, называемой нормализацией. На самом деле, методология, которая рассматривалась до сих пор в данном приложении, и дисциплина нормализации дополняют друг друга в том смысле, что, как Вы сами, вероятно, убедитесь, целесообразно применение их обеих на практике. Однако в литературе нормализация часто обсуждается таким образом, как будто она является единственным необходимым инструментом проектирования. Наше мнение, как уже указывалось, заключается, наоборот, в том, что максимальную пользу из нее можно извлечь как из завершающей проверочной стадии в рамках представленной выше методологии проектирования. Нормализация, несомненно, не панацея от всех бед. По этой причине ей посвящается лишь сравнительно небольшая часть данного приложения. Более полное обсуждение вопросов, связанных с нормализацией, можно найти в публикациях, указанных в библиографии.


Коротко, идея нормализации заключается в следующем. Как указывалось в главе 1, каждая таблица в реляционной базе данных удовлетворяет условию, в соответствии с которым в позиции на пересечении каждой строки и столбца таблицы всегда находится единственное атомарное значение, и никогда не может быть множества таких значений. Любая таблица, удовлетворяющая этому условию, называется нормализованной.

Фактически, ненормализованные таблицы, т. е. таблицы, содержащие повторяющиеся группы, даже не допускаются в реляционной базе данных. Всякая нормализованная таблица автоматически считается таблицей в первой нормальной форме, сокращенно 1НФ. Таким образом, строго говоря, «нормализованная» и «находящаяся в 1НФ» означают одно и то же. Однако на практике термин «нормализованная» часто используется в более узком смысле — «полностью нормализованная», означающем, что в проекте не нарушаются никакие принципы нормализации, обсуждаемые ниже.

Теперь в дополнение к 1НФ можно определить дальнейшие уровни нормализации —вторую нормальную форму (2НФ), третью нормальную форму (3НФ) и т. д. По существу, таблица находится в 2НФ, если она находится в 1НФ и удовлетворяет, кроме того, некоторому дополнительному условию, суть которого не имеет здесь особого значения. Таблица находится в 3НФ, если она находится в 2НФ и, помимо этого, удовлетворяет еще другому дополнительному условию и т. д. Таким образом, каждая нормальная форма является в некотором смысле более ограниченной, чем ей предшествующая. Но важнее то, что каждая нормальная форма является также и более желательной,

чем предшествующая. Это связано с тем, что «(N+1)-я нормальная форма» не обладает некоторыми непривлекательными особенностями, свойственными «N-й нормальной форме». Общий смысл дополнительного условия, налагаемого на (N+l)-ю нормальную форму по отношению к N-й нормальной форме, состоит именно в исключении этих непривлекательных особенностей. Рассмотрим, например, таблицу SPSC, приведенную ниже. Первичным ее ключом является комбинация полей (НОМЕР_ПОСТАВЩИКА, НОМЕР_ДЕТАЛИ). Таблица находится в первой, но не во второй, нормальной форме.



SPSC

НОМЕР_

ПОСТАВЩИКА

НОМЕР_

ДЕТАЛИ

КОЛИЧЕСТВО

ГОРОД

S1

S1

S2

S2

Р1

Р2

Р1

Р2

300

400

200

400

Лондон

Лондон

Париж

Париж

«Непривлекательная особенность» таблицы SPSC очевидна:

поле ГОРОД содержит много избыточной информации. Эта избыточность в свою очередь будет порождать проблемы, связанные с обновлением и непротиворечивостью. Например, для поставщика S1 мог бы указываться город Лондон в одной записи, а город Париж в другой, если не осуществлялись бы соответствующие проверки. Интуитивно представляется, что принято ошибочное решение относительно поля ГОРОД. Лучшим вариантом проекта был бы следующий:

sp

НОМЕР_

ПОСТАВЩИКА

НОМЕР_

ДЕТАЛИ

КОЛИЧЕСТВО

sc

НОМЕР_

ПОСТАВЩИКА

ГОРОД

S1

S1

S2

S2

Р1

Р2

Р1

Р2

300

400

200

400

S1

S2

Лондон

Париж

Эти таблицы находятся в 2НФ, а фактически также в 3НФ, в 4НФ и в 5НФ. Здесь 5НФ — это «окончательная» нормальная форма в очень специфическом смысле, обсуждение которого, к сожалению, не входит в задачу этого приложения.

Общая цель дальнейшей дисциплины нормализации заключается в исключении избыточности информации, как это было сделано в предыдущем примере. Эта дисциплина предусматривает ряд принципов, с помощью которых содержащая избыточную информацию таблица может быть разбита на меньшие таблицы, не содержащие избыточности. Окончательная цель, как уже отмечалось, сводится к получению такого проекта, в котором каждый факт появляется в одном и только в одном месте.

Принципы нормализации обсуждаются здесь лишь весьма кратко. Введем сначала понятие функциональной зависимостиОшибка! Закладка не определена. (ФЗ). Говорят, что поле В таблицы Т функционально зависит от поля А таблицы Т в том и только в том случае, когда в любой заданный момент времени для каждого из различных значений поля Т.А обязательно существует только одно из различных значений поля Т.В. Например, в приведенной выше таблице SPSC поле ГОРОД функционально зависит от поля НОМЕР_ПОСТАВЩИКА, так как для каждого номера поставщика должен существовать в точности один город; если в качестве номера поставщика указывается S1, то каждый раз при этом в поле ГОРОД должно быть задано «Лондон». Отметим, что в этом определении допускается, что поля Т.А и Т.В могут быть составными. Вернемся снова к таблице SPSC. Можно обнаружить, что поле КОЛИЧЕСТВО функционально зависит от составного поля (НОМЕР_ПОСТАВЩИКА, НОМЕР_ДЕТАЛИ). Запишем результаты рассмотрения таблицы SPSC следующим образом:



НОМЕР_ПОСТАВЩИКА                                                            --® ГОРОД

(НОМЕР_ПОСТАВЩИКА, НОМЕР_ДЕТАЛИ)                                    --® КОЛИЧЕСТВО

Мы подошли теперь к критической точке. Если проект базы данных удовлетворяет критерию «каждый факт в одном месте», единственными функциональными зависимостями в любой таблице будут зависимости вида K®F, где К — первичный ключ,, a F — некоторое другое поле.

Заметим, что это следует из определения первичного ключа таблицы, в соответствии с которым K®F всегда имеет место для всех полей данной таблицы. «Один факт в одном месте» говорит о том, что не имеют силы никакие другие функциональные зависимости. Цель дисциплины нормализации состоит именно в том, чтобы избавиться от всех этих «других» ФЗ, т. е. ФЗ, которые имеют иной вид, чем K®F.

Следует рассмотреть, по существу, два случая:

1. Таблица имеет составной первичный ключ вида, скажем, (К1,К2), и включает также поле F, которое функционально зависит от части этого ключа, например от К2, но не от полного ключа. Этот случай был проиллюстрирован выше в примере с таблицей SPSC. В этом случае принципы нормализации рекомендуют сформировать другую таблицу, содержащую К2 и F (первичный ключ— К2), и удалить F из первоначальной таблицы:

Заменить Т (К1, К2, F), первичный ключ (К1, К2), ФЗ К2 --®F       

на             T1 (К1, К2),    первичный ключ (К1, К2),

и               Т2 (К2, F),       первичный ключ К2.

2. Таблица имеет первичный ключ К, поле F1, которое, конечно, функционально зависит от К, и другое ноле F2, которое функционально зависит от F1. Решение здесь, по существу, то же самое, что и прежде — формируется другая таблица, содержащая F1 и F2, с первичным ключом F1, и F2 удаляется из первоначальной таблицы:

Заменить Т (К, F1, F2)    первичный ключ К, ФЗ F1 --®F2

на       T1 (К, F1),                         первичный ключ К

и       Т2 (F1, F2),             первичный ключ F1.

Для любой заданной таблицы, повторяя применение двух рассмотренных правил, почти во всех практических ситуациях можно получить в конечном счете множество таблиц, которые находятся в «окончательной» нормальной форме и, таким образом, не содержат каких-либо функциональных зависимостей вида, отличного от K--®F.



Далее, дисциплина нормализации влечет за собой сведение больших таблиц к меньшим таблицам. Грубо говоря, предполагается, что в качестве входных данных уже имеется некоторое малое число больших таблиц. Манипулирование ими в соответствии с дисциплиной нормализации порождает в качестве результата большое число малых таблиц. Но эта дисциплина ничего не говорит о том, как прежде всего получить эти большие таблицы. Процедура проектирования, рассмотренная в общих чертах ранее в данном приложении, наоборот, имеет дело именно с этой проблемой. Именно поэтому мы утверждаем, что два указанных подхода дополняют друг друга. Таким образом, предлагаемая общая методология проектирования баз данных состоит из:

1. Использования процедур, рассмотренных в разделах B.1 — В.7, для генерации таблиц, представляющих стержневые, ассоциативные и т. д. сущности, а затем

2. Использования процедур, описанных в данном разделе, для проверки того, чтобы в этих таблицах не было неумышленных нарушений каких-либо принципов нормализации.

Завершая данный раздел, приведем два заключительных замечания о нормализации:

— Низшие нормальные формы, например, 2НФ, сами по себе не особенно важны. Они служат, главным образом, средством получения окончательной нормальной формы.

— Весьма маловероятно встретить на практике таблицы, которые находятся в 3НФ, но не в 4НФ или 5НФ, хотя это теоретически и возможно. Поэтому мы слышим, что люди говорят о третьей нормальной форме, а не о четвертой или пятой, как будто бы она является единственной и окончательной целью. На практике это обычно — позволительное упрощение.


ВОЗМОЖНОСТИ ЯВНОГО БЛОКИРОВАНИЯ


Помимо механизма неявного блокирования, описанного в предыдущем разделе, система DB2 обеспечивает некоторые явные возможности, о которых программист должен быть по меньшей мере осведомлен, хотя в большинстве ситуаций будет достаточно неявных возможностей. Средства явного блокирования в некоторой мере неоднородны и состоят из 1) предложения LOCK TABLE (блокировать таблицу) языка SQL, 2) факультативного параметра уровня изоляции в команде BIND и 3) параметра «единица блокирования» табличного пространства.

Предложение LOCK TABLE

Предложение LOCK TABLE языка SQL имеет следующий формат:

LOCK TABLE имя—таблицы IN режим MODE;

где «режим» может специфицироваться как SHARE (совместный) или EXCLUSIVE (монопольный), «имя—таблицы» должно обозначать базовую таблицу, а не представление. Например:

LOCK TABLE SP IN EXCLUSIVE MODE;

Это предложение устанавливает блокировку типа Х для всей базовой таблицы SP в интересах издающей его транзакции. Конечно, эта транзакция, возможно, должна будет ждать до тех пор, пока она сможет установить эту блокировку, если некоторая другая транзакция ранее уже установила блокировку, противоречащую данной. Как только указанная блокировка будет установлена, никакая другая транзакция не сможет обращаться каким-либо образом к любой части этой таблицы до тех пор, пока не будет снята первоначальная блокировка. Эта блокировка не будет снята, пока не завершится данная программа[21]

(а не транзакция).

Если вместо EXCLUSIVE специфицируется SHARE, то данная транзакция будет, конечно, устанавливать блокировку типа S, а не типа X. При этом другие транзакции не смогут установить блокировку типа Х для рассматриваемой таблицы или какой-либо се части до тех пор, пока не будет снята первоначальная блокировка. Однако до этого момента времени они смогут устанавливать блокировку типа S для данной таблицы или некоторой ее части.

Назначение предложения

LOCK TABLE состоит в следующем. Если транзакция обращается к большому числу отдельных записей и поочередно блокирует их, как было описано в предыдущем разделе, то накладные расходы на блокирование для этой транзакции могут быть весьма высокими в отношении как пространства, так и времени—пространства для удержания блокировок к основной памяти, а времени — для их установки. Рассмотрим, например, программу, которая просматривает всю таблицу поставок и печатает ее. Для такой программы, вероятно, лучше установить единственную блокировку на уровне таблицы, как в приведенном выше примере, и таким образом полностью обойтись для этой таблицы без необходимости блокировок на уровне записей. Это делается, конечно, в ущерб параллелизму, однако производительность данной отдельной транзакции будет повышаться и, возможно, в такой степени, что будет также повышаться суммарная производительность системы.


Установление блокировки типа Х на уровне таблицы действительно позволит полностью обойтись без необходимости блокировок на уровне записей для рассматриваемой таблицы, как было только что сказано. Установление же блокировки типа S на уровне таблицы избавит от блокировок типа Х на уровне записей (опять-таки для рассматриваемой таблицы). В самом деле, если программа обновляет какую-либо запись в данной таблице, ей все же потребуется установить блокировку типа Х для этой конкретной записи, благодаря чему параллельные транзакции будут лишены возможности «увидеть» незафиксированное изменение.

Примечание. Хотя операция LOCK TABLE определяется, конечно, как блокирование базовой таблицы, фактически система DB2 блокирует табличное пространство, которое содержит эту таблицу (см. главу 13).

Уровень изоляции

Уровень изоляции — это свойство плана прикладной задачи. Оно специфицируется с помощью параметра команды BIND, которая продуцирует этот план. Имеются два возможных значения этого параметра: RR («повторяемое чтение») и CS («стабильноcть курсора»), причем RR—значение, которое принимается по умолчанию.

Указанные значения параметра имеют следующий смысл:

— «Стабильность курсора» означает, что если использующая этот план транзакция:

а) получает возможность доступа к некоторой конкретной записи путем установки курсора так, чтобы он указывал эту запись, и таким образом

б) устанавливает для этой записи блокировку типа S, а затем

в) отказывается от возможности доступа к этой записи, не обновляя ее, и поэтому

г) не повышает ее блокировку типа S до уровня X, то

д) можно снять эту блокировку типа S, не обязательно дожидаясь следующей точки синхронизации.

— «Повторяемое чтение» означает, что блокировки типа S на уровне записей удерживаются до следующей точки синхронизации подобно блокировкам типа X. Уровень изоляции CS может обеспечить несколько большую степень параллелизма, чем уровень изоляции RR, но вообще это не очень хороший вариант. Именно поэтому по умолчанию принимается значение RR. Проблема, связанная со значением CS, состоит в том, что для транзакции, оперирующей на этом уровне, запись может быть изменена «у нее за спиной», как показано на рис. 11.4, и поэтому такая транзакция может продуцировать неверный ответ. Фактически, если транзакция оперирует на уровне изоляции CS, то теоретически всегда возможно определить вторую транзакцию, которая может исполняться параллельно с первой таким образом, чтобы продуцировать некорректный общий результат. Напротив, транзакция, оперирующая на уровне изоляции RR, может вести себя совершенно так, как если бы она исполнялась в системе с единственным пользователем.



Заметим, что хотя уровень изоляции специфицируется как часть команды BIND, а не как часть программы, программисту все же необходимо быть о нем осведомленным, поскольку от значения этого параметра может зависеть логика программы, иначе говоря, оно может влиять на способ, которым должна кодироваться программа.

Параметр «единица блокирования» табличного пространства

Этот вопрос здесь затрагивается только для полноты рассмотрения. Следующее описание, вероятно, не будет иметь большого смысла до тех пор, пока читатель не изучит главу 13.

Как указывалось в разделе 11.5, механизм неявного блокирования в системе DB2 определяется в терминах блокировок уровня записей. Однако это логическое

определение. Физически DB2 блокирует данные в терминах страниц или табличных пространств. Иначе говоря, когда заданная транзакция логически блокирует некоторую отдельную запись, система DB2 физически блокирует либо страницу, либо табличное пространство, которое содержит эту запись, в зависимости от того, что было специфицировано для этого табличного пространства в запросе, когда оно создавалось.

Для любого заданного табличного пространства может быть специфицирован в качестве «единицы блокирования» один из следующих вариантов: PAGE (страница), TABLESPACE (табличное пространство) или ANY (любой из предшествующих вариантов). При этом:

— ANY (вариант по умолчанию) означает, что DB2 сама будет решать вопрос о подходящей физической единице блокирования для табличного пространства каждого плана, т. е. для одного и того же табличного пространства один план может устанавливать блокировки на уровне страниц, в то время как другой устанавливает их на уровне табличного пространства.

— TABLESPACE означает, что все блокировки, устанавливаемые на данные в этом табличном пространстве, будут осуществляться на уровне табличного пространства.

— PAGE означает, что в заданном табличном пространстве блокировки данных будут всякий раз, когда это возможно, устанавливаться на уровне страниц. Однако иногда DB2 будет все же устанавливать блокировки на уровне табличного пространства. Детальное рассмотрение этого вопроса выходит за рамки данной работы.


ВПРОЦЕДУРА ПРОЕКТИРОВАНИЯ: ПОСЛЕДОВАТЕЛЬНОСТЬ ОСНОВНЫХ ШАГОВ


Теперь мы имеем возможность представить последовательность основных шагов процедуры проектирования.

Примечание. В последующем для краткости вместо «тип сущностей» будем говорить «сущность».

1. Представьте каждый стержень (независимую сущность) как базовую таблицу. Специфицируйте первичный ключ этой базовой таблицы.

2. Представьте каждую ассоциацию (связь вида «многие-ко-многим» или «многие-ко-многим-ко-многим» и т. д. между сущностями) как базовую таблицу. Используйте в этой таблице внешние ключи для идентификации участников ассоциации. Специфицируйте ограничения, связанные с каждым из этих внешних ключей. Специфицируйте первичный ключ этой таблицы, являющийся, вероятно, комбинацией всех внешних ключей, идентифицирующих участников ассоциации.

3. Представьте каждую характеристику (обозначающую сущность, существование которой зависит от соответствующей обозначаемой сущности) как базовую таблицу с внешним ключом, идентифицирующим сущность, описываемую этой характеристикой. Специфицируйте ограничения на внешний ключ, представляющие зависимость по существованию. Специфицируйте первичный ключ этой таблицы — по всей вероятности, комбинацию этого внешнего ключа и свойства, которое гарантирует «уникальность в рамках описываемой сущности».

4. Представьте каждое обозначение (связь вида «многие-к-одной» между двумя сущностями), с которыми мы еще не имели дела в п. 3, как внешний ключ в базовой таблице, представляющей обозначающую сущность. Специфицируйте связанные с каждым таким внешним ключом ограничения.

5. Представьте каждое свойство как поле в базовой таблице, представляющей сущность, которая непосредственно описывается чтим свойством.

6. Используйте для первичных и внешних ключей рецепты, приведенные ниже в разделах В.6 и В.7.

7. Для того чтобы исключить в проекте непреднамеренные нарушения каких-либо принципов нормализации, выполните процедуру, описанную в разделе В.8.

8. Повторяйте перечисленные шаги до тех пор, пока не будет завершена разработка проекта.



ВРАЗЛИЧНЫЕ СОВЕТЫ И РЕКОМЕНДАЦИИ


Завершим это довольно длинное приложение кратким перечнем различных советов и рекомендаций. Недостаток места исключает возможность слишком подробного обсуждения этих вопросов.

Составные ключи

Использование составных (состоящих из нескольких полей) первичных ключей может оказаться весьма неудобным. Если выясняется, что в Вашем проекте имеется таблица с составным первичным ключом, примите во внимание те преимущества, которые обеспечиваются введением нового, несоставного поля, которое могло бы служить первичным ключом вместо первоначально выбранного. Например, можно ввести в таблицу SP поле номера поставки НОМЕР_ПОСТАВКИ.

Подтипы сущностей

Иногда заданная сущность может быть одновременно нескольких типов. Один и тот же человек, например, может быть одновременно служащим, акционером и покупателем. Кроме того, некоторые типы сущностей являются подтипами других типов. Так, все директора являются служащими. Тип сущностей Y называется подтипом типа сущностей X, если каждый экземпляр Y обязательно является экземпляром X. Все свойства, обозначения и т. д., относящиеся к X, относятся также и к Y, но не наоборот. Например, директора имеют зарплату, поскольку зарплату имеют все служащие, но они имеют также и бюджет, которого не имеют служащие, не являющиеся директорами. Такая ситуация может быть удобно представлена следующим образом (снова с помощью псевдоЯОД):

CREATE   TABLE СЛУЖАЩИЕ                         /* служащие (стержневые сущности)*/

PRIMARY KEY (НОМЕР_СЛУЖАЩЕГО)

FIELDS    (НОМЕР_СЛУЖАЩЕГО . . ., ЗАРПЛАТА . . .);

CREATE   TABLE ДИРЕКТОРА             /* директора — подтип типа сущностей

СЛУЖАЩИЕ*/

PRIMARY KEY (НОМЕР_СЛУЖАЩЕГО)

FOREIGN KEY (НОМЕР_СЛУЖАЩЕГО

IDENTIFIES СЛУЖАЩИЕ и т. д.)

FIELDS (НОМЕР_СЛУЖАЩЕГО . .., БЮДЖЕТ . . .);

Одно из достоинств этого проекта по сравнению с вариантом, когда эти две таблицы скомбинированы в одну, состоит в том, что он исключает необходимость в неопределенных значениях, которые потребовались бы в противном случае для представления значений БЮДЖЕТ для служащих, которые не являются директорами.


Домены

Хотя система DB2 не поддерживает понятие домена, оно может быть все же полезно в процессе проектирования и может быть, однако, представлено средствами псевдоЯОД. Например;

CREATE               DOMAIN НОМЕР_СЛУЖАЩЕГО CHAR (5); /*номера

поставщиков */

CREATE               TABLE S

FIELDS                        (НОМЕР_СЛУЖАЩЕГО DOMAIN

(НОМЕР_СЛУЖАЩЕГО), . . .);

CREATE               TABLE SP

FIELDS                        (НОМЕР_СЛУЖАЩЕГО DOMAIN

(НОМЕР_СЛУЖАЩЕГО), . . .);

Рекомендация.

Всегда, когда это возможно, следует давать каждому полю то же самое имя, что и у определяющего домена. Если же такой возможности нет, давайте полю имя этого домена с использованием некоторого уточнителя в качестве префикса, который обеспечивает уникальность полного имени в содержащей его таблице Так, например, можно использовать НОМЕР_ПОСТАВЩИКА, S.HOMEP_ПОСТАВЩИКА или SP.HOMEP_ПOСТАВЩИКА и т. д. в качестве имен полей, содержащих номера поставщиков. Не используйте, например, НОМЕР_ПОСТАВЩИКА в одной таблице, НОМ_ПОСТ — в другой, а НОМЕР_ПОСТ — в третьей и т. д. Одна из причин использования этого правила состоит в том, что оно облегчает жизнь пользователю— нужно запоминать меньше различных имен, допускается меньше произвола. Другая, возможно, более важная причина—это правило позволяет с помощью запроса к каталогу узнать все случаи использования данного домена. Например:

SELECT    NAME, TBNAME

FROM       SYSIBM. SYSCOLUMNS

WHERE    NAME LIKE ' % НОМЕР_ПОСТАВЩИКА';

 

Неопределенные значения

Будьте очень внимательны с неопределенными значениями. В поведении неопределенных значений проявляется много произвола и противоречивости, и они могут быть в этой связи источником многих трудностей.

Например:

— два неопределенных значения считаются дубликатами друг друга в связи со спецификациями DISTINCT, UNIQUE и ORDER BY; это не относится, однако, к WHERE или GROUP BY;

— при наличии неопределенных значений для стандартных функций COUNT, SUM и AVG не гарантируется удовлетворение требования, чтобы среднее было равно сумме, деленной на количество;



— при наличии неопределенных значений не гарантируется, что выражение SUM(Fl) +SUM(F2) будет иметь то же самое значение, что и выражение SUM(F1+F2), где F1 и F2—некоторые поля.

В результате следует очень внимательно подумать, хотите ли Вы вообще допускать неопределенные значения для каких-либо полей. Вполне возможно, что Вашим намерениям будет лучше служить использование некоторого «недопустимого» значения, которое, однако, не является неопределенным, такого, как -1 для поля ОТРАБОТАННЫЕ_ЧАСЫ. Если Вы действительно выберете этот путь, то данные ранее рецепты относительно первичных и внешних ключей потребуют, конечно, некоторого пересмотра. Заметим, однако, что имеются три места, в которых понятие неопределенного значения встраивается в саму структуру языка SQL. А именно, SQL:

— предусматривает

присваивание неопределенного значения для любого поля, добавляемого к таблице с помощью предложения ALTER TABLE

— генерирует

неопределенное значение как результат применения какой-либо функции, например

AVQ, к пустому множеству

— генерирует

неопределенное значение для любого неспецифицированного поля при выполнении предложения INSERT.

Векторы

Представляйте векторы по столбцам, а не по строкам. Например, диаграмму продаж товаров х,у,... за последние годы лучше представить в виде:

ПРОДАЖИ

ТОВАР

МЕСЯЦ

КОЛИЧЕСТВО

х

х

.

х

y

y

.

y

.

Январь

Февраль

.

декабрь

январь

февраль

.

декабрь

.

100

50

.

360

75

144

.

35

.

а не так, как показано ниже:

ПРОДАЖИ

ТОВАР

КОЛИЧ_

ЯНВАРЬ

КОЛИЧ_

ФЕВРАЛЬ

. . .

КОЛИЧ_

ДЕКАБРЬ

x

y

.

100

75

.

50

144

.

 . . .

 . . .

 . . .

360

35

.

Одна из причин такой рекомендации заключается в том, что при этом значительно проще записываются обобщенные (параметризованные) запросы. Рассмотрите, например, как выглядит сравнение сведений из диаграммы продаж для товара i

в месяце m со сведениями для товара j в месяце n, где i, j, m и n — параметры.



Смысловая перегрузка полей

Не перегружайте полей более чем одним смысловым значением. Например, ясно, что поле «размер заказа на закупку» относится только к закупаемым деталям. Но оно могло бы также использоваться для представления «количества-находящихся-в-работе» деталей, производимых на своем предприятии. Однако такой проект порождает сложности в программировании, трудности в понимании системной документации, приводит также к возникновению серьезных проблем, если когда-либо будет решено и производить на своем предприятии и закупать одну и ту же деталь.

Снова нормализация

В заключение еще несколько слов о нормализации.

— Во-первых, принципы нормализации являются только принципами. Нет никаких обязательных требований, чтобы все таблицы были, например, в третьей нормальной форме. Единственное требование состоит в том, чтобы они были по крайней мере в первой нормальной форме. Дисциплина нормализации в некотором смысле оптимизирует производительность обновления за счет производительности выборки — избыточность, которую пытается исключить нормализация, плоха для обновления, но она может быть хороша для выборки данных. Можно высказать это другим образом: «Принципы нормализации рекомендуют руководствоваться критерием «один факт в одном месте»; но иногда есть существенные причины для того, чтобы иметь два факта в одном месте или один факт в двух местах». Поэтому Вы можете иногда сделать выбор в пользу нарушения этих принципов. Но, поступая так, документируйте причины, которыми Вы руководствовались.

— Во-вторых, все наши обсуждения были связаны с базовыми таблицами. Даже если базовые таблицы находятся в 3НФ, нет никакой необходимости, чтобы этому условию удовлетворяли представления, и в действительности они чаще всего и не находятся в 3НФ. Процедура проектирования, которая была настойчиво рекомендована в этом приложении, в большой степени независима от приложений. Мы просто говорили: «Решите, в каких сущностях Вы заинтересованы; решите, какие существуют между ними связи, и т. д.», и при этом полностью игнорировали вопрос, каким образом планируется использовать эту информацию. Впоследствии можно будет в некоторой мере приспособить, реструктуризовать, скорректировать этот независимый от приложений проект с тем, чтобы удовлетворять потребности конкретных приложений с помощью механизма представлений. Однако такая деятельность по приспособлению носит в большой степени вторичный характер. Главная задача состоит прежде всего в том, чтобы получить как раз независимый проект.





ВРЕЦЕПТ, КАСАЮЩИЙСЯ ПЕРВИЧНЫХ КЛЮЧЕЙ


Как уже указывалось, ЯОД системы DB2 не поддерживает понятий первичного и внешнего ключей. Поэтому в этом и следующем разделе представлены некоторые рецепты, с помощью которых можно провести в жизнь свою собственную дисциплину использования первичных и внешних ключей. Прежде всего, о первичных ключах. Для каждого первичного ключа в Вашем проекте:

— Специфицируйте вариант NOT NULL для каждого входящего в него поля (см. раздел 3.2).

— Создайте индекс со спецификацией UNIQUE по комбинации всех входящих в него полей (см. раздел 3.3).

— Обеспечьте существование указанного индекса всякий раз, когда в эту таблицу вставляется какая-либо запись или обновляется первичный ключ какой-либо записи в этой таблице, т. е. создайте данный индекс, прежде чем первоначально будет загружаться таблица, и «никогда» его не уничтожайте.

— Сохраните спецификации PRIMARY KEY, записанные средствами псевдоЯОД, как комментарий в каталоге (см. раздел 7.3).



ВРЕЦЕПТ, КАСАЮЩИЙСЯ ВНЕШНИХ КЛЮЧЕЙ


Для каждого внешнего ключа в Вашем проекте:

— Специфицируйте вариант NOT NULL для каждого поля в этом внешнем ключе тогда и только тогда, когда для этого внешнего ключа применяется вариант NULLS NOT ALLOWED.

— Примите во внимание преимущества создания индекса (вероятно, без спецификации UNIQUE) по комбинации всех полей в данном внешнем ключе. Такой индекс обычно будет желателен по соображениям производительности — Вы сами сможете часто обнаруживать, что выполняются операции соединения по внешнему ключу и соответствующему ему первичному ключу. Однако обсуждение проблем производительности выходит за рамки этого приложения.

— Используйте механизм санкционирования доступа для запрещения в интерактивном режиме всех операций, которые могли бы нарушить ограничения, налагаемые на эти внешние ключи. Под «операциями в интерактивном режиме» здесь понимаются операции SQL, такие, как INSERT или DELETE, которые запрашиваются конечным пользователем с помощью SPUFI или QMF, а не прикладной программой. В частности, запретите в этом режиме:

— — операции DELETE над таблицей, на котирую имеются ссылки

— — операции UPDATE над первичным ключом таблицы, на которую имеются ссылки

— — операции INSERT над таблицей, на которую имеются ссылки

— — операции UPDATE над внешними ключами таблицы, на которую имеются ссылки.

Примите ограничения на внешние ключи в качестве части спецификации требований к программам ведения базы данных. Идеально было бы иметь в точности одну такую программу для каждого внешнего ключа. Это не означает, что одна программа не может иметь дела с многими внешними ключами. Но один внешний ключ не должен вестись многими программами. Используйте механизм санкционирования доступа для предотвращения исполнения всеми другими программами каких-либо операций, которые могли бы нарушить эти ограничения (см. предыдущий абзац).

Сохраните спецификации

FOREIGN KEY, записанные средствами псевдоЯОД, как комментарий в каталоге. Наконец, в качестве независимой (и консервативной) меры:

Напишите служебную программу, которую следует периодически выполнять для обнаружения любых нарушений ограничений и выдачи сообщений о них.



ВРЕГИСТРАЦИЯ ПРОЕКТНЫХ РЕШЕНИЙ: ПСЕВДОЯОД


Когда осуществляется процесс проектирования, необходимо, конечно, регистрировать принимаемые проектные решения, и лучше это делать некоторым более или менее формальным образом. Вопрос состоит в том, какой следует использовать для этого формализм. Есть много возможных ответов на этот вопрос, и ни один из них не является, очевидно, более предпочтительным, чем остальные. Это, до некоторой степени,— исключительно дело вкуса. Однако одним из весомых кандидатов на роль такого формализма являются предложения языка определения данных (предложения ЯОД). В конце концов, такие предложения рано или поздно должны быть сформулированы, когда проект будет трансформироваться в определение базы данных. К сожалению, одни только предложения ЯОД системы DB2 оказываются неадекватными поставленной задаче по той важной причине, что они не поддерживают некоторых понятий, в частности, первичных и внешних ключей, что чрезвычайно критично для процесса проектирования, как мы уже могли убедиться. Поэтому здесь предлагается формализм, который можно было бы назвать «псевдоЯОД». ПсевдоЯОД основан на обычном ЯОД, входящем в SQL, но включает конструкции для непосредственной поддержки необходимых отсутствующих понятий. Рассмотрим, например, тип стержневых сущностей «поставщики». Уже говорилось, что каждый тип стержневых сущностей будет отображаться в базовую таблицу системы DB2. Таким образом, можно было бы написать предложение псевдоЯОД:

CREATE   TABLE S         /* поставщики (стержневые сущности) * /

PRIMARY KEY (НОМЕР_ПОСТАВЩИКА)

FIELDS (НОМЕР_ПОСТАВЩИКА . . . );

для того чтобы зарегистрировать тот факт, что эта базовая таблица, названная S, существует, представляет тип стержневых сущностей «поставщики» и имеет первичный ключ НОМЕР_ПОСТАВЩИКА, который, конечно, является некоторым полем в этой таблице[29]. Позднее мы вернемся к вопросу о добавлении дальнейших спецификаций к этому предложению с тем, чтобы регистрировать другие факты об этом типе сущностей. В идеале все такие предложения псевдоЯОД следовало бы хранить форме текстового файла, и для поддержки этого файла и процессе проектирования использовать текстовой редактор. В конце концов, мы преобразуем эти предложения в подходящее множество подлинных предложений ЯОД системы DB2, которые можно использовать как исходные данные для процесса определения базы данных



Ниже приведен пример предложения псевдоЯОД


Ниже приведен пример предложения псевдоЯОД для поставок, показывающий возможное множество спецификаций внешних ключей:

CREATE   TABLE SP       /*поставки — связывает S и Р*/

PRIMARY KEY          (НОМЕР_ПОСТАВЩИКА, НОМЕР_ДЕТАЛИ)

FOREIGN KEY           (НОМЕР_ПОСТАВЩИКА  IDENTIFIES S

NULLS NOT   ALLOWED

DELETE          OF S.RESTRICTED

UPDATE         OF S. НОМЕР_ПОСТАВЩИКА

CASCADES)

FOREIGN KEY           (НОМЕР_ДЕТАЛИ IDENTIFIES P

NULLS            NOT ALLOWED

DELETE          OF P.RESTRICTED

UPDATE         OF P.НОМЕР_ДЕТАЛИ

RESTRICTED)

FIELDS                        (НОМЕР_ПОСТАВЩИКА . . ., НОМЕР_ДЕТАЛИ . .

., КОЛИЧЕСТВО . . .);

Фразы PRIMARY KEY (первичный ключ) и FOREIGN KEY (внешний ключ) в псевдоЯОД имеют следующий общий синтаксис:

Фраза-PRIMARY-KEY

:: = PRIMARY KEY (первичный—ключ),

где «первичный — ключ» — это либо единственное имя-поля, например НОМЕР_ПОСТАВЩИКА, либо заключенный в круглые скобки список имен-полей, разделенных запятыми, например (НОМЕР_ПОСТАВЩИКА, НОМЕР_ДЕТАЛИ).

Фраза-FOREIGN-KEY

:    : = FOREIGN KEY     (внешний—ключ IDENTIFIES цель

NULLS [NOT] ALLOWED

DELETE OF цель эффект

UPDATE OF первичный — ключ — цели эффект),

где а) «внешний—ключ»—то же самое, что было сказано выше о «первичном-ключе», т. е. либо единственное имя-поля, либо заключенный в круглые скобки список имен-полей, разделенных запятыми; б) «цель» — имя-таблицы; в) «первичный-ключ-цели» специфицирует «первичный-ключ» для «цели» и, наконец, г) «эффект—CASCADES (каскадируется), RESTRICTED (ограничивается) или NULLIFIES (устанавливается неопределенное значение).

Примечание. Фразы PRIMARY KEY и FOREIGN KEY, подобные приведенным выше, были бы в высшей степени желательными расширениями существующего ЯОД системы DB2.


ВСХЕМА КЛАССИФИКАЦИИ СУЩНОСТЕЙ


Будем различать сущности трех основных классов: стержневые, ассоциативные и характеристические. Если говорить кратко, стержневая сущность (или стержень) —это независимая сущность (ей свойственно независимое существование). Ассоциативная сущность (или ассоциация) рассматривается как связь между двумя или более другими сущностями вида "многие-ко-многим" (либо "многие-ко-многим-ко-многим" и т. п.). Наконец, характеристическая сущность (характеристика) представляет собой сущность, единственная цель которой в рамках рассматриваемой предметной области состоит в описании или уточнении некоторой другой сущности.

Примеры:

Стержни — поставщики, детали, служащие, отделы

Ассоциации — поставки

Характеристики — номенклатуры заказов (их единственная цель состоит в том, чтобы описать «старшие» сущности, а именно, заказы на закупки)

Ассоциации и характеристики не являются независимыми, поскольку они предполагают существование некоторой другой сущности или сущностей, которые будут ассоциироваться или «характеризоваться».

Основой приведенной выше классификационной схемы служит тот факт, что связи между сущностями можно естественным образом разделить на две различные категории, а именно: связи вида "многие-ко-многим", которые мы называем ассоциациями, и связи вида "многие-к-одной", которые мы называем обозначениями. Более точно:

— Ассоциация, как

уже пояснялось, это связь вида "многие-ко-многим" (-ко-многим и т. д.) между двумя или более сущностями. Ассоциации рассматриваются как полноправные сущности:

они могут обладать свойствами, могут участвовать в других ассоциациях и т. д. точно так же, как стержневые сущности. Например, поставки, являющиеся ассоциациями, имеют в качестве свойства «количество».

— Обозначение—это связь вида "многие-к-одной" между двумя сущностями. Обычно они не рассматриваются как полноправные сущности, хотя это не привело бы ни к какой ошибке. Вместо этого свойства (и т. д.) обозначения в большинстве случаев считаются свойствами (и т. д.) обозначаемой сущности. Пусть, например, служащие зачисляются в отделы. Свойство «дата зачисления» (дата зачисления служащего в отдел), которое, строго говоря, является свойством обозначения, т. е. связи служащий-отдел, вполне может с равным правом рассматриваться как свойство самого по себе служащего.


Примечание. Связь вида «одна-к-одной» рассматривается просто как специальный случай вида «многие-к-одной». В предлагаемой методологии она не получает какой-либо специальной интерпретации.

Характеристика —

это обозначающая сущность, существование которой зависит от сущности, которую она обозначает. Служащие не являются характеристиками отделов, поскольку служащие имеют независимое существование. Если удаляется отдел, то из этого не следует, что также должны быть удалены служащие этого отдела. В отличие от предыдущего примера номенклатуры заказов являются характеристиками заказов на закупки. Номенклатура заказа не может существовать в отсутствие соответствующего заказа на закупку, и если удаляется заказ на закупку, то также должна быть удалена вся номенклатура этого заказа.

Необходимость в характеристических сущностях возникает в связи с тем, что сущности реального мира имеют иногда многозначные свойства. Предположим, например, что поступают детали нескольких цветов и что имеется в распоряжении деталь Р1 красного, белого и голубого цвета. Поскольку реляционная модель не поддерживает повторяющихся групп, следующий вариант недопустим:

Р

НОМЕР_ДЕТАЛИ

НАЗВАНИЕ

ЦВЕТ

.  .  .

Р1

Гайка



.  .  .

Вместо этого мы должны представить данную ситуацию следующим образом:

Р

НОМЕР_

ДЕТАЛИ

НАЗВАНИЕ

.  .  .

PC

НОМЕР_

ДЕТАЛИ

ЦВЕТ

Р1

Гайка

.  .  .

Р1

Р1

Р1

Красный

Белый

Голубой

Здесь таблица Р представляет тип стержневых сущностей (тип сущностей «деталь»), а таблица PC — тип характеристических сущностей (тип сущностей «цвет деталей»), существование которых зависит от этих стержневых сущностей. Если, например, из таблицы Р удаляется Р1, то из таблицы PC должны быть также удалены все записи, соответствующие Р1.

Поскольку характеристическая сущность представляет собой частный случай сущности, она может, конечно, иметь свойства, может участвовать в ассоциациях, обозначать другие сущности и иметь свои собственные (более низкого уровня) характеристики.

Переопределим, наконец, стрежневую сущность как сущность, которая не является ни ассоциацией, ни характеристикой. Стержневые сущности — это «все то, о чем база данных». Такие сущности имеют независимое существование, хотя они могут все-таки обозначать другие сущности, как, например, служащие обозначают отделы. Любая сущность, независимо от того, является ли она стержневой, характеристической или ассоциативной, может вместе с тем быть обозначаемой.


ВСТАВКА ЕДИНСТВЕННОЙ ЗАПИСИ


Добавить в таблицу Р деталь Р7 (город 'Атенс', вес — 2, название и цвет в настоящее время неизвестны).

Insert

INTO        Р (НОМЕР_ДЕТАЛИ, ГОРОД, BEC)

VALUES  ('Р7', 'Атенс', 2);

Создается новая запись для детали с заданным номером, городом и весом, с неопределенными значениями для названия и цвета. Эти два последних поля не должны быть, конечно, определены как NOT NULL в предложении CREATE TABLE для таблицы Р. Порядок слева — направо, в котором поля указаны в предложении INSERT, не обязательно должен совпадать с порядком слева — направо, в котором поля были специфицированы в предложении CREATE (или ALTER).


Вставить новую поставку с номером поставщика S20, номером детали Р20 и количеством 1000.

INSERT

INTO        SP (НОМЕР—ПОСТАВЩИКА, НОМЕР—ДЕТАЛИ, КОЛИЧЕСТВО)

VALUES ('S20', 'Р20', 1000);

Подобно операциям

UPDATE и DELETE операция INSERT при отсутствии соответствующего управления также может порождать проблему целостности по ссылкам (см. главу 11, а также Приложения А и В). В рассматриваемом случае система DB2 не проверяет, имеется ли поставщик S20 в таблице S и деталь Р20 в таблице Р.



ВСТАВКА ЕДИНСТВЕННОЙ ЗАПИСИ С ОПУЩЕННЫМИ ИМЕНАМИ ПОЛЕЙ


Добавить деталь Р8 в таблицу Р, при этом: название—'Звездочка', цвет — 'Розовый', вес— 14, город — 'Ницца'.

INSERT

INTO        P

VALUES ('Р8', 'Звездочка', 'Розовый', 14, 'Ницца');

Отсутствие списка полей эквивалентно спецификации списка всех полей в таблице в порядке слева — направо, как они были определены в предложении CREATE (или ALTER). Как и «SELECT * », такая краткая нотация может быть удобной для интерактивного SQL. Она потенциально опасна, однако, во встроенном SQL, т. е. в предложениях SQL, используемых в прикладной программе, в связи с тем, что предполагаемый список полей может изменяться, если для программы заново осуществляется связывание, а определение таблицы было в этом промежутке времени изменено.



ВСТАВКА МНОЖЕСТВА ЗАПИСЕЙ


Для каждой поставляемой детали получить ее номер и общий объем поставок, сохранить результат в базе данных (см. пример 5.4.7).

CREATE               TABLE            ВРЕМЕННАЯ

(НОМЕР_ДЕТАЛИ     CHAR (6),

ОБЪЕМ_ПОСТАВКИ INTEGER);

INSERT

INTO        ВРЕМЕННАЯ (НОМЕР_ДЕТАЛИ, ОБЪЕМ_ПОСТАВКИ)

SELECT    НОМЕР_ДЕТАЛИ, SUM (КОЛИЧЕСТВО)

FROM                   SP

GROUP                BY НОМЕР_ДЕТАЛИ;

Здесь предложение

SELECT выполняется точно так же, как обычно, но результат не возвращается пользователю, а копируется в таблицу ВРЕМЕННАЯ. Теперь с этой копией пользователь может делать все, что он пожелает — делать дальнейшие запросы, печатать и даже обновлять ее. Никакая из этих операций не будет оказывать какого-либо влияния на первоначальные данные. В конечном счете таблицу ВРЕМЕННАЯ можно будет уничтожить, когда она больше не будет нужна:

DROP       TABLE            ВРЕМЕННАЯ;

Предыдущий пример очень хорошо показывает, почему свойство замкнутости реляционных систем, обсуждаемое во введении к разделу 4.2, является таким важным. Приведенная полная процедура работает именно в связи с тем, что результатом предложения SELECT является другая таблица. Она не работала бы, если бы результат был чем-либо иным, кроме таблицы.

Между прочим, целевая таблица вовсе не обязательно должна быть первоначально пустой для вставки множества записей, хотя в приведенном примере это так. Если таблица не пуста, новые записи просто добавляются к тем, которые уже имеются.

Одно из важных применений INSERT.. .SELECT — построение так называемого внешнего соединения. Как указывалось в главе 4, обычное (естественное) соединение двух таблиц не включает в результате строк какой-либо из двух таблиц, для которых нет соответствующих строк в другой таблице. Например, обычное соединение таблиц S и Р по городам не включает какой-либо строки для поставщика S5 или для детали РЗ, поскольку в Атенсе не хранится никакая деталь и нет поставщиков, находящихся в Риме (см. пример 4.3.1). Следовательно, в некотором смысле можно считать, что при обычном соединении теряется информация

для таких несоответствующих строк. Однако иногда может потребоваться способность сохранять эту информацию. Рассмотрим следующий пример.



ВСТАВКА ОДНОЙ ЗАПИСИ


Добавить в таблицу Р деталь Р7 со следующими характеристиками: город «Атенс», вес 2, название и цвет в настоящее время неизвестны (пример 6.4.1):

Р

НОМЕР_ДЕТАЛИ

НАЗВАНИЕ

ЦВЕТ

ВЕС

ГОРОД

I.

Р7

2

Атенс

Здесь «I.» аналогично «D.» в предыдущем примере указано под именем таблицы.

В заключение данного раздела следует заметить, что существуют некоторые запросы, которые могут быть сформулированы в SQL, но не выражаются в QBE, по крайней мере с помощью его реализации в QMF. Так, в QBE не предусмотрены какие-либо диалоги следующих конструкций SQL:

– NOT EXISTS

– стандартных функций (SUM, AVG и т. д.)

– GROUP BY и

HAVING.

Эти опущения не имеют столь важного значения: NOT EXISTS и HAVING необходимы лишь для весьма сложных запросов; а результатов, получаемых с помощью GROUP BY и стандартных функций, можно во всяком случае достигнуть более легким образом, используя возможности генерации отчетов QMF.



ВЫБОРКА ПО МНОЖЕСТВУ УСЛОВИЙ


Выдать номера деталей, вес которых находится в диапазоне от 16 до 19 включительно (пример 4.2.7):

Р

НОМЕР_ДЕТАЛИ

НАЗВАНИЕ

ЦВЕТ

ВЕС

ВЕС

ГОРОД

Р.

>= 16

<= 19

Для добавления к пустой таблице второго столбца с именем ВЕС перед тем, как формулировать запрос, используются команды редактирования.



ВЫБОРКА, ПРИ КОТОРОЙ ВОВЛЕКАЕТСЯ NULL (неопределенное значение)


Допустим, например, что значением в столбце СОСТОЯНИЕ для поставщика S5 является не 30, а неопределенное значение. Выдать номера поставщиков, у которых состояние больше, чем 25:

SELECT                НОМЕР_ПОСТАВЩИКА

FROM                   S

WHERE                СОСТОЯНИЕ > 25;

В результате получим:

НОМЕР_ПОСТАВЩИКА

S3

Здесь поставщик S5 не был назван в результате. Если неопределенное значение сравнивается с некоторым другим значением при вычислении предиката, то независимо от используемого оператора сравнения результатом сравнения никогда не является истина, даже если этот другой операнд также является неопределенным значением. Иными словами, если оказывается, что СОСТОЯНИЕ имеет неопределенное значение, то ни одно из следующих сравнений не будет принимать значение истина[12]:

СОСТОЯНИЕ > 25

СОСТОЯНИЕ < = 25

СОСТОЯНИЕ = 25

СОСТОЯНИЕ  Ø= 25

СОСТОЯНИЕ = NULL (Это недопустимая синтаксическая конструкция. См. ниже)

СОСТОЯНИЕ  Ø= NULL (Это — тоже).

Поэтому если издать запрос:

SELECT                НОМЕР_ПОСТАВЩИКА

FROM                   S

WHERE                СОСТОЯНИЕ < = 25;

и сравнить его результат с результатом предыдущего запроса, то можно установить, что поставщик S5 не появляется ни в одном из них. Результат приведенного запроса:

НОМЕР_ПОСТАВЩИКА

S1

S2

S4

Для проверки наличия (или отсутствия) неопределенного значения предусмотрен специальный предикат вида:

имя — столбца IS [NOT] NULL

Например:

SELECT                НОМЕР_ПОСТАВЩИКА

FROM                   S

WHERE                СОСТОЯНИЕ IS NULL;

В результате имеем:

НОМЕР_ПОСТАВЩИКА

S5

Синтаксическая конструкция «СОСТОЯНИЕ = NULL» является некорректной, поскольку ничто — и даже само неопределенное значение — не считается равным неопределенному значению. (Несмотря на это, два неопределенных значения рассматриваются, однако, как дубликаты друг друга при исключении дубликатов. Предложение SELECT DISTINCT (ВЫБРАТЬ РАЗЛИЧНЫЕ) даст в результате не более одного неопределенного значения. Аналогичным образом индекс со спецификацией UNIQUE (уникальный) будет допускать в индексируемом столбце не более одного неопределенного значения. Наконец, при упорядочении ORDER BY (УПОРЯДОЧИТЬ ПО) неопределенные значения интерпретируются, как будто бы они больше или равны всем значениям, не являющимся неопределенными).

Заметим, между прочим, что использование символа NULL во фразе SELECT не допускается. Например, следующая конструкция некорректна:

SELECT НОМЕР_ДЕТАЛИ, 'ВЕС = ', NULL

FROM   P

WHERE ВЕС IS NULL;



ВЫБОРКА С ИСКЛЮЧЕНИЕМ ДУБЛИКАТОВ


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

SELECT DISTINCT     НОМЕР—ДЕТАЛИ

FROM                                      SP;

В этом случае результат таков:

НОМЕР_ДЕТАЛИ

Р1

Р2

РЗ

Р4

Р5

Р6



ВЫБОРКА С ИСПОЛЬЗОВАНИЕМ BETWEEN (между)


Выдать сведения о деталях, вес которых находится в диапазоне от 16 до 19 включительно:

SELECT                НОМЕР_ДЕТАЛИ, НАЗВАНИЕ, ЦВЕТ, ВЕС, ГОРОД

FROM                   P

WHERE                ВЕС BETWEEN 16 AND 19;

Имеем следующий результат:

НОМЕР_ДЕТАЛИ

НАЗВАНИЕ

ЦВЕТ

ВЕС

ГОРОД

Р2

РЗ

Р6

Болт

Винт

Блюм

Зеленый

Голубой

Красный

17

17

19

Париж

Рим

Лондон

Может быть также специфицировано NOT BETWEEN (не принадлежит диапазону между), например:

SELECT                НОМЕР_ДЕТАЛИ, НАЗВАНИЕ. ЦВЕТ, ВЕС, ГОРОД

FROM                   P

WHERE                ВЕС NOT BETWEEN 16 AND 19;

Получаем тогда:

НОМЕР_ДЕТАЛИ

НАЗВАНИЕ

ЦВЕТ

ВЕС

ГОРОД

Р1

Р4

Р5

Гайка

Винт

Кулачок

Красный

Красный

Голубой

12

14

12

Лондон

Лондон

Париж



ВЫБОРКА С ИСПОЛЬЗОВАНИЕМ IN (принадлежит)


Выдать детали, вес которых равен 12, 16 или 17:

SELECT                НОМЕР_ДЕТАЛИ, НАЗВАНИЕ, ЦВЕТ, ВЕС, ГОРОД

FROM                   P

WHERE                ВЕС IN (12, 16, 17);

Результат:

НОМЕР_ДЕТАЛИ

НАЗВАНИЕ

ЦВЕТ

ВЕС

ГОРОД

Р1

Р2

РЗ

Р5

Гайка

Болт

Винт

Кулачок

Красный

Зеленый

Голубой

Голубой

12

17

17

12

Лондон

Париж

Рим

Париж

Предикат IN является в действительности просто краткой записью предиката, представляющего собой последовательность отдельных сравнений, соединенных операторами OR (или). Предыдущее предложение SELECT эквивалентно следующему:

SELECT                НОМЕР_ДЕТАЛИ, НАЗВАНИЕ, ЦВЕТ, ВЕС, ГОРОД

FROM                   P

WHERE                ВЕС = 12

OR                        ВЕС = 16

OR                        ВЕС = 17;

Имеется в распоряжении также предикат NOT IN (не принадлежит), например предложение:

SELECT                НОМЕР_ДЕТАЛИ, НАЗВАНИЕ, ЦВЕТ, ВЕС, ГОРОД

FROM                   P

WHERE                ВЕС NOT IN (12, 16, 17);

дает результат:

НОМЕР_ДЕТАЛИ

НАЗВАНИЕ

ЦВЕТ

ВЕС

ГОРОД

Р4

Р6

Винт

Блюм

Красный

Красный

14

19

Лондон

Лондон

Подобно предикату IN предикат NOT IN может рассматриваться только как сокращенная запись другого предиката, который не использует NOT IN. Упражнение.

Запишите «развернутую форму» предложения из предшествующего примера.



ВЫБОРКА С ИСПОЛЬЗОВАНИЕМ КВАНТОРОВ СУЩЕСТВОВАНИЯ


Выдать фамилии поставщиков, поставляющих деталь Р2 (пример 5.3.1):

S

НОМЕР_

ПОСТАВЩИКА

ФАМИЛИЯ

SP

НОМЕР_

ПОСТАВЩИКА

НОМЕР_

ДЕТАЛИ

_SX

Р.

_SX

Р2

Строка в таблице SP неявным образом квантифицирована квантором существования «существует». Этот запрос можно перефразировать следующим образом: «Показать на экране фамилии поставщиков SX таких, что существует какая-либо поставка детали Р2 поставщиком SX».



ВЫБОРКА С ИСПОЛЬЗОВАНИЕМ ПРЕДИКАТА LIKE (похоже на)


Выдать все детали, названия которых начинаются с буквы «С»:

SELECT                НОМЕР_ДЕТАЛИ, НАЗВАНИЕ, ЦВЕТ, ВЕС, ГОРОД

FROM                   P

WHERE                НАЗВАНИЕ LIKE 'C%';.

Получаем результат (Англоязычные названия деталей с номерами Р5 и Р6 в этом примере — Cam и Cog соответственно.— Примеч. пер.):

НОМЕР_ДЕТАЛИ

НАЗВАНИЕ

ЦВЕТ

ВЕС

ГОРОД

Р5

Р6

Кулачок

Блюм

Голубой

Красный

12

19

Париж

Лондон

Обычно предикат LIKE имеет форму:

имя—столбца  LIKE литерная—строковая—константа, где «имя—столбца» должно обозначать столбец типа CHAR или VARCHAR. Этот предикат принимает для заданной записи значение истина, если значение в указанном столбце соответствует образцу, специфицируемому «литерной—строковой—константой». Литеры этой константы интерпретируются следующим образом:

— Литера «_» (разрыв или подчеркивание) обозначает любую одиночную литеру.

— Литера «%» (процент) обозначает любую последовательность из п литер (где п может быть нулем).

— Все другие литеры обозначают просто сами себя.

Следовательно, в приведенном примере предложение SELECT будет осуществлять выборку записей из таблицы P, для которых значение в столбце НАЗВАНИЕ начинается буквой «С» и содержит любую последовательность из нуля или более литер, следующую за этой буквой «С».

Ниже приведено еще несколько примеров, в которых используется LIKE:

АДРЕС LIKE '% Беркли %'                                 будет принимать значение истина, если АДРЕС содержит где-либо внутри него строку 'Беркли'

НОМЕР_ПОСТАВЩИКА LIKE 'S_ _ '   будет принимать значение истина, если значение в столбце НОМЕР—ПОСТАВЩИКА состоит в точности из трех литер и первая из них литера «S»

НАЗВАНИЕ LIKE '% К_ _ _ '                             будет принимать значение истина, если значение в столбце НАЗВАНИЕ состоит из четырех или более литер и трем последним из них предшествует литера «К»

ГОРОД NOT LIKE ' % Е %'                                будет принимать значение истина, если значение ГОРОД не содержит литеры «Е»



ВЫБОРКА С ИСПОЛЬЗОВАНИЕМ СОЕДИНЕНИЯ


Выдать номера деталей, которые либо весят более 16 фунтов, либо поставляются поставщиком S2, либо удовлетворяют обоим этим условиям (пример 5.5.1):

Р

НОМЕР_

ДЕТАЛИ

ВЕС

SP

НОМЕР_

ПОСТАВЩИКА

НОМЕР_ДЕТАЛИ

_РХ

> 16

S2

_PY

Р.

Р.

_РХ

_PY



ВЫБОРКА С УПОРЯДОЧЕНИЕМ


Выдать номера и состояния поставщиков, находящихся в Париже, в порядке убывания их состояния:

SELECT                НОМЕР_ПОСТАВЩИКА, СОСТОЯНИЕ

FROM                   S

WHERE                ГОРОД = 'Париж'

ORDER                BY СОСТОЯНИЕ DESC;

Результат:

НОМЕР_ПОСТАВЩИКА

СОСТОЯНИЕ

S3

S2

30

10

В общем случае не гарантируется, что результирующая таблица будет упорядочена каким-либо определенным образом. Здесь, однако, пользователь специфицировал, что результат перед тем, как он будет показан, должен быть организован в определенной последовательности. Упорядочение может быть специфицировано таким же образом, как в предложении CREATE INDEX (см. раздел 3.3):

имя—столбца [упорядочение] [,имя—столбца [упорядочение]]..., где «упорядочение», как и ранее, это ASC (возрастание) или DECS (убывание), и по умолчанию принимается ASC. Каждое «имя—столбца» должно идентифицировать некоторый столбец результирующей таблицы. Поэтому, например, следующее предложение недопустимо:

SELECT                НОМЕР_ПОСТАВЩИКА

FROM                   S

ORDER                BY ГОРОД;

Разрешается также идентифицировать столбцы во фразе ORDER BY (упорядочить по) «номерами—столбцов» вместо «имен—столбцов», где «номер—столбца» указывает порядковую позицию (слева направо) данного столбца в результирующей таблице запроса. Благодаря этому возможно упорядочение результата на основе «вычисляемых столбцов», которые не обладают именем. Например, упорядочить результат примера 4.2.3 по возрастанию номера детали в рамках возрастания веса в граммах:

SELECT                НОМЕР_ДЕТАЛИ, ВЕС*454

FROM                   P

ORDER                BY 2, НОМЕР_ДЕТАЛИ; [или ORDER BY 2,1;]

Здесь «2» ссылается на второй столбец результирующей таблицы.

Получаем:

НОМЕР_ДЕТАЛИ

Р1

Р5

Р4

Р2

РЗ

Р6

5448

5448

6356

7718

7718

8626




Выдать номера поставщиков и состояния для поставщиков из Парижа в порядке возрастания номеров поставщиков в рамках убывания состояния. (Расширенный вариант примера 4.2.6.)

Имеем в QBE:

S

НОМЕР_ПОСТАВЩИКА

ФАМИЛИЯ

СОСТОЯНИЕ

ГОРОД

Р. АО(2)

Р. DО(1)

Париж

Здесь «АО.» обозначает «в порядке возрастания», a «DO.» — «и порядке убывания». Целые числа в скобках указывают последовательность «от старшего к младшему» для столбцов упорядочения. В данном примере СОСТОЯНИЕ—старший столбец, а НОМЕР_ПОСТАВЩИКА—младший.



ВЫБОРКА СПЕЦИФИЦИРОВАННЫХ ИЗ СОЕДИНЕНИЯ


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

SELECT                S.НОМЕР_ПОСТАВЩИКА, Р.НОМЕР_ДЕТАЛИ

FROM                               S, P

WHERE                S.ГОРОД = Р.ГОРОД;

Имеем результат:

НОМЕР_ПОСТАВЩИКА

НОМЕР_ДЕТАЛИ

S1

S1

S1

S2

S2

S3

S3

S4

S4

S4

P1

P4

P6

P2

P5

P2

P5

P1

P4

P6



ВЫБОРКА (специфицированных полей из) СОЕДИНЕНИЯ


Выдать все комбинации «номер поставщика/номер детали» такие, что рассматриваемые поставщик и деталь «соразмещены» (пример 4.3.4):

S

НОМЕР_

ПОСТАВЩИКА

ГОРОД

Р

НОМЕР_

ДЕТАЛИ

ГОРОД

_SX

_сх

_РХ

_сх

P.

_SX

_РХ

Пояснение. Для этого запроса нужны три пустых таблицы — по одной для S и Р (показаны только столбцы, имеющие отношение к данному запросу) и одна — для результата. При этом и таблице для результата можно не специфицировать ни имени этой таблицы, ни имен столбцов. Обратите внимание, каким образом специфицированы элементы образца, которые связывают эти три таблицы. Полный запрос может быть перефразирован следующим образом: «Показать на экране пары номер поставщика/номер детали — SX/PX — такие, что SX и РХ размещены в одном и том же городе СХ».



ВЫБОРКА, ТРЕБУЮЩАЯ ИСПОЛЬЗОВАНИЯ СВЯЗКИ OR


Выдать номера поставщиков и состояния для поставщиков, которые либо находятся в Париже, либо имеют состояние более 20, либо удовлетворяют обоим этим условиям (модифицированный вариант примера 4.2.5).

Условия, специфицированные в одной строке, считаются соединенными связкой AND, как иллюстрировалось приведенными до  сих пор примерами. Для того, чтобы два условия были связаны с помощью OR, они должны быть специфицированы в разных строках, как показано ниже:

S

НОМЕР_ПОСТАВЩИКА

ФАМИЛИЯ

СОСТОЯНИЕ

ГОРОД

Р.

Р.

> 20

Париж

Замечание. Если данный поставщик удовлетворяет обоим условиям этого примера, соответствующий номер поставщика будет всеже появляться в результате только один раз.

Другой подход к этому запросу основан на использовании так называемого блока условия.

Блок условия позволяет специфицировать условия любой степени сложности. Например:

S

НОМЕР_ПОСТАВЩИКА

ФАМИЛИЯ

СОСТОЯНИЕ

ГОРОД

Р.

-ST

-SC

УСЛОВИЯ

-SC = Париж OR -ST > 20

Пояснение. Здесь -ST и -SC являются «элементами образца». Фактически они представляют собой переменные,

обозначающие состояние и город соответственно некоторого потенциального целевого поставщика. Блок условия специфицирует предикат, которому должны удовлетворять эти переменные для того, чтобы соответствующий целевой поставщик оказался среди поставщиков, подлежащих выборке. Имя элемента образца может быть произвольным с тем лишь ограничением, что оно должно начинаться с символа подчеркивания.

Другая команда редактирования DRAW COND (нарисовать блок условия) служит для того, чтобы заставить QMF показать на экране пустой блок условия. Условия в блоке условия могут включать AND, OR, NOT, IN (только в форме простого списка значений), LIKE и NULL, совсем как в SQL. (Замечание. IN, LIKE и NULL могут использоваться при заполнении пустой таблицы так же, как и блока условия.) Однако часто легче формулировать запросы без использования блока условия, и в дальнейшем возможность его использования часто будет игнорироваться.



ВЫБОРКА ВЫЧИСЛЯЕМЫХ ЗНАЧЕНИЙ


Выдать номер и вес каждой детали в граммах для всех деталей, предполагая, что в таблице Р веса деталей заданы в фунтах (фунт приблизительно равен 454 грамма — Примеч. пер,)

SELECT                НОМЕР_ДЕТАЛИ, ВЕС *454

FROM                   Р;

Получаем результат:

НОМЕР_ДЕТАЛИ

Р1

Р2

РЗ

Р4

Р5

Рб

5448

7718

7718

6356

5448

8626

Фраза SELECT (и фраза WHERE) может включать арифметические выражения, а также простые имена полей. Можно, кроме того, осуществлять выборку просто констант. Например:

SELECT                НОМЕР_ДЕТАЛИ, 'Вес в граммах = ', ВЕС*454

FROM                   Р;

Получаем результат:

НОМЕР_ДЕТАЛИ

Р1

Р2

РЗ

Р4

Р5

Р6

Вес в граммах =

Вес в граммах =

Вес в граммах =

Вес в граммах =

Вес в граммах =

Вес в граммах =

5448

7718

7718

6356

5448

8626

Заметим, что в этом результате три столбца.

В связи с этим примером возникает следующий вопрос: что произойдет, если вес какой-либо детали имеет неопределенное значение (NULL)? Напомним, что NULL представляет неизвестное значение. Предположим, например, что вес детали Р1 задан в базе данных как неопределенное значение вместо значения 12. Каково тогда значение выражения ВЕС*454 для этой детали? Ответ состоит в том, что оно также является неопределенным значением. В общем случае фактически любое арифметическое выражение считается имеющим неопределенное значение, если какой-либо из его операндов сам имеет неопределенное значение. Иными словами, если оказывается, что вес имеет неопределенное значение, то неопределенное значение имеют и все следующие выражения:

ВЕС+454

ВЕС - 454

ВЕС*454

ВЕС/454

Неопределенные значения показываются на терминале как тире или дефис. Дальнейшее обсуждение неопределенных значений связано с примером в разделе 4.2.10.



ВЫБОРКА ВЫЧИСЛЯЕМЫХ ЗНАЧЕНИЙ И КОНСТАНТ


Выдать для всех деталей номера деталей и вес их в граммах. Вес деталей в таблице Р задан в фунтах (расширенный вариант примера 4.2.3);

Р

НОМЕР_ДЕТАЛИ

ВЕС

Р.

_PW

Р. 'Вес в граммах=’

P._ PW ´ 454



Теперь мы рассмотрели все возможности


Теперь мы рассмотрели все возможности предложения SELECT языка SQL, которые были намерены проиллюстрировать в этой книге. Чтобы завершить эту главу, приведем весьма изощренный пример, который показывает, каким образом многие (но отнюдь не все) эти средства могут быть использованы вместе в едином запросе. Рассмотрим также концептуальный алгоритм обработки SQL — запросов общего вида.

ЗАКЛЮЧИТЕЛЬНЫЕ ЗАМЕЧАНИЯ


В этой главе был представлен краткий обзор объектов среды хранения, поддерживаемых системой DB2. Как уже отмечалось в разделе 13.1, мы не ставили задачи описать в этой книге во всех подробностях соответствующие предложения определения данных. Отметим, однако, следующее.

– Табличное пространство для данной таблицы специфицируется и предложении CREATE TABLE, соответствующем этой таблице.

– База данных для данного табличного пространства специфицируется в предложении CREATE TABLESPACE, соответствующем этому табличному пространству; предполагается, что база данных для заданного индексного пространства—та же, что и для таблицы, над которой определяется этот индекс — индексное пространство должно быть частью той же базы данных, в которую входит соответствующее табличное пространство.

– Детальные аспекты сегментирования (диапазоны страниц и т. п.) табличного пространства специфицируются в предложении CREATE INDEX для требуемого индекса кластеризации. Подробности сегментирования соответствующего индексного пространства специфицируются также в этом предложении CREATE INDEX.

– Группа памяти для данного пространства или сегмента специфицируется в предложении CREATE TABLESPACE или CREATE INDEX, определяющем это пространство или этот сегмент.

– Тома, составляющие данную группу памяти, специфицируются и предложении CREATE, которое создает эту группу памяти.

Помимо всего перечисленного выше, а также указанного в разделе 13.1, DB2 обеспечивает исчерпывающую систему спецификации по умолчанию, которая разработана для того, чтобы облегчить «вхождение в контакт» с системой. Полный механизм умолчаний можно представить следующим образом:

– Предложение CREATE TABLE может специфицировать базу данных, а не табличное пространство. В этом случае DB2 автоматически создает табличное пространство в этой базе данных для новой таблицы. Это табличное пространство будет автоматически уничтожаться при уничтожении данной таблицы. При этом даже нет необходимости специфицировать базу данных. Если не специфицированы ни база данных, ни табличное пространство, DB2 создаст табличное пространство для новой таблицы в базе данных по умолчанию—базе данных, определяемой для таких целей при установке системы.


– Если в предложении CREATE TABLESPACE не специфицируется база данных, то новое табличное пространство будет назначаться в базе данных по умолчанию.

— Группа памяти может быть специфицирована на любом (или на всех) из следующих уровней:

— уровень базы данных (в предложении CREATE DATABASE)

— уровень пространства (в предложениях CREATE TABLESPACE и CREATE INDEX)

— уровень сегмента (в спецификации сегмента в предложениях CREATE INDEX и CREATE TABLESPACE).

Если для заданного сегмента не специфицирована группа памяти на уровне сегмента, то имеется в виду группа памяти, которая относится к пространству, содержащему данный сегмент. Если группа памяти не специфицирована для заданного пространства на уровне пространства, то для этого пространства имеется в виду группа памяти, которая относится к содержащей это пространство базе данных. Если же не специфицирована группа памяти на уровне базы данных для заданной базы данных, то для этой базы данных будет использоваться группа памяти по умолчанию — группа памяти, которая определяется для таких целей при установке системы.

Из всего сказанного выше следует, что приведенные в главе 3 предложения определения данных действительно адекватны потребностям «легкого вхождения в контакт». Однако в большинстве реальных ситуаций на установке потребуется, вероятно, осуществлять более жесткое управление, которое возможно без использования умолчаний. Назначение умолчаний состоит, главным образом, в том, чтобы дать пользователю возможность быстро научиться использованию системы, а не в обеспечении подходящего множества спецификаций для производственной обстановки.

В заключение следует кратко упомянуть о буферных пулах. Буферы в основной памяти группируются в ряд пулов. Заданное пространство может использовать только один такой пул. Буферный пул для заданного пространства специфицируется с помощью еще одного параметра в соответствующем предложении CREATE. Если этот параметр опущен, то, как обычно, предполагается, конечно, спецификация по умолчанию. Таким образом, установка системы может в некоторой степени управлять разделением и близостью данных в основной памяти. Например, можно было бы приписать данное индексное пространство и соответствующее ему табличное пространство к различным буферным пулам, повышая, таким образом, вероятность того, что статьи индекса и записи данных могут одновременно находиться в основной памяти.





ЗАПРОС, ИСПОЛЬЗУЮЩИЙ EXISTS


Выдать фамилии поставщиков, которые поставляют деталь P2 (та же самая задача, что и в примерах 5.2.1 и 5.2.3).

SELECT                ФАМИЛИЯ

FROM                   S

WHERE                EXISTS

(SELECT *

FROM              SP

WHERE           НОМЕР_ПОСТАВЩИКА=

S.НОМЕР_ПОСТАВЩИКА

AND                НОМЕР_ДЕТАЛИ = 'P2');

Пояснение. EXISTS (существует) представляет здесь квантор существования — понятие, заимствованное из формальной логики. Пусть символ «х» обозначает некоторую произвольную переменную. Тогда в логике предикат с навешенным квантором существования EXISTS х (предикат—зависящий—от—х) принимает значение истина

тогда и только тогда, когда «предикат—зависящий—от—х» имеет значение истина при каком-либо значении переменной х. Предположим, например, что переменная х обозначает любое целое число в диапазоне от 1 до 10. Тогда предикат

EXISTS х (х < 5)

принимает значение истина. Напротив, предикат

EXISTS х (х < 0)

принимает значение ложь.

В языке SQL предикат с квантором существования представляется выражением вида

EXISTS (SELECT * FROM. . .).

Такое выражение считается истинным тогда и только тогда, когда результат вычисления подзапроса, представленного с помощью «SELECT* FROM.. .», является непустым множеством, иными словами, тогда и только тогда, когда существует какая-либо запись в таблице, указанной во фразе FROM подзапроса, которая удовлетворяет условию WHERE этого подзапроса. (На практике этот подзапрос всегда будет коррелированным множеством.)

Вернемся к приведенному выше примеру. Поочередно рассматриваем каждое значение столбца ФАМИЛИЯ и проверяем, является ли для него истинным условие существования. Предположим, что первое значение поля ФАМИЛИЯ — 'Смит'. Тогда соответствующее значение поля НОМЕР_ПОСТАВЩИКА—S1. Является ли пустым множество записей из SP, содержащих НОМЕР_ПОСТАВЩИКА, равный S1, и НОМЕР_ДЕТАЛИ, равный Р2? Если ответ отрицателен, то существует запись в SP с НОМЕРОМ_ПОСТАВЩИКА, равным S1, и номером детали, равным Р2, и, следовательно, 'Смит' должно быть одним из результирующих значений. Аналогично поступаем для каждого из других значений столбца ФАМИЛИЯ.

Хотя этот первый пример только показывает иной способ формулировки запроса для задачи, с которой мы уже умеем справляться в языке SQL (используя либо соединение, либо оператор IN), EXISTS представляет собой одну из наиболее важных возможностей полного языка SQL. Фактически любой запрос, который может быть выражен с использованием IN, может быть альтернативным образом сформулирован также с помощью EXISTS. Однако обратное высказывание несправедливо (см., например, п. 5.3.3 ниже).



ЗАПРОС, ИСПОЛЬЗУЮЩИЙ NOT EXISTS


Выдать фамилии поставщиков, которые не поставляют деталь Р2 (обратная задача по отношению к примеру 5.3.1).

SELECT                ФАМИЛИЯ

FROM                   S

WHERE                NOT EXIST

(SELECT         *

FROM              SP

WHERE           НОМЕР_ПОСТАВЩИКА=

S.НОМЕР_ПОСТАВЩИКА

AND                НОМЕР_ДЕТАЛИ = 'Р2');

Результат:

фамилия

    Адамc

Этот запрос можно перефразировать: «Выбрать фамилии поставщиков таких, что не существует поставки, связывающей их с деталью Р2». Заметим, что легко преобразовать решение предыдущей задачи (пример 5.3.1) в решение данной.

Между прочим, заключенный в скобки подзапрос, входящий в выражение EXISTS, вовсе не обязательно должен использовать предложение SELECT вида «SELECT *». Можно использовать, например, предложение следующего вида: «SELECT имя-поля FROM...». Однако на практике оно почти всегда будет иметь вид «SELECT *», как уже было продемонстрировано в наших примерах.



ЗАПРОС, ТРЕБУЮЩИЙ ИСПОЛЬЗОВАНИЯ UNION


Выдать номера деталей, которые имеют вес более 16 фунтов либо поставляются поставщиком S2 (либо то и другое).

SELECT                НОМЕР_ДЕТАЛИ

FROM                   P

WHERE                BEC>16

UNION

SELECT                НОМЕР_ДЕТАЛИ

FROM                   SP

WHERE                НОМЕР_ПОСТАВЩИКА ='S2';

Результат:

P1

P2

P3

P6

Из этого простого примера следует несколько соображений:

—Избыточные дубликаты всегда исключаются, из результата UNION. Поэтому, хотя в рассматриваемом примере деталь P2 выбирается обеими из двух составляющих предложений SELECT, в окончательном результате она появляется только один раз.

—Любое число предложений SELECT может быть соединено операторами UNION. Можно расширить данный пример с тем, чтобы включить номера красных деталей, дополнив приведенный выше запрос следующей конструкцией:

UNION

SELECT                НОМЕР_ДЕТАЛИ

FROM                   P

WHERE                ЦВЕТ = 'Красный'

перед заключительной точкой с запятой. Заметим, что такого же результата можно было достигнуть, добавляя к первому из первоначальных предложений

SELECT фразу OR ЦBET= ='Красный'.

—Любая фраза ORDER BY в запросе должна входить как часть только в последнее предложение SELECT и должна указывать столбцы, по которым осуществляется упорядочение, путем указания их порядковых позиций, т. е. их номеров.

—В связи с оператором

UNION часто оказывается полезной возможность включения констант во фразу SELECT. Например, можно указать, какому из двух условий WHERE удовлетворяет каждая из отдельных деталей:

SELECT                НОМЕР_ДЕТАЛИ, 'ее вес > 16 фунтов'

FROM                   P

WHERE                ВЕС > 16

UNION

SELECT                НОМЕР_ДЕТАЛИ, 'деталь поставляется S2'

FROM                   SP

WHERE                НОМЕР_ПОСТАВЩИКА = 'S3'

ORDER                BY 2, 1;

Результат:

PI

Р2

Р2

РЗ

Р6

деталь поставляется S2

деталь поставляется S2

ее вес > 16 фунтов

ее вес > 16 фунтов

ее вес > 16 фунтов


Когда строковая константа выступает в качестве элемента, подлежащего выборке, считается, что она имеет тип VARCHAR и длину, равную числу литер в константе, и допускаются неопределенные значения.

У читателя может возникнуть желание узнать, поддерживаются ли в языке SQL какие-либо аналоги операторов INTERSECTION (пересечение) и DIFFERENCE (разность), поскольку объединение, пересечение и разность в теоретико-множественных рассмотрениях обычно выступают совместно. Пересечение двух множеств представляет собой множество всех элементов, принадлежащих обоим исходным множествам. Разность двух множеств — это множество элементов, принадлежащих первому исходному множеству, но не принадлежащих второму. В языке SQL эти два оператора непосредственно не поддерживаются, но каждый из них может быть смоделирован с помощью функции EXISTS. Пусть, например, А и В—таблицы, состоящие из единственного столбца, а именно, столбца номеров поставщиков. Пусть А представляет «поставщиков из Лондона», а В — «поставщиков, которые поставляют деталь Р1». Тогда

SELECT                НОМЕР_ПОСТАВЩИКА

FROM                   A

WHERE                EXISTS

(SELECT         НОМЕР_ПОСТАВЩИКА

FROM              В

WHERE           В. НОМЕР_ПОСТАВЩИКА=

А. НОМЕР_ПОСТАВЩИКА);

представляет пересечение А и В, т. е. поставщиков из Лондона, которые поставляют деталь P1, a

SELECT                НОМЕР_ПОСТАВЩИКА

FROM                   A

WHERE                NOT EXISTS

(SELECT         НОМЕР_ПОСТАВЩИКА

FROM              В

WHERE           В.НОМЕР_ПОСТАВЩИКА=

А. НОМЕР_ПОСТАВЩИКА);

представляет разность между А и В (в указанном порядке), т. е. поставщиков из Лондона, которые не поставляют деталь Р1. Упражнение.

Что представляет собой разность между В и А (именно в этом порядке)?


ЗАПРОС, В КОТОРОМ ИСПОЛЬЗУЕТСЯ ИМПЛИКАЦИЯ


Выдать номера поставщиков, поставляющих по крайней мере все те детали, которые поставляются поставщиком S2 (тот же самый запрос, что и в предыдущем примере).

В этом примере иллюстрируется еще одно очень полезное понятие — логическая импликация.

Первоначальную задачу можно перефразировать следующим образом: «Выдать номера поставщиков, скажем, Sx, таких, что ДЛЯ ВСЕХ деталей Ру, если поставщик S2 поставляет деталь Ру, то поставщик Sx поставляет деталь Ру».

Выражение

IF p THENq          (ЕСЛИ р ТО q),

где р и q — предикаты, является предикатом логической импликации. Он  определяется как эквивалент предиката:

NOT (p) OR q.

Иными словами, импликация «IF p THEN q» (читается также следующим образом: «из р СЛЕДУЕТ q») принимает значение ложь

тогда и только тогда, когда q — ложь,

а р — истина, как показывает приведенная ниже таблица истинности (В таблице Т обозначает «истина» (от англ.  true), a F-

«ложь» (от англ.false) .— Примеч. пер.)

Р

q

IF p THEN q

Т

Т

Т

Т

F

F

F

Т

Т

F

F

Т

Многие формулировки задач на обычном языке весьма естественным образом выражаются в терминах логической импликации. Несколько примеров можно найти в конце данной главы среди предлагаемых упражнений. Язык SQL непосредственно не поддерживает импликацию. Но предыдущее определение показывает, каким образом любой содержащий импликацию предикат может быть трансформирован в другой предикат, который ее не содержит. Пусть, например, р представляет собой предикат «Поставщик S2 поставляет деталь Ру», а q — предикат «Поставщик Sx поставляет деталь Ру». Тогда предикат

IF p THEN q

эквивалентен предикату

NOT (поставщик S2 поставляет деталь Ру)

OR  (поставщик Sx поставляет деталь Ру);

или в языке SQL:

NOT         EXISTS

(SELECT         *

FROM              SP SPY

WHERE           SPY. НОМЕР_ПОСТАВЩИКА = 'S2')

OR            EXISTS

(SELECT         *

FROM              SP SPZ

WHERE           SPZ. НОМЕР_ПОСТАВЩИКА = Sx

AND                SPZ. НОМЕР_ДЕТАЛИ = SPY. НОМЕР_ДЕТАЛИ)


Следовательно, предикат

FORALL Py (IF p THEN q),

который эквивалентен предикату

NOT EXISTS Py (NOT (IF p THEN q)),

т. е. предикату

NOT EXISTS Py (NOT (NOT (p) OR q)),

может быть записан, таким образом, в виде:

NOT EXISTS Py (p AND NOT (q)),

или в языке SQL:

NOT    EXISTS

(SELECT         *

FROM              SP  SPY

WHERE           НОМЕР_ПОСТАВЩИКА = 'S2'

AND                NOT EXISTS

(SELECT         *

FROM              SP SPZ

WHERE           SPZ.НОМЕР_ПОСТАВЩИКА=Sx

AND                SPZ.НОМЕР_ДЕТАЛИ=.SPY.НОМЕР_

ДЕТАЛИ))

Поэтому полный запрос принимает вид:

SELECT                DISTINCT НОМЕР_ПОСТАВЩИКА

FROM                   SP SPX

WHERE                NOT EXISTS

(SELECT         *

FROM              SP SPY

WHERE SPY.НОМЕР_ПОСТАВЩИКА = 'S2'

AND    NOT EXISTS

(SELECT         *

FROM              SP SPZ

WHERE SPZ.НОМЕР_ПОСТАВЩИКА =

 SPX. НОМЕР_ПОСТАВЩИКА

AND                 SPZ. НОМЕР_ДЕТАЛИ =

 SPY. НОМЕР_ДЕТАЛИ));

Такой же вид имеет запрос в примере 5.3.4. Таким образом, понятие импликации обеспечивает основу для систематического подхода к определенному классу (весьма сложных) запросов и их преобразованию в эквивалентную форму в языке SQL. Попрактиковаться в таком подходе позволяют упражнения 5.12—5.18 в конце данной главы.


ЗАПРОСЫ, ИСПОЛЬЗУЮЩИЕ СОЕДИНЕНИЕ


Способность «соединять» две или более таблицы в одну представляет собой одну из наиболее мощных возможностей реляционных систем. Фактически наличие операции соединения (join) — едва ли не самое главное, что отличает реляционные системы от систем других типов (см. Приложение А). Итак, что такое соединение? Говоря нестрого, это запрос, в котором выборка данных осуществляется более чем из одной таблицы. Ниже приводится простой пример.



ЗАПРОСЫ ПО КАТАЛОГУ


Поскольку каталог состоит из таблиц, точно таких же, как обычные пользовательские таблицы, из него можно запрашивать данные с помощью предложений SELECT языка SQL так же, как из обычных таблиц. Например, чтобы узнать, какие таблицы содержат столбец НОМЕР-ПОСТАВЩИКА, можно использовать следующий запрос:

SELECT    TBNAME

FROM       SYSIBM.SYSCOLUMNS

WHERE    NAME = 'НОМЕР_ПОСТАВЩИКА';

Результат:

TBNAME

    S

    SP

«Создателем» таблиц каталога считается SYSIBM. Поэтому для того, чтобы обратиться к таблице каталога, например SYSCOLUMNS, необходимо использовать SYSIBM в качестве префикса для имени таблицы, как во фразе FROM рассмотренного примера. В противном случае система DB2 будет предполагать, что Вы обращаетесь к Вашей собственной таблице, т. е. префиксом по умолчанию является Ваше собственное имя, известное системе, как пояснялось в главе 3.

Другой пример. Из каких столбцов состоит таблица S?

SELECT    NAME

FROM       SYSIBM. SYSCOLUMNS

WHERE    TBNAME == 'S';

Результат:

NAME

НОМЕР_ПОСТАВЩИКА

ФАМИЛИЯ

СОСТОЯНИЕ

ГОРОД

И еще один пример. Сколько таблиц создал пользователь КДДЕЙТ?

SELECT    COUNT(*)

FROM       SYSIBM.SYSTABLES

WHERE    CREATOR = 'КДДЕЙТ';

Пользователь, незнакомый со структурой базы данных, может с помощью подобного рода запросов получить информацию об этой структуре. Например, пользователь, которому требуется сформулировать запросы к базе данных, скажем, поставщиков и деталей, но который не располагает какими-либо подробными знаниями относительно того, какие в точности таблицы существуют в этой базе данных и из каких именно столбцов они состоят, может воспользоваться запросами к каталогу и сначала получить нужные знания, а затем перейти к .формулировке собственно запроса на данные. В традиционной (нереляционной) системе такие первоначальные запросы обычно должны были бы направляться к системному словарю данных, а не к базе данных (На самом деле, представление каталога (метаданных) базы данных как части самой базы данных, доступной не только СУБД, но и пользователю с помощью обычных средств манипулирования данными, не является прерогативой реляционных систем. Такой подход может быть реализован в СУБД, основанных и на других моделях данных. Обсуждение этого вопроса можно найти в работе: Когаловский М. Р., Виноградов М. М., Макальский К. И. Самоописываемые базы данных и реализация СУБД//Математические и реализационные проблемы СУБД.—М.: ЦЭМИ АН СССР, 1981—С. 31—53— Примеч. пер.) В действительности, каталог системы DB2 может рассматриваться как рудиментарный словарь — рудиментарный в том смысле, что он содержит только информацию, которая непосредственно необходима DB2, тогда как полноценный словарь данных обычно содержит много дополнительной информации, например о том, какие отчеты получают различные отделы. Важное отличие и существенное, с точки зрения легкости использования, достоинство системы DB2 заключаются в том, что запросы к каталогу и к базе данных осуществляются через один и тот же интерфейс, а именно—SQL. Напротив, в традиционных системах словарь и база данных всегда различались, и доступ к ним осуществлялся через различные интерфейсы. Интересно подумать о том, можно ли будет когда-либо расширить каталог системы DB2 с тем, чтобы он мог обеспечивать функции развитого словаря (такое расширение должно быть достаточно простым для реализации).