Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lab7.doc
Скачиваний:
1
Добавлен:
01.04.2025
Размер:
265.22 Кб
Скачать

7. Встроенные функции и подзапросы

Встроенные функции могут использоваться только во фразе SELECT или в команде HAVING. Однако фраза SELECT, содержащая встроенную функ­цию, может быть частью подзапроса. Рассмотрим пример такого подзапроса:

Запрос: У кого из работников почасовая ставка выше среднего?

SELECT WORKER_NAME

FROM WORKER

WHERE HRLY_RATE >

(SELECT AVG(HRLY_RATE)

FROM WORKER)

Результат:

NAME

К. Немо

П.Мэйсон

Х. Колумб

Обратите внимание, что подзапрос не коррелирует с главным запросом. Подзапрос выдает ровно одно значение - среднюю почасовую ставку. Глав­ный запрос выбирает работника только в том случае, если его ставка больше вычисленной средней.

В коррелированных запросах также могут использоваться встроенные функции:

Запрос: У кого из работников почасовая ставка выше средней почасовой ставки среди подчиненных того же менеджера?

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

SELECT A. WORKER_NAME

FROM WORKER A

WHERE A.HRLY_RATE >

(SELECT AVG(B.HRLY_RATE)

FROM WORKER В

WHERE B.SUPV_ID = A.SUPV_ID)

Результат:

A.WORKER NAME

К.Немо

П.Мэйсон

X.Колумб

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

8. Операции реляционной алгебры

Как отмечалось ранее и как вы, вероятно, заметили, SQL напоминает реляционное исчисление наличием целевого списка (фраза SELECT) и опре­деляющего выражения (фраза WHERE). В SQL2, однако, реализованы не­которые операции реляционной алгебры, которые мы сейчас обсудим. В ча­стности, объединение, пересечение, разность и соединение реализованы в явном виде как операторы SQL. Мы рассмотрим их по очереди.

Операторы UNION (объединение), INTERSECT (пересечение) и EXCEPT (разность). Как и в реляционной алгебре, операторы объединения, пересечения и разности применяются к двум таблицам, которые должны быть объединительно-совместимы. Этот термин в SQL имеет несколько от­личающееся значение. Две таблицы объединительно-совместимы, если в них одинаковое число столбцов и соответствующие столбцы имеют совместимые типы данных, то есть такие типы, которые могут быть легко преобразованы друг в друга. Например, два числовых типа не обязательно должны совпа­дать, но они должны преобразовываться друг в друга.

Объединительно-совместимые таблицы. Две или более таблицы, имеющие эквивалентные (по количеству и областям) наборы столбцов.

При обсуждении объединения, пересечения и разности мы воспользу­емся следующим примером (рис. 3).

Рис. 3. Две реляционные таблицы с информацией о торговых агентах

UNION. Предположим, что мы хотим получить одну таблицу, содержа­щую информацию обо всех торговых агентах. Воспользуемся SQL-выражением

(SELECT * FROM SP_SUBORD)

UNION

(SELECT * FROM SP_MGR)

или в другом виде

SELECT *

FROM (TABLE SP_SUBORD UNION TABLE SP_MGR)

Результат представлен на рис. 4. Как и в реляционной алгебре, объе­динением двух реляционных таблиц будет реляционная таблица, содержа­щая каждую строку, лежащую хотя бы в одной из двух таблиц.

Рис. 4. Объединение таблиц SP_SUBORD и SP_MGR

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

(SELECT * FROM SP_SUBORD)

UNION ALL

(SELECT * FROM SP_MGR)

или формой

SELECT *

FROM (TABLE SP_SUBORD UNION ALL TABLE SP_MGR)

то тогда те строки, которые входят в обе таблицы, будут повторяться в объединении дважды.

UNION. Операция, создающая теоретико-множественное объединение двух таблиц.

INTERSECT. Предположим, что мы хотим идентифицировать тех торго­вых агентов, которые одновременно подчиняются кому-либо и сами явля­ются менеджерами. Другими словами, нам нужно пересечь две таблицы, чтобы найти строки, лежащие в них обеих. Мы воспользуемся SQL-выражением

INTERSECT. Операция, создающая теоретико-множественное пересечение двух таблиц.

(SELECT * FROM SP_SUBORD) INTERSECT

(SELECT * FROM SP_MGR)

или в другой форме

SELECT *

FROM (TABLE SP_SUBORD INTERSECT TABLE SP_MGR)

Результат представлен на рис. 5.

Рис. 5. Пересечение таблиц SP_SUBORD и SP_MGR

Как и в случае объединения, ни одна строка не появляется в пересече­нии более одного раза. Однако, если в одной таблице имеется m копий строки, а в другой таблице имеется n копий строки, и m<n, то пересечение будет содержать m копий этой строки, если мы воспользуемся таким син­таксисом:

