Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

УП СУБД ч1

.pdf
Скачиваний:
14
Добавлен:
11.06.2015
Размер:
1.05 Mб
Скачать

 

COUNT(*)

 

COUNT(RESULT)

 

 

 

5

 

 

3

 

 

 

 

Рис. 10.7. Значение запроса 10.9

 

SELECT SUM(result) FROM CourseResult;

(10.10)

 

 

 

 

 

 

 

 

 

SUM(RESULT)

 

 

 

 

 

 

14

 

 

 

Рис. 10.8. Значение запроса 10.10

При группировке по некоторому полю пустые значения в этом поле также не игнорируется:

SELECT result, COUNT(result), COUNT(*)

 

(10.11)

FROM CourseResult GROUP BY result;

 

 

 

 

 

 

 

RESULT

COUNT(RESULT)

 

COUNT(*)

 

 

-

0

 

 

2

 

 

5

2

 

 

2

 

 

4

1

 

 

1

 

Рис. 10.9. Значение запроса 10.11

При работе с пустыми значениями используются функции NVL() и NVL2(). Функция NVL() имеет два параметра; значение этой функции – значение первого параметра, если это не пустое значение, или значение второго параметра. Функция NVL2() имеет три параметра; если значение первого параметра – NULL, то функция возвращает значение третьего параметра или значение второго параметра – в противном случае. Ниже приведены примеры использования этих функций.

SELECT STUDENT, COURSE, NVL(TO_CHAR(RESULT), ‘без оценки’)

FROM CourseResult

(10.12)

 

 

 

 

STUDENT

COURSE

 

NVL(TO_CHAR(RESULT),’БЕЗОЦЕНКИ’)

Jane

OS

 

5

Bill

C Programming

 

5

Polie

Graphics

 

без оценки

Jane

DBMS

 

4

Bill

DBMS

 

без оценки

Рис. 10.10. Значение запроса 10.12

101

SELECT STUDENT, COURSE, NVL2(RESULT, ‘хорошо’, ‘плохо’)

FROM CourseResult

(10.13)

 

 

 

STUDENT

COURSE

NVL2(RESULT,’ХОРОШО’,’ПЛОХО’)

Jane

OS

Хорошо

Bill

C Programming

Хорошо

Polie

Graphics

Плохо

Jane

DBMS

Хорошо

Bill

DBMS

Плохо

Рис. 10.11. Значение запроса 10.13

10.2. Запросы с соединением

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

CREATE TABLE Student

студенты

(

name CHAR(20),

имя студента

 

class INT );

группа

CREATE TABLE Course

читаемые курсы

(

title CHAR(20),

название курса

 

staff CHAR(20));

имя преподавателя

CREATE TABLE Staff

преподаватели

(

name CHAR(20),

имя преподавателя

 

position CHAR(20) );

должность

CREATE TABLE Attends

посещаемые курсы

(

student CHAR(20),

имя студента

 

title CHAR(20));

название курса

 

 

 

 

 

 

 

NAME

CLASS

 

 

 

Gill

1

 

 

 

Jane

3

 

Bill 3

Polie 2

102

 

NAME

POSITION

 

Won Kim

Full Professor

 

G.Anderson

Senior Lector

 

S.Abiteboul

Full Professor

 

 

 

 

TITLE

STAFF

 

DBMS

G.Anderson

 

Graphics

G.Anderson

 

OS

G.Anderson

 

C Programming

Won Kim

 

Cryptography

Won Kim

 

 

 

 

STUDENT

TITLE

 

Jane

DBMS

 

Bill

DBMS

 

Jane

OS

 

Bill

C Programming

 

Polie

Graphics

Рис. 10.12. Таблицы Student, Course, Staff и Attends

Рассмотрим запрос, который осуществляет выборку из двух таблиц:

SELECT * FROM Course, Attends;

(10.12)

 

 

 

 

TITLE

STAFF

STUDENT

TITLE

DBMS

