Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Базы данных. Практический курс. В 2 частях. Ч.1. Объектно-реляционные базы данных на примере PostgreSQL 9.5. Учебное пособие.pdf
Скачиваний:
0
Добавлен:
06.09.2026
Размер:
2 Мб
Скачать
Глава 3. Введение в язык SQL 3.2. Средства запроса данных языка SQL
Результатом первого запроса будет отношение
Count
8
Результатом второго запроса будет отношение
Count
5
Разница в результатах возникает потому, что второй оператор
SELECT не учитывает повторяющиеся строки.
Вот еще один пример использования агрегатных функций:
SELECT MIN(SalesPrice), MAX(SalesPrice), SUM(SalesPrice) FROM TRANSACTION WHERE TransactionID < 406;
Результатом будет следующая таблица:
Min Max Sum
9750.00 73500.00 165950.00
Кроме случая с использованием ключевых слов GROUP BY и
PARTITION BY (см. далее), Имена столбцов не могут смешиваться с
агрегатными функциями. Например, следующий оператор недопу­стим:
SELECT CustomerID, SUM(SalesPrice) FROM TRANSACTION WHERE TransactionID < 406;

3.2.7 Агрегатные функции и группировка

Полезность агрегатных функций увеличивает тот факт, что их можно применять к группам строк данных. Например, следующий оператор подсчитывает количество художников каждой националь­ности:
SELECT Nationality, COUNT(*) FROM ARTIST GROUP BY Nationality;
Результат будет таким:
51
3.2. Средства запроса данных языка SQL Глава 3. Введение в язык SQL
Nationality Count
German 1 French 2 Russian 1 US 3 Spanish 1
Ключевое слово GROUP BY предписывает СУБД отсортировать таблицу по указанному столбцу, а затем применить агрегатные функции к группам строк, имеющим одинаковые значения данного столбца. При использовании GROUP BY имя столбца, по которому производится группировка, и агрегатные функции могут сосуще­ствовать в предложении SELECT. Это первый из двух случаев, когда имя столбца может появляться вместе с агрегатными функциями.
Далее ограничить множество выдаваемых результатов можно, применяя к формируемым группам различные условия. Например, если нас интересуют только те группы, в которых имеется более одной записи, мы могли бы написать следующее:
SELECT Nationality, COUNT(*) FROM ARTIST GROUP BY Nationality HAVING COUNT(*) > 1;
Результатом этого оператора будет следующая таблица:
Nationality Count
French 2 US 3
Вместе с ключевым словом GROUP BY можно использовать и предложение WHERE. Однако здесь имеет место неоднозначность. Если условие в предложении WHERE применяется до формирования групп, результат будет иным, чем когда это условие применяется к уже сформированным группам. Для устранения этой неоднознач­ности стандарт SQL устанавливает, что в случаях, когда предложе­ния WHERE и GROUP BY используются одновременно, первым должно применяться условие, записанное в предложении WHERE. Рассмот­рим, например, следующий оператор:
52
Глава 3. Введение в язык SQL 3.2. Средства запроса данных языка SQL
SELECT Nationality, COUNT(*) FROM ARTIST WHERE ArtistID < 106 GROUP BY Nationality HAVING COUNT(*) > 1;
При выполнении данного оператора сначала применяется условие из предложения WHERE, которое отбирает художников, чей идентификатор меньше 106. Затем, после формирования групп, применяется условие из предложения HAVING. Результат имеет сле­дующий вид:
Nationality Count
US 2

3.2.8 Оконные функции