(SELECT * FROM SP_SUBORD)

INTERSECT ALL

(SELECT * FROM SP_MGR)

Как и в случае объединения, ключевое слово ALL означает, что повторы строк нужно рассматривать как отдельные строки.

EXCEPT. Предположим, что мы хотим найти всех торговых агентов, ко­торые никому не подчиняются. Мы хотим вычесть таблицу SP_SUBORD из таблицы SP_MGR. В SQL-92 разность множеств поддерживается оператором EXCEPT. В нашем примере мы воспользуемся выражением

EXCEPT. Операция, создающая теоретико-множественную разность двух таблиц.

(SELECT * FROM SP_SUBORD)

EXCEPT

(SELECT * FROM SP_MGR)

или в другой форме

SELECT *

FROM (TABLE SP_SUBORD EXCEPT TABLE SP_MGR)

Результат представлен на рис. 6.

Рис. 6. Результат операции SP_MGR - SP_SUBORD

Если мы воспользуемся синтаксисом

(SELECT * FROM SP_SUBORD)

EXCEPT ALL

(SELECT * FROM SP_MGR)

в случае, когда в таблице SP_MGR имеется m копий строки, а в таблице SP_SUBORD имеется n копий строки, где m > n, то в результирующей таблице будет m-n копий этой строки. Если же m <= n, то в результирующей таблице не будет ни одной копии этой строки.

Теперь, когда мы дали общее представление об операторах SQL UNION, INTERSECT и EXCEPT, мы хотим взглянуть на них более пристально. Огра­ничение, накладываемое на таблицу, к которой применяются операторы объединительной совместимости, кажется слишком сильным. В конце кон­цов, как часто мы имеем дело с таблицами, у которых в точности одинако­вые столбцы? Рассмотрим слегка модифицированный синтаксис операторов и примеры, в которых ограничение не соблюдается. Рассмотрим такой запрос:

Запрос: Кто из штукатуров начинает работу 9 октября?

(SELECT * FROM WORKER

WHERE SKILL_TYPE = 'Штукатур')

INTERSECT CORRESPONDING BY (WORKER_ID)

(SELECT * FROM ASSIGNMENT

WHERE START_DATE = '09.10')

Результат:

WORKER ID

1520

Мы выделили часть SQL-выражения, важную для нашего обсуждения. Две фразы SELECT определяют две таблицы, которые явно не являются объ­единительно-совместимыми. Однако мы можем взять их пересечение, огово­рив, что рассматриваются только те столбцы, которые есть в обеих таблицах. Мы указываем, какие столбцы рассматривать, в команде CORRESPONDING BY. В нашем случае рассматривается только столбец WORKER_ID. Система оставит из результатов выполнения команд SELECT только значения в столбце WORKER_ID, Затем она возьмет пересечение этих двух множеств, и это будет результат запроса. Таким образом, в результате получится список ИД тех работников, которые имеют специальность «штукатур» и получили работу, которая должна начинаться 9 октября - в точности это и требовалось.

Такой же подход используется для операторов UNION и EXCEPT. Фраза CORRESPONDING BY следует за оператором и перечисляет столбцы, общие для обеих рассматриваемых таблиц. Рассмотрим еще несколько примеров:

Запрос: Какие здания являются зданиями офисов или же на них назна­чен рабочий 14127

(SELECT * FROM BUILDING

WHERE TYPE = 'Офис')

UNION CORRESPONDING BY (BLDG_ID)

(SELECT * FROM ASSIGNMENT

WHERE WORKER_ID = 1412)

Результат:

BLDG_ID

312

210

111

460

435

515

Запрос: На какие здания офисов не назначен рабочий 1235?

(SELECT * FROM BUILDING

WHERE TYPE = 'Офис')

EXCEPT CORRESPONDING BY (BLDG_ID)

(SELECT * FROM ASSIGNMENT

WHERE WORKER_ID = 1235)

Результат:

BLDG ID

210

111

Вы, вероятно, заметили, что эти запросы относительно легко сформули­ровать. Мы просто определяем подходящие подмножества строк из двух таб­лиц, а затем применяем соответствующий оператор UNION, INTERSECT или EXCEPT. Это существенно расширяет практические возможности языка, поскольку многие люди считают, что подобные запросы проще формулировать, пользуясь именно таким подходом. Например, применим к последнему за­просу «старый» подход SQL:

SELECT BLDG_ID

FROM BUILDING

WHERE TYPE = 'Офис' AND

NOT EXISTS (SELECT *

FROM ASSIGNMENT

WHERE BUILDING.BLDG_ID = ASSIGNMENT.BLDG_ID

AND WORKER_ID = 1235)