G.Anderson

Jane

DBMS

DBMS

G.Anderson

Bill

DBMS

DBMS

G.Anderson

Jane

OS

DBMS

G.Anderson

Bill

C Programming

DBMS

G.Anderson

Polie

Graphics

Graphics

G.Anderson

Jane

DBMS

Graphics

G.Anderson

Bill

DBMS

Graphics

G.Anderson

Jane

OS

Graphics

G.Anderson

Bill

C Programming

Graphics

G.Anderson

Polie

Graphics

OS

G.Anderson

Jane

DBMS

OS

G.Anderson

Bill

DBMS

OS

G.Anderson

Jane

OS

OS

G.Anderson

Bill

C Programming

OS

G.Anderson

Polie

Graphics

C Programming

Won Kim

Jane

DBMS

Рис. 10.13. Значение запроса 10.12

103

TITLE

STAFF

STUDENT

TITLE

C Programming

Won Kim

Bill

DBMS

C Programming

Won Kim

Jane

OS

C Programming

Won Kim

Bill

C Programming

C Programming

Won Kim

Polie

Graphics

Cryptography

Won Kim

Jane

DBMS

Cryptography

Won Kim

Bill

DBMS

Cryptography

Won Kim

Jane

OS

Cryptography

Won Kim

Bill

C Programming

Cryptography

Won Kim

Polie

Graphics

Рис. 10.13. (продолжение)

С точки зрения формальной семантики языка SQL значение данного запроса образовано следующим образом. Каждая строка таблицы Course (всего 5 строк) «объединяется» с каждой строкой из таблицы Attends (5 строк); всего получается 5*5 строк в результирующем множестве. Подобное действие, получившее название соединение двух таблиц, (точнее говоря, в данном случае – кросс-сединение), похоже на математическую операцию декартового произведения двух множеств. Этот запрос, однако, является десемантизированным (бессмысленным), поскольку с содержательной точки зрения его формальное значение – результирующее множество представляет собой механически построенный набор полей, не имеющий какого-либо содержания.

Более продуктивным является использование запросов следующего вида:

SELECT Attends.student, Course.title, Course.staff

FROM Course, Attends

(10.13)

WHERE Course.title = Attends.title;

 

 

 

 

 

 

 

STUDENT

TITLE

 

STAFF

 

 

Jane

DBMS

 

G.Anderson

 

 

Bill

DBMS

 

G.Anderson

 

 

Jane

OS

 

G.Anderson

 

 

Bill

C Programming

 

Won Kim

 

 

Polie

Graphics

 

G.Anderson

 

Рис. 10.14. Значение запроса 10.13

104

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

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

Формальное вычисление значения запроса, называемого запросом с эквисоединением двух таблиц, можно представить как: 1) вычисление набора всех возможных пар строк из обеих таблиц; 2) удаление из этого набора строк, не удовлетворяющих условию WHERE.

Запросы 10.12 и 10.13 можно записать в соответствии с более современным синтаксисом языка, используя конструкцию (INNER) JOIN:

SELECT Attends.student, Course.title, Course.staff

(10.14)

FROM Course CROSS JOIN Attends;

SELECT Attends.student, Course.title, Course.staff

 

FROM Course JOIN Attends

(10.15)

ON Course.title = Attends.title;

SELECT student, title, staff

(10.16)

FROM Course JOIN Attends USING (title);

SELECT title, staff, student

(10.17)

FROM Course NATURAL JOIN Attends;

Запрос 10.16 использует конструкцию JOIN USING, предполагающую соединение двух таблиц по совпадающим именам полей в таблицах; вариант соединения в запросе 10.17 называется естественным соединением (NATURAL JOIN), при этом в паре таблиц предполагается наличие одноименных полей.

105

При использовании естественного соединения и конструкции JOIN USING имена полей в выражениях после SELECT не могут быть квалифицированными. Конструкция CROSS JOIN в запросе 10.14 реализует декартово произведение.