Использование оконных функций – второй из двух случаев, когда имя столбца может появляться вместе с агрегатными функ­циями.
При использовании группировки результирующая таблица со­держит по одной строке для каждого группируемого значения, а оконная функция не свертывает результаты, принадлежащие одной группе.
Следующий запрос использует оператор GROUP BY:
SELECT Title, ArtistID, COUNT(*) FROM WORK GROUP BY Title, ArtistID ORDER BY ArtistID;
Результат имеет вид:
Title ArtistID Count
Mi Vida 101 1 Mystic Fabric 106 2 Slow Embers 106 1 Northwest by Night 108 1
Следующий запрос содержит оператор PARTITION BY для реа­лизации оконной функции и имеет вид:
53
3.2. Средства запроса данных языка SQL Глава 3. Введение в язык SQL
SELECT Title, ArtistID, COUNT(*) OVER (PARTITION BY ArtistID) FROM WORK ORDER BY ArtistID;
Результат данного запроса представлен в таблице:
Title ArtistID Count
Mi Vida 101 1 Mystic Fabric 106 3 Slow Embers 106 3 Mystic Fabric 106 3 Northwest by Night 108 1
Как видно из примеров, оператор PARTITION BY является близ­ким аналогом оператора GROUP BY, но вместо группировки результа­тов по столбцам, указанным в запросе вне агрегатных функций, что приводит к уменьшению общего количества строк в результирую­щей таблице, данный оператор возвращает результаты вычисления агрегатных функций.

3.2.9 Чтение данных из нескольких таблиц с применением вложенных запросов

Все запросы, рассмотренные ранее, считывали данные из оди­ночной таблицы. Бывает, однако, что для получения требуемой информации необходимо обработать более одной таблицы. Пред­положим, например, что мы хотим знать названия работ, которые были проданы галереей дороже 20 000. Названия работ хранятся в таблице WORK, а стоимости продаж в таблице TRANSACTION.
Если бы мы знали, что дороже 20 000 были проданы работы с номерами 301, 302 и 305, мы могли бы получить названия этих работ с помощью следующего запроса:
SELECT Title FROM WORK WHERE WorkID IN (301, 302, 305);
Но в том-то и дело, что в условии задачи номера работ нам не заданы. Ничто, однако, не мешает нам узнать эти номера, иниции­ровав следующий запрос:
54
Глава 3. Введение в язык SQL 3.2. Средства запроса данных языка SQL
SELECT DISTINCT WorkID FROM TRANSACTION WHERE SalesPrice > 20000;
Результатом будет таблица:
WorkID
301 305 302
Теперь мы можем объединить эти два SQL-запроса при помо-
щи так называемого вложенного запроса (subquery):
SELECT Title FROM WORK WHERE WorkID IN (
SELECT DISTINCT WorkID FROM TRANSACTION WHERE SalesPrice > 20000
);
Результатом этого оператора будет следующее:
WorkID
Mystic Fabric Mi Vida Northwest by Night
И действительно, здесь мы видим названия работ, которые были проданы галереей дороже 20 000. Подобным образом вложен­ность запросов может быть расширена до трех, четырех и более уровней.

3.2.10 Чтение данных из нескольких таблиц с помощью операции соединения