В этом решении использован коррелированный подзапрос и оператор NOT EXISTS. Естественно предположить, что большинству людей значи­тельно сложнее сформулировать такое решение, чем решение с оператором EXCEPT. Тем не менее, обратите внимание, что запрос можно было бы реа­лизовать с помощью старого синтаксиса SQL. Это не так просто.

Оператор JOIN (соединение). SQL2 содержит несколько операторов со­единения в явной форме: естественное соединение, внутреннее соединение, несколько внешних соединений, объединительное соединение и кросс-соеди­нение. Мы рассмотрим только естественное и внутреннее соединения.

Естественное соединение. Соответственно названию, естественное соеди­нение имеет то же значение в SQL, что и в реляционной алгебре. Предполо­жим, что мы хотим соединить таблицы WORKER и ASSIGNMENT. Мы мо­жем использовать такой синтаксис:

WORKER NATURAL JOIN ASSIGNMENT

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

SELECT P.WORKER_ID, WORKER_NAME, HRLY_RATE, SKILL_TYPE,

SUPV_ID, WORKER_ID, BLDG_ID, START_DATE, NUM_DAYS

FROM WORKER, ASSIGNMENT

WHERE P.WORKER_ID = ASSIGNMENT.WORKER_ID,

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

NATURAL JOIN. Оператор, соединяющий таблицы в том случае, если общие столбцы имеют равные значения.

JOIN USING. Предположим, у нас есть две таблицы А и В, и у них есть общие столбцы К, L, М и N. Предположим, что мы хотим соединить таб­лицы не по всем общим столбцам, а только по столбцам L и N. Тогда мы можем воспользоваться следующим выражением:

A JOIN В USING (L, N)

Это выражение даст тот же результат, что и SELECT-выражение, в кото­ром в команде SELECT будут сначала перечислены столбцы L и N, за кото­рыми следуют оставшиеся столбцы А и оставшиеся столбцы В. Фраза WHERE в таком выражении должна иметь вид

WHERE A.L = B.L AND A.N = B.N

JOIN USING. Операция, связывающая таблицы только по указанным общим столбцам, имеющим равные значения.

JOIN ON. Если мы хотим задать более общее условие соединения двух таблиц, то можем пользоваться этой формой. Например, предположим, что мы хотим присоединить таблицу WORKER к ней самой, связав WORKER ID с SUPV_ID, чтобы получить информацию о менеджере каждого работника. Воспользуемся следующим выражением:

WORKER W JOIN WORKER SUPV

ON W.SUPV_ID = SUPV.WORKER_ID

В этом примере мы создали две копии таблицы WORKER и дали им псевдонимы W и SUPV, соответственно. Фраза ON содержит условие равен­ства SUPV_ID копии W и WORKER_ID копии SUPV таблицы WORKER.

JOIN ON. Операция, связывающая таблицы при выполнении условия.

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

Запрос: Выдать данные о назначении и работнике для каждого штука­тура, начинающего работу 9 октября.

(SELECT * FROM WORKER WHERE SKILL_TYPE = 'Штукатур')

NATURAL JOIN

(SELECT * FROM ASSIGNMENT WHERE START_DATE = '09.10')

Возможно, вы заметили, что этот запрос почти идентичен тому, который использовался ранее для иллюстрации работы оператора INTERSECT. Раз­ница состоит в том, что вместо того, чтобы просто получить список WORKER_ID, мы получим всю связанную с работником информацию, по­скольку кортежи таблицы WORKER будут связаны с кортежами таблицы ASSIGNMENT.

Запрос: Выдать данные о назначении, работнике и здании для каждого штукатура, начинающего работу 9 октября и работающего на жилом доме.

(SELECT * FROM WORKER WHERE SKILL_TYPE = 'Штукатур')

NATURAL JOIN

(SELECT * FROM ASSIGNMENT WHERE START_DATE = '09.10')

NATURAL JOIN

(SELECT * FROM BUILDING WHERE TYPE - 'Жилой дом')

В этом случае WORKER_ID и BLDG_ID - столбцы, по которым выпол­няется соединение - будут стоять в таблице результатов первыми, за ними будут следовать оставшиеся столбцы таблиц WORKER, ASSIGNMENT, BUILDING (именно в таком порядке). Если в результате мы получаем избы­точную информацию, то можем поместить все это выражение внутрь выра­жения SELECT FROM, указывающего нужные столбцы:

SELECT WORKER_ID, START_DATE, BLDG_ID, ADDRESS

FROM (SELECT * FROM WORKER WHERE SKILL_TYPE = 'Штукатур')

NATURAL JOIN

(SELECT * FROM ASSIGNMENT WHERE START_DATE = '09.10')

NATURAL JOIN

(SELECT * FROM BUILDING WHERE TYPE = 'Жилой дом')

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]