Рассмотрим трех- и четырехтабличные запросы:

SELECT Student.name, Student.class, Attends.title,

 

Course.staff

 

 

 

FROM Student, Attends, Course

 

 

WHERE Student.name = Attends.student

AND Attends.title = Course.title;

(10.18)

 

 

 

 

 

 

NAME

CLASS

 

TITLE

STAFF

 

Bill

3

 

DBMS

G.Anderson

 

Jane

3

 

DBMS

G.Anderson

 

Polie

2

 

Graphics

G.Anderson

 

Jane

3

 

OS

G.Anderson

 

Bill

3

 

C Programming

Won Kim

 

 

 

Рис. 10.15. Значение запроса 10.18

 

 

SELECT Student.name, Student.class, Attends.title,

 

 

 

Course.staff, Staff.position

 

 

 

FROM Student, Attends, Course, Staff

 

 

 

WHERE Student.name = Attends.student

 

 

 

 

AND Attends.title = Course.title

 

(10.19)

 

AND Course.staff = Staff.name;

 

 

 

 

 

 

 

 

NAME

 

CLASS

TITLE

STAFF

 

POSITION

Jane

 

3

OS

G.Anderson

 

Senior Lector

Jane

 

3

DBMS

G.Anderson

 

Senior Lector

Bill

 

3

C Programming

Won Kim

 

Full Professor

Bill

 

3

DBMS

G.Anderson

 

Senior Lector

Polie

 

2

Graphics

G.Anderson

 

Senior Lector

 

 

Рис. 10.16. Значение запроса 10.19

 

 

Запрос 10.19 с использованием JOIN ON записывается так:

SELECT Student.name, Student.class, Attends.title,

 

 

 

Course.staff

 

 

 

 

 

FROM ( Student JOIN Attends

 

 

 

 

ON Student.name = Attends.student ) JOIN

 

 

Course ON ( Attends.title = Course.title );

(10.20)

106

Скобки в последнем примере необязательны и использованы для наглядности текста.

Вернемся к запросу 10.13. В выборке запись, соответствующая записи «Cryptography Won Kim» из таблицы Course, отсутствует, поскольку в таблице Attends нет ни одной записи со значением Cryptography в поле Course. Если в результирующем множестве необходимо присутствие таких «несвязанных» записей, следует использовать так называемые несимметричные соединения – правое (RIGHT JOIN) или левое (LEFT JOIN) внешние соединения, или полное соединение, в отличие от симметричного (внутреннего) соединения. Следующие два эквивалентных примера иллюстрируют использование левого соединения:

SELECT Student.name, Attends.title

 

FROM Student LEFT JOIN Attends

(10.21)

ON Student.name = Attends.student

SELECT Student.name, Attends.title

 

FROM Student, Attends

(10.22)

WHERE Student.name = Attends.student (+)

 

 

 

 

 

 

NAME

TITLE

 

 

 

Jane

DBMS

 

 

 

Bill

DBMS

 

 

 

Jane

OS

 

 

 

Bill

C Programming

 

 

 

Polie

Graphics

 

 

 

Gill

-

 

 

Рис. 10.17. Значения запроса 10.21 и 10.22

Впоследнем запросе 10.22 используется архаичная запись операции левого соединения, характерная для ранних версий языка SQL в системе Oracle.

Врезультирующем множестве строки действительно присутствует строка, соответствующая записи “Gill” исходной таблицы Student, а значение поля Title, для которого значение в таблице Course не существует, получило формальное значение NULL. Ниже приведен пример правого соединения:

SELECT student, title, staff

 

FROM Attends RIGHT JOIN Course

(10.23)

USING (title);

107

STUDENT

TITLE

STAFF

Jane

DBMS

G.Anderson

Bill

DBMS

G.Anderson

Jane

OS

G.Anderson

Bill

C Programming

Won Kim

Polie

Graphics

G.Anderson

-

Cryptography

Won Kim