Вложенные запросы подходят для обработки нескольких таб­лиц до тех пор, пока результаты (столбцы в предложении SELECT) относятся к одной и той же таблице. Если же нам нужно извлечь данные из двух или более таблиц, при помощи вложенного запро­са это сделать не удастся. Вместо этого необходимо использовать операцию соединения (JOIN).
55
3.2. Средства запроса данных языка SQL Глава 3. Введение в язык SQL
Основная идея здесь – создать новое отношение, связав между собой содержимое двух или более исходных отношений. Рассмот­рим следующий пример:
SELECT Title, SalesPrice FROM WORK, TRANSACTION WHERE WORK.WorkID = TRANSACTION.WorkID;
Смысл этого оператора заключается в том, что создается но­вая таблица с двумя столбцами Title и SalesPrice. Эти столбцы берутся соответственно из таблиц WORK и TRANSACTION при условии, что столбец WorkID в таблице WORK равен одноименному столбцу в таблице TRANSACTION. Обозначения WORK.WorkID и TRANSACTION.WorkID необходимы для устранения конфликта имен столбцов.
Эту операцию можно представить себе следующим образом. Начнем с первой строки таблицы TRANSACTION. Возьмем значение столбца WorkID в данной строке (в табл. 2.4 это 301) и просмотрим строки таблицы WORK (табл. 2.3). Найдя в таблице WORK строку, где
WorkID также равняется 301, соединим столбец Title только что
найденной первой строки таблицы WORK со столбцом SalesPrice пер­вой строки таблицы TRANSACTION.
Первая строка таблицы WORK (см. табл. 2.3) имеет WorkID, рав­ный 301, поэтому мы соединяем столбец Title первой строки табли­цы WORK со столбцом SalesPrice первой строки таблицы TRANSACTION, и получаем тем самым первую строку соединения:
Title SalesPrice
Mystic Fabric 18500.00
Теперь, по-прежнему используя равенство WorkID = 301, най­дем следующую строку в отношении WORK, которая имеет WorkID, равный 301. Таких строк больше нет, поэтому переходим ко второй строке таблицы TRANSACTION. Так как в этой строке WorkID так же равен 301, снова найдем первую строку в отношении WORK, которая имеет WorkID, равный 301. Соединив столбец Title первой стро­ки таблицы WORK со столбцом SalesPrice второй строки таблицы
TRANSACTION, мы получим вторую строку соединения:
56
Глава 3. Введение в язык SQL 3.2. Средства запроса данных языка SQL
Title SalesPrice
Mystic Fabric 18500.00 Mystic Fabric 46700.00
Таким образом, перебирая все строки отношения TRANSACTION,
получаем окончательный результат:
Title SalesPrice
Mystic Fabric 18500.00 Mystic Fabric 46700.00 Mystic Fabric 9750.00 Mi Vida 17500.00 Mi Vida 73500.00 Slow Embers 14500.00 Mystic Fabric Northwest by Night 71500.00
Таблицу, получившуюся в результате соединения, можно об­рабатывать также, как и любую другую таблицу. Например, мы мо­жем сгруппировать строки по названиям картин и просуммировать вырученные суммы по каждой из картин. Это сделает следующий запрос:
SELECT Title, SUM(SalesPrice) FROM WORK, TRANSACTION WHERE WORK.WorkID = TRANSACTION.WorkID GROUP BY Title;
Результатом будет следующая таблица:
Title Sum
Mi Vida 91000.00 Slow Embers 14500.00 Northwest by Night 71500.00 Mystic Fabric 74950.00
Предложение WHERE мы также можем применить в процессе создания соединения:
SELECT Title, SalesPrice FROM WORK, TRANSACTION WHERE WORK.WorkID = TRANSACTION.WorkID AND SalesPrice > 20000;
57
3.2. Средства запроса данных языка SQL Глава 3. Введение в язык SQL
Результат соединения будет таким:
Title SalesPrice
Mystic Fabric 46700.00 Mi Vida 73500.00 Northwest by Night 71500.00
Это такая же таблица, поэтому все описанные выше
SQL-операторы к ней применимы.
Теперь рассмотрим случай, когда требуется соединить три таблицы. Предположим, нам нужно знать по каждой картине вы­рученную сумму и имя художника. Для этого нам нужно соеди­нить три таблицы: TRANSACTION (поле SalesPrice), WORK (поле Title) и
ARTIST (поле Name):
SELECT Title, SalesPrice, Name FROM WORK, TRANSACTION, ARTIST WHERE WORK.WorkID = TRANSACTION.WorkID AND WORK.ArtistID = ARTIST.ArtistID;
Результатом соединения будет следующая таблица:
Title SalesPrice Name
Mystic Fabric 46700.00 Tobey Mystic Fabric 18500.00 Tobey Mi Vida 73500.00 Miro Mi Vida 17500.00 Miro Slow Embers 14500.00 Tobey Mystic Fabric Tobey Mystic Fabric 9750.00 Tobey Northwest by Night 71500.00 Chagall
В стандарте SQL-92 введен альтернативный синтаксис соеди­нения, ставший весьма популярным, поскольку его легче интерпре­тировать. Здесь вместо WHERE используются ключевые слова JOIN и
ON:
SELECT Title, SalesPrice FROM WORK JOIN TRANSACTION ON WORK.WorkID = TRANSACTION.WorkID;
Результат имеет следующий вид:
58
Глава 3. Введение в язык SQL 3.2. Средства запроса данных языка SQL
Title SalesPrice
Mystic Fabric 46700.00 Mystic Fabric 18500.00 Mi Vida 73500.00 Mi Vida 17500.00 Slow Embers 14500.00 Mystic Fabric Mystic Fabric 9750.00 Northwest by Night 71500.00
Сделать оператор соединения более удобным для чтения мож-
но, используя псевдонимы для имен таблиц. Выражение FROM WORK
W присваивает таблице WORK псевдоним W. Это позволяет переписать
предыдущий оператор следующим образом:
SELECT Title, SalesPrice FROM WORK W JOIN TRANSACTION T ON W.WorkID = T.WorkID;
Соединение трех таблиц можно выполнить путем добавления
предложения JOIN в конец первого оператора SELECT:
SELECT W.Title, SalesPrice, A.Name FROM WORK W JOIN TRANSACTION T ON W.WorkID = T.WorkID JOIN ARTIST A ON W.ArtistID = A.ArtistID;
Следует обратить внимание, что когда требуется указать имя столбца в первой строке оператора SELECT, необходимо использо­вать псевдоним, а не имя таблицы. Так, в вышеприведенном опера­торе SELECT используется запись W.Title, а не WORK.Title.
По мере того как запросы усложняются, этот формат оказы­вается легче интерпретировать, и именно он будет использоваться для соединений далее. На практике необходимо знать оба формата, поскольку и тот, и другой применяются в промышленности.
Теперь рассмотрим различия между вложенным запросом и соединением. На практике соединение во многих случаях можно использовать в качестве альтернативы вложенным запросам. На­пример, ранее в пункте 3.2.9 был использован вложенный запрос для нахождения названия работ, которые были проданы галереей
59
3.2. Средства запроса данных языка SQL Глава 3. Введение в язык SQL
дороже 20 000. Этот же запрос можно реализовать и с помощью соединения:
SELECT DISTINCT Title FROM WORK JOIN TRANSACTION ON WORK.WorkID = TRANSACTION.WorkID AND SalesPrice > 20000;
Хотя ситуации, когда соединение можно использовать вместо вложенного запроса, нередки, такая замена все же возможна не всегда. Например, соединения не могут заменить коррелированные вложенные запросы, а также запросы с использованием ключевых слов EXISTS и NOT EXISTS (будут рассматриваться далее в следующих разделах пособия).
И наоборот, не всегда вложенный запрос может служить за­меной для соединения. В соединении запрашиваемые столбцы мо­гут принадлежать любой из соединяемых таблиц, а во вложенном запросе все возвращаемые столбцы должны принадлежать только одной таблице, и именно той, которая указана в предложении FROM самого первого оператора SELECT. Например, в следующем вложен­ном запросе в результат войдут только столбцы таблицы ARTIST:
SELECT DISTINCT Name FROM ARTIST WHERE ArtistID IN (
SELECT ArtistID FROM WORK WHERE WorkID IN (
Select WorkID FROM TRANSACTION WHERE SalesPrice > 20000
)
);
Если нужно включить в результат столбец WORK.Title, придет­ся использовать соединение:
SELECT A.Name, W.Title FROM ARTIST A JOIN WORK W ON A.ArtistID = W.ArtistID JOIN TRANSACTION T ON T.WorkID = W.WorkID AND SalesPrice > 20000;
60
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]