Рис. 10.18. Значение запроса 10.23

Наконец, приведем пример полного соединения (FULL JOIN), которое предполагает наличие «несвязанных» записей в обеих таблицах:

SELECT name, title, staff

 

FROM Student LEFT JOIN Attends

 

ON Student.name = Attends.student

(10.24)

FULL JOIN Course USING (title);

В этом запросе сначала образуется левое соединение таблиц Student и Attends по полям name и student соответственно, что, как видно из примера 10.23, приводит к появлению в выборке пустых значений в поле title. Затем выполняется полное соединение полученной выборки с таблицей Course:

NAME

TITLE

STAFF

Bill

DBMS

G.Anderson

Jane

DBMS

G.Anderson

Polie

Graphics

G.Anderson

Jane

OS

G.Anderson

Bill

C Programming

Won Kim

Gill

-

-

-

Cryptography

Won Kim

Рис. 10.19. Значение запроса 10.24

Несимметричные соединения полезны для выявления «несвязанных» записей; этот тип запросов с соединением часто называется антисоединением. Следующий характерный пример определяет количество студентов, посещающих проводимые курсы, включая курсы, которые никто не посещает:

108

SELECT title «Курс», staff «Преподаватель»

 

FROM Attends RIGHT JOIN Course USING (title)

(10.25)

WHERE student IS NULL;

Аналогичный результат можно получить и следующим образом:

SELECT title «Курс», staff «Преподавателя», COUNT(student) «Посещают,чел.»

FROM Attends RIGHT JOIN Course USING (title)

GROUP BY title, staff;

(10.26)

 

 

 

 

Курс

Преподавателя

Посещают, чел.

 

OS

G.Anderson

1

 

Graphics

G.Anderson

1

 

C Programming

Won Kim

1

 

DBMS

G.Anderson

2

 

Cryptography

Won Kim

0

 

Рис. 10.20. Значение запроса 10.26

Модифицируя предыдущий запрос, можно получить название курса, не посещаемого студентами:

SELECT title «Курс», staff «Преподаватель» FROM Attends RIGHT JOIN Course USING (title)

GROUP BY title, staff

 

(10.26)

 

HAVING COUNT(student) = 0;

 

 

 

 

 

Курс

Преподаватель

 

 

 

 

 

 

Cryptography

Won Kim

 

 

 

 

 

Рис. 10.21. Значение запроса 10.26

Соединение таблиц может выполняться не только по одному полю, но и по комбинации полей (два или более). Рассмотрим, например, следующий запрос:

SELECT A.student, A.title, CR.result

 

FROM Attends A JOIN CourseResult CR

 

ON CR.student = A.student

(7.27)

AND CR.Course = A.title

109

STUDENT

TITLE

RESULT

Bill

C Programming

5

Jane

OS

5

Jane

DBMS

4

Bill

DBMS

-

Polie

Graphics

-

Рис. 10.22. Значение запроса 10.27

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

Однако с формальной точки зрения нет основания считать, что каждой записи в таблице Attends обязательно должна соответствовать запись в таблице CourseResult (хотя это было бы естественным предположением). Если такая ситуация возможна, то запрос 7.27 должен использовать соединение этих двух таблиц.

Если в запросе с соединением некоторая таблица в конструкции FROM используется два и более раз, такой запрос называется запросом с самосоединением. Такие запросы удобны для работы с рекурсивными данными, представленными в виде записей в SQL-таблице. Например, в следующем примере в таблице «Трубы» представлена топология газовых коммуникаций, которая имеет древовидную структуру:

CREATE TABLE «Трубы»

Паспорт

Номер

Отвод из

( «Паспорт» CHAR(100),

ТВД-12А

1

-

«Номер» INT,

ТСД-234А1

2

1

«Отвод из» INT );

ТСД-32И

3

2

 

ТНД-43В2

4

3

 

ТСД-73

5

1

Рис. 10.23. Данные таблицы «Трубы»

110