Язык SQL · 2018-09-16 · Министерство образования и науки...

Preview:

Citation preview

Министерство образования и науки Российской Федерации

Псковский государственный университет

Н.В. Мотина

Язык SQL

Методические указания к лабораторным работам

по курсам «Базы данных» и «Управление данными»

Псков

Издательство ПсковГУ

2013

УДК 004.655

ББК 32.973.26-018.1

М85

Рекомендовано к изданию кафедрой

«Вычислительная техника»

Псковского государственного университета

Рецензенты:

– Аристов М.В. – кандидат физ.-мат. наук, доцент кафедры «Инфор-

мационные системы и технологии» Псковского государственного

университета;

– Хватцев А.А. – канд. физ.-мат. наук, доцент кафедры «Высшая ма-

тематика» Псковского государственного университета.

Мотина, Н.В.

М85 Язык SQL: Методические указания к лабораторным работам по

курсам «Базы данных» и «Управление данными». Псковский

государственный университет. Псков : Изд.-во ПсковГУ, 2013.

104 с.

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

появященных ознакомлению с SQL – языком структурированных запросов

к базе данных. Представлен синтаксис команд выборки данных, начиная с

простейших и заканчивая достаточно сложными запросами с агрегирова-

нием данных и использованием подзапросов и представлений, а также ко-

манд изменения данных и команд определения данных. Изложение мате-

риала сопровождается примерами соответствующих SQL-запросов. Каж-

дый раздел оформлен в виде отдельной лабораторной работы, где после

рассмотрения теоретического материала следуют задания для самостоя-

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

ности SQL-команд СУБД PostgreSQL 7.1.

УДК 004.655

ББК 32.973.26-018.1

© Мотина Н. В., 2013

© Псковский государственный университет, 2013

3

ОГЛАВЛЕНИЕ

1. ВВЕДЕНИЕ В SQL.......................................................................................... 6

1.1. Что такое SQL ............................................................................................ 6

1.2. Ввод команд SQL ...................................................................................... 8

1.3. Типы данных .............................................................................................. 8

1.3.1. Строки ................................................................................................... 9

1.3.2. Числа ................................................................................................... 10

1.3.3. Логические типы данных .................................................................. 12

1.3.4. Дата и время ....................................................................................... 13

1.3.5. Интервалы .......................................................................................... 14

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

1.3.7. Преобразование типов ...................................................................... 16

Лабораторная работа 1 ................................................................................... 17

2. ПРОСТАЯ ВЫБОРКА ДАННЫХ ............................................................... 18

2.1. Структура оператора SELECT ............................................................... 18

2.2. Форма оператора SELECT для простой выборки данных .................. 20

2.3. Сортировка записей ................................................................................. 22

2.4. Выбор интервалов записей ..................................................................... 23

2.5. Условные выражения с оператором CASE ........................................... 24

2.5.1. Оператор CASE со значениями ........................................................ 24

2.5.2. Оператор CASE с условием поиска ................................................. 25

2.6. Функция COALESCE .............................................................................. 26

Лабораторная работа 2 ................................................................................... 27

3. УТОЧНЕНИЕ ЗАПРОСА ............................................................................. 28

3.1. Секция WHERE ....................................................................................... 28

3.2. Предикаты ................................................................................................ 29

3.2.1. Between ............................................................................................... 30

3.2.2. IN и NOT IN ....................................................................................... 30

3.2.3. LIKE и NOT LIKE .............................................................................. 30

3.2.4. SIMILAR ............................................................................................. 31

3.2.5. IS NULL .............................................................................................. 31

3.2.6. OVERLAPS......................................................................................... 32

Лабораторная работа 3 ................................................................................... 33

4. МНОГОТАБЛИЧНЫЕ ЗАПРОСЫ .............................................................. 34

4.1. Выбор источников в секции FROM ....................................................... 34

4.2. Операции соединения ............................................................................. 35

4.2.1. Перекрестное соединение ................................................................. 35

4.2.2. Естественное соединение ................................................................. 37

4.2.3. Соединение по именам столбцов ..................................................... 38

4.2.4. Условное соединение ........................................................................ 39

4.2.5. Сложные соединения ........................................................................ 40

Лабораторная работа 4 ................................................................................... 41

4

5. ИТОГОВЫЕ ЗАПРОСЫ ............................................................................... 43

5.1. Агрегатные функции ............................................................................... 43

5.2. Группировка записей .............................................................................. 44

5.3. Отбор групп записей ............................................................................... 45

Лабораторная работа 5 ................................................................................... 47

6. СЛОЖНЫЕ ЗАПРОСЫ ................................................................................ 48

6.1. Теоретико-множественные операции ................................................... 48

6.1.1. Декартово произведение наборов записей ..................................... 48

6.1.2. Объединение наборов записей ......................................................... 50

6.1.3. Пересечение наборов записей .......................................................... 51

6.1.4. Вычитание наборов записей ............................................................. 51

6.2. Внешние соединения............................................................................... 52

6.2.1. Левое внешнее соединение ............................................................... 52

6.2.2. Правое внешнее соединение ............................................................ 53

6.2.3. Полное внешнее соединение ............................................................ 53

6.3. Подзапросы .............................................................................................. 54

6.3.1. Простые подзапросы ......................................................................... 54

6.3.2. Связанные подзапросы ..................................................................... 56

6.4. Представления ......................................................................................... 59

Лабораторная работа 6 ................................................................................... 61

7. КОМАНДЫ ИЗМЕНЕНИЯ ДАННЫХ ....................................................... 62

7.1. Добавление новых записей ..................................................................... 62

7.2. Удаление записей .................................................................................... 63

7.3. Изменение данных................................................................................... 63

Лабораторная работа 7 ................................................................................... 66

8. ОПРЕДЕЛЕНИЕ ДАННЫХ ......................................................................... 67

8.1. Создание таблиц ...................................................................................... 67

8.1.1. Оператор CREATE TABLE .............................................................. 67

8.1.2. Ограничения для столбцов ............................................................... 67

8.1.3. Ограничения для таблиц ................................................................... 68

8.1.4. Внешние ключи ................................................................................. 69

8.2. Удаление таблиц ...................................................................................... 70

8.3. Модификация таблиц .............................................................................. 70

8.3.1. Создание полей .................................................................................. 71

8.3.2. Назначение и отмена значений по умолчанию .............................. 71

8.3.3. Переименование таблицы ................................................................. 72

8.3.4. Переименование полей ..................................................................... 72

8.3.5. Добавление ограничений .................................................................. 72

Лабораторная работа 8 ................................................................................... 74

ПРИЛОЖЕНИЯ ................................................................................................. 75

П.1. Возможности PostgreSQL ...................................................................... 75

П.2. Консоль psql ............................................................................................ 75

П.3. Команды SQL .......................................................................................... 76

5

П.3.1. Перечень команд SQL СУБД PostgreSQL ...................................... 76

П.3.2. Форматирование команд SQL ......................................................... 77

П.3.3. Выполнение запросов ....................................................................... 78

П.3.4. Ключевые слова и идентификаторы ............................................... 79

П.3.5. Комментарии ..................................................................................... 80

П. 4. Типы данных PostgreSQL 7.1. .............................................................. 81

П.4.1. Перечень типов данных ................................................................... 81

П.4.2. Преобразование типов ..................................................................... 84

П.4.3. Константы .......................................................................................... 85

П.5. Операторы ............................................................................................... 87

П.5.1. Правила использования операторов ............................................... 87

П.5.2. Строковые операторы ...................................................................... 88

П.5.3. Числовые операторы ........................................................................ 89

П.5.4. Двоичные операторы ........................................................................ 90

П.5.5. Логические операторы ..................................................................... 91

П.5.6. Операторы и NULL .......................................................................... 91

П.5.7. Приоритет операторов ..................................................................... 92

П.6. Функции ................................................................................................... 93

П.6.1. Использование функций .................................................................. 93

П.6.2. Математические функции ................................................................ 93

П.6.3. Строковые функции ......................................................................... 94

П.6.4. Функции для работы с датой и временем ...................................... 96

П.6.5. Функции преобразования типа ........................................................ 98

СПИСОК ЛИТЕРАТУРЫ ............................................................................... 102

6

1. ВВЕДЕНИЕ В SQL

1.1. Что такое SQL

SQL (Structured Query Language) – это структурированный язык за-

просов к реляционным базам данных. На этом языке можно формулиро-

вать выражения (запросы), которые извлекают требуемые данные, моди-

фицируют их, создают таблицы и изменяют их структуру, определяют

права доступа к данным и многое другое.

Запросы выполняются системой управления базой данных (СУБД).

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

специальных приложений, предоставляющих пользователю удобный ин-

терфейс. Однако доступ к базе данных можно получить и без них – с по-

мощью только SQL. Да и специализированные приложения обычно ис-

пользуют SQL-фрагменты кода при обращении к данным.

Таким образом, SQL – широко распространенный стандарт языка ра-

боты с реляционными базами данных. Различных СУБД существует много,

а универсальное средство работы с базами данных одно – SQL.

Первые разработки систем управления реляционными базами дан-

ных (реляционных СУБД) были выполнены в компании IBM в начале

1970-х годов. Тогда же был создан язык данных, предназначенный для ра-

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

SEQUEL – от англ. Structured English QUEry Language (структурированный

английский язык запросов). Однако официальная версия была названа ко-

роче – SQL (Structured Query Language).

В 1981 году IBM выпускает реляционную СУБД SQL/DS. К этому

времени компания Relation Software Inc. (сегодня это Oracle corporation)

уже выпустила свою реляционную СУБД. Эти продукты сразу же стали

стандартом систем, предназначенных для управления базами данных. В

состав этих продуктов вошел и SQL, который фактически стал стандартом

для языков данных. Производители других СУБД выпустили свои версии

SQL. В них имелись не только основные возможности продуктов IBM.

Чтобы получить некоторое преимущество для «своей» СУБД, производи-

тели вводили некоторые расширения SQL. Вместе с тем, начались работы

по созданию общепризнанного стандарта SQL.

В 1986 году Американский национальный институт стандартов

(American National Standarts Institute, ANSI) выпустил официальный стан-

дарт SQL-86, который в 1989 году был обновлен и получил новое название

SQL-89. В 1992 году этот стандарт был назван SQL-92. В настоящее время

известен стандарт SQL-2003.

Любая реализация SQL в конкретной СУБД несколько отличается от

стандарта. Так, многие СУБД (например, Microsoft Access 2003, Post-

7

greSQL 7.3) поддерживают SQL-92 не в полной мере, а лишь с некоторым

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

рые не входят в стандарт. Однако разработчики СУБД стремятся к тому,

чтобы новые версии их продуктов как можно в большей степени соответ-

ствовали стандарту SQL.

SQL задумывался как простой язык запросов к реляционной базе

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

лось, что близость по форме к естественному языку сделает SQL сред-

ством, доступным для широкого применения обычными пользователями

баз данных, а не только программистами. Первоначально SQL не содержал

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

мирования. Запросы, синтаксис которых довольно прост, вводились прямо

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

выполнялись. Однако SQL так и не стал инструментом банковских служа-

щих, продавцов авиа- и железнодорожных билетов, экономистов и других

служащих различных фирм, использующих информацию, хранимую в ба-

зах данных. Для них простой SQL оказался слишком сложным и неудоб-

ным, несмотря на свою близость к естественному языку вопросов.

На практике с базой данных обычно работают посредством прило-

жений, написанных программистами на процедурных языках, например, на

С, Visual Basic, Pascal, Java и др. Часто приложения создаются в специаль-

ных средах визуальной разработки, таких как Delphi, Microsoft Access, Vis-

ual dBase и т.п. Приложения имеют удобный графический интерфейс, не

вынуждающий пользователя непосредственно вводить запросы на языке

SQL. Вместо него это делает приложение.

Реляционные базы данных могут и действительно существуют вне

зависимости от приложений, обеспечивающих пользовательский интер-

фейс. Если по каким-либо причинам такого интерфейса нет, то доступ к

базе данных можно осуществить с помощью SQL, используя консоль или

какое-нибудь приложение, с помощью которого можно соединиться с ба-

зой данных, ввести и отправить SQL-запрос (например, Borland SQL Ex-

plorer).

Язык SQL считают декларативным (описательным) языком, в отли-

чие от языков, на которых пишутся программы. Это означает, что выраже-

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

Нет необходимости подробно описывать действия, которые должна вы-

полнить СУБД, чтобы выбрать из таблицы указанные в запросе данные.

Надо просто описать, что хочется получить. В результате выполнения за-

проса СУБД возвращает таблицу, содержащую запрошенные данные. Если

в базе данных не оказалось данных, соответствующих запросу, то будет

возвращена пустая таблица.

8

Однако последние версии SQL поддерживают операторы управления

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

перехода и цикла). Поэтому SQL сейчас это не чисто декларативный язык.

Кроме выборки, добавления, изменения и удаления данных из таб-

лиц, SQL позволяет выполнять все необходимые действия по созданию,

модификации и обеспечению безопасности баз данных. Все эти возможно-

сти распределены между тремя компонентами SQL:

DML (Data Manipulation Language – язык манипулирования данны-

ми) предназначен для поддержки базы данных: выбора (SELECT),

добавления (INSERT), изменения (UPDATE) и удаления (DELETE)

данных из таблиц;

DDL (Data Definition Language – язык определения данных) предна-

значен для создания, модификации и удаления таблиц и всей базы

данных. Примерами операторов, входящих в DDL, являются CREATE

TABLE (создать таблицу), CREATE VIEW (создать представление),

ALTER TABLE (изменить таблицу), DROP (удалить) и др.;

DCL (Data Control Language – язык управления данными) предназна-

чен для обеспечения защиты базы данных от различного рода по-

вреждений.

1.2. Ввод команд SQL

Ключевые слова в выражениях на языке SQL могут записываться как

прописными, так и строчными буквами, в одну или несколько строк. В

конце выражения должна стоять точка с запятой. Однако во многих систе-

мах в случае ввода одного SQL-выражения допускается не указывать при-

знак окончания (;).

Все ключевые слова SQL (команды, операторы и проч.) являются за-

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

столбцов, переменных и т.п.

Подробнее о правилах записи команд SQL, принятых в СУБД Post-

greSQL, см. в приложении (П.3. Команды SQL).

1.3. Типы данных

Различные СУБД поддерживают несколько отличающиеся наборы

типов данных для столбцов базы данных. Аналогичная ситуация и с типа-

ми данных, поддерживаемых различными версиями и реализациями SQL.

Типы данных, используемые в PostgreSQL, приведены в приложении (П.4.

Типы данных PostgreSQL 7.1.). Вместе с тем, всегда имеются типы данных,

9

которые поддерживаются всеми реализациями SQL. В спецификации

SQL:2003 признаны пять предопределенных общих типов, внутри которых

могут быть подтипы:

строковый (символьный):

CHARACTER (ИЛИ CHAR);

CHARACTER VARYING (ИЛИ VARCHAR);

CHARACTER LARGE OBJECT (ИЛИ CLOB);

числовой:

точные числовые типы: 1 INTEGER; 2 SMALLINT; 3 BIGINT; 4 NUMERIC; 5 DECIMAL;

приблизительные числовые типы:

1 REAL;

2 DOUBLE PRECISION;

3 FLOAT;

логический (булевский) – BOOLEAN;

даты-времени:

DATE;

TIME WITHOUT TIME ZONE;

TIME WITH TIME ZONE;

TIMESTAMP WITHOUT TIME ZONE;

TIMESTAMP WITH TIME ZONE;

интервальный.

1.3.1. Строки

Строковые данные (последовательности символов) имеют три глав-

ных строковых типа. Для столбца таблицы можно указать тип CHARAC-

TER (n) или CHAR (n) (строка фиксированной длины), где n – максималь-

ное количество символов, содержащихся в строке. Если (n) не указано, то

предполагается, что строка состоит из одного символа. Если в столбец ти-

па CHARACTER (n) вводится m < n символов, то оставшиеся позиции за-

полняются пробелами.

Тип данных CHARACTER VARYING (n) или VARCHAR (n) (строка пе-

ременной длины) применяется тогда, когда вводимые данные имеют раз-

личную длину и нежелательно дополнять их пробелами. При этом сохра-

няется только то количество символов, которое ввел пользователь. В дан-

10

ном случае указание максимального количества символов обязательно (в

отличие от CHARACTER).

Данные типов CHARACTER и CHARACTER VARYING могут участво-

вать в одних и тех же строковых операциях.

Тип данных CHARACTER LARGE OBJECT (CLOB – большой сим-

вольный объект) используется для представления очень больших символь-

ных строк (например, статей, книг и т.п.). В некоторых СУБД данный тип

называется MEMO, а в других – TEXT. С данными этого типа можно выпол-

нять не все операции, предусмотренные для типов CHARACTER и CHAR-

ACTER VARYING. Так, их нельзя использовать в операциях сравнения, за

исключением равенства и неравенства. Кроме того, столбцы этого типа не

могут быть первичными и внешними ключами, а также быть объявлены

как имеющие уникальные значения.

Значения строкового типа в SQL-выражениях заключаются в оди-

нарные кавычки. Например, ‘Иванов Иван Иванович’, ‘12345

рублей’, ‘тел. (812) 123-4567’. Пустая строка не содержит ни

одного символа и имеет вид: ''. Строка, содержащая один или более про-

белов, не является пустой.

1.3.2. Числа

Числовой тип данных может быть двух видов – точный и приблизи-

тельный. Точные числовые типы позволяют точно выразить значение чис-

ла. Некоторые величины имеют очень большой диапазон значений, и в та-

ких случаях достаточно ограничиться некоторым приближенным их пред-

ставлением с учетом технических возможностей компьютера (размеров ре-

гистра).

К точным числовым относятся следующие пять типов:

INTEGER – целое (без дробной части) число. Количество разрядов

(точность) зависит от реализации SQL. В некоторых реализациях

числа этого типа лежат в диапазоне от –2147483648 до 2147483647

(четырехбайтное целое число);

SMALLINT – малое целое число. Количество разрядов зависит от ре-

ализации SQL, но не больше количества разрядов INTEGER в этой

же реализации. В некоторых реализациях числа этого типа лежат в

диапазоне от –32768 до 32767 (двухбайтное целое число);

BIGINT – большое целое число. Количество разрядов зависит от ре-

ализации SQL и превышает количество разрядов числа типа INTE-

GER;

NUMERIC (X, Y) – число, в котором всего X разрядов (точность),

из которых Y разрядов (масштаб) отводится для дробной части. Если

11

Y не указано (NUMERIC (X)), то для дробной части отводится коли-

чество разрядов, установленное в системе по умолчанию. Если не

указаны ни X, ни Y (NUMERIC), то принимаются обе эти величины,

установленные по умолчанию. Например, если указан тип

NUMERIC (6, 2), то максимальное значение числа равно

9999.99;

DECIMAL (X, Y) – десятичное число, в котором всего X разря-

дов, из которых Y разрядов отводятся для дробной части. Если X

или/и Y не указаны, то принимаются значения по умолчанию. Этот

тип очень похож на NUMERIC. Отличие состоит в том, что если в

DECIMAL (X, Y) указанные X и Y меньше, чем допустимые реали-

зацией SQL, то будут использоваться последние. Если X и Y не ука-

заны, по применяется система умолчаний. Например, для столбца за-

дан тип DECIMAL (6, 2). Если реализация SQL позволяет, то в

этот столбец можно ввести числа, превышающие 9999.99. В отли-

чие от DECIMAL (X, Y), тип NUMERIC (X, Y) жестко задает

диапазон возможных значений числовой величины.

К приблизительным числовым типам относятся следующие три типа:

REAL – вещественное число одинарной точности с плавающей раз-

делительной точкой (эта точка «плавает», появляясь в различных ме-

стах числа). Например, 5.25, 5.257, 5.2573. Точность представ-

ления числа зависит от реализации SQL и оборудования. Например,

32-битовый компьютер дает большую точность, чем 16-битовый;

DOUBLE PRECISION – вещественное число двойной точности с

плавающей разделительной точкой. Точность представления зависит

от реализации SQL и оборудования. Применяется для представления

научных данных (например, результатов измерений) в широком диа-

пазоне значений, т.е. как очень малых (близких к 0), так и очень

больших;

FLOAT (X) – вещественное число с плавающей разделительной

точкой и минимальной точностью x, занимающее не более 8 байтов.

Если компьютер может поддерживать указанную точность, исполь-

зуя аппаратную одинарную точность, то система будет использовать

арифметику одинарной точности. Если указанная точность требует

арифметики с двойной точностью, то система будет использовать ее.

Данный тип следует применять, если предполагается возможность

переноса базы данных на другую аппаратную платформу, отличаю-

щуюся размерами регистров. Пример значения FLOAT: 5.318E-24

(т.е. 5.318, умноженное на 10 в степени -24). Такую же форму

представления имеют и числа типа REAL и DOUBLE PRECISION.

12

При создании таблиц целочисленные типы применяются для столб-

цов, содержащих разного рода идентификаторы, например, номера (коды)

клиентов, товаров, заказов и т.п. Разумеется, если содержимое столбца

должно быть целым числом (например, количество ящиков, бутылок, штук

и т.п.), то тип этого столбца естественно определить как INTEGER,

SMALLINT или BIGINT.

Пусть в таблице КЛИЕНТЫ имеется столбец ID_КЛИЕНТА, содержа-

щий уникальные идентификаторы клиентов. Если количество клиентов не

превышает 32000, то тип столбца можно определить как SMALLINT. Если

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

столбца ID_КЛИЕНТА следует определить как INTEGER.

Если столбец в проектируемой таблице должен содержать числа с

дробной частью, то для него можно задать какой-нибудь нецелочисленный

тип. При отсутствии уверенности, что применить: точные числовые типы

или приблизительные, следует выбирать точные (NUMERIC, DECIMAL).

Они требуют меньше ресурсов и дают точные результаты. Если в столбце

предполагается хранить данные из очень широкого диапазона (и очень ма-

лые, и очень большие числа), то следует использовать приблизительные

типы данных (FLOAT, REAL).

1.3.3. Логические типы данных

В этой части математической логики, основоположником которой

был английский математик Джон Буль, данные имеют только два значения

– ИСТИНА и ЛОЖЬ, обозначаемые как true и false соответственно.

Данные логического типа получаются в результате операций сравнения.

Например, результатом вычисления выражения 3 < 5 является ИСТИНА, а

выражение 2 + 3 = 10 – ЛОЖЬ.

В SQL тип данных BOOLEAN (булевский) имеет три значения –

true, false и unknown. Значение unknown (неизвестное) было введено

для обозначения результата, получающегося при сравнении со значением

NULL (неопределенное). Если пользователь еще не ввел в ячейку таблицы

никакого значения, то эта «пустая» ячейка содержит значение NULL, ин-

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

Результатом любой операции сравнения true или false с NULL

или с unknown всегда является unknown.

В SQL-выражениях логические значения заключаются в кавычки,

например, ‘TRUE’ или ‘true’.

13

1.3.4. Дата и время

Тип DATE (дата) предназначен для хранения значений даты, элемен-

ты которых расположены в следующем порядке: год (4 цифры), дефис (-),

месяц (2 цифры), дефис, день (2 цифры). Таким образом, значения даты за-

нимают 10 позиций, например, 2005-10-02.

Данные этого типа могут содержать любую дату с 0001 года по

9999 год.

Для представления времени предусмотрены два типа:

TIME WITHOUT TIME ZONE (время без часового пояса) предна-

значен для хранения значений времени, элементы которых располо-

жены в следующем порядке: часы, двоеточие, минуты, двоеточие,

секунды. Часы и минуты представляются двумя цифрами, а секунды

могут быть представлены двумя и более цифрами (если требуется

дробная часть), например 18:35:19.547. Длина дробной части се-

кунд зависит от реализации, но внутреннее представление времени

должно иметь не менее 6 цифр. По умолчанию время данного типа

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

должно быть представлено с n цифрами после разделительной точки,

достаточно использовать такой синтаксис: TIME WITHOUT TIME

ZONE (n). Например, чтобы кроме секунд указывались еще и мил-

лисекунды, следует определить тип как TIME WITHOUT TIME

ZONE (3). Длина данных рассматриваемого типа без дробной части

равна 8 символам, а с дробной частью – 9 плюс количество цифр по-

сле разделительной точки. Для задания времени без указания часово-

го пояса с использованием установок по умолчанию можно исполь-

зовать короткий синтаксис – TIME;

TIME WITH TIMEZONE (время с часовым поясом) – такой же тип

данных, как и TIME WITHOUT TIME ZONE. Отличие заключается

лишь в том, что к значению времени добавляется еще и информация

о разности между местным и всемирным временем. Всемирное время

(Universal Time Coordinated, UTC) – это время по Гринвичу, т.е. вре-

мя нулевого меридиана, проходящего через г. Гринвич в Великобри-

тании (Greenwich Mean Time, GMT). Значение разности между ло-

кальным и всемирным временем находится в диапазоне от –12:59 до

13:00. Длина данных рассматриваемого типа равна длине данных ти-

па TIME WITHOUT TIME ZONE плюс 6, поскольку дополнитель-

ная информация о разности времен занимает 6 позиций (дефис,

знак (+) или (-), 2 цифры для часов, двоеточие, 2 цифры для минут).

Для одновременного представления даты и времени служат следую-

щие два типа:

14

TIMESTAMP WITHOUT TIME ZONE (дата и время без часового по-

яса). Элементы данных этого типа имеют такие же характеристики,

как и для данных типа DATE и TIME WITHOUT TIME ZONE, за ис-

ключением одного: данные типа TIMESTAMP WITHOUT TIME

ZONE по умолчанию имеют 6 цифр в дробной части секунд, а не 0,

как в типе TIME WITHOUT TIME ZONE. Для указания количества

цифр в дробной части используется синтаксис TIMESTAMP WITH-

OUT TIME ZONE (n). Если дробной части нет, то данные занимают

19 позиций: 10 позиций для даты, один пробел и 8 позиций для вре-

мени. Если определена дробная часть, то длина данных равна 20

плюс количество цифр в дробной части секунд;

TIMESTAMP WITH TIME ZONE (дата и время с часовым поясом) –

такой же тип данных, как и TIMESTAMP WITHOUT TIME ZONE.

Отличие состоит в том, что к значению времени добавляется еще и

информация о разности между местным и всемирным временем. До-

полнительная информация занимает 6 позиций. Данные типа

TIMESTAMP WITH TIME ZONE без дробной части занимают 25 по-

зиций, с дробной частью – 26 плюс количество цифр в дробной части

секунд.

1.3.5. Интервалы

Интервал представляет собой разность между двумя значениями ти-

па дата-время.

Интервал времени можно задать двумя способами: в виде начального

и конечного моментов или в виде начального момента и длительности,

например:

(TIME '12:25:30', TIME '14:30:00') – интервал, задан-

ный начальным и конечным моментами;

(TIME '12:45:00', INTERVAL '5' HOUR) – интервал, за-

данный начальным моментом и длительностью в часах.

Чтобы задать значение типа интервал, используется такой синтаксис: INTER-

VAL 'длина' YEAR | MONTH | DAY | HOUR | MINUTE | SECO

ND

Здесь длина – длина интервала, после которой указывается единица

измерения (возможные значения указаны через вертикальную черту):

YEAR – год;

MONTH – месяц;

DAY – день;

HOUR – час;

15

MINUTE – минута;

SECOND – секунда.

Например, для задания интервала длиной 15 дней следует использо-

вать выражение INTERVAL '15' DAY.

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

Если в ячейку (поле) таблицы вводятся какие-то значения (буквы,

цифры, пробелы или еще что-нибудь), то эти ячейки приобретают так

называемые определенные значения. С определенными значениями, при-

надлежащими тому или иному типу можно выполнять какие-то операции.

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

поля (столбцы). Такая запись ничего не содержит. Запись в таблице, кото-

рая создана, но в которую не введены конкретные значения, называется

пустой. В каждой ячейке пустой записи содержится так называемое не-

определенное значение, обозначаемое через NULL. Значение NULL пони-

мается как неопределенное или неизвестное.

Каждый раз при добавлении в таблицу новой записи без ввода в нее

каких-либо конкретных значений, СУБД устанавливает в ее полях значе-

ние NULL.

Значение NULL можно интерпретировать так, как хочется, напри-

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

Важно понимать, что число 0 или пустая строка '' являются вполне

определенными значениями и отличаются от NULL, хотя визуально пустая

строка и неопределенное значение могут отображаться одинаково – в виде

пустой ячейки таблицы. Многие функции SQL возвращают в зависимости

от обстоятельств какое-то определенное значение либо NULL. Это необхо-

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

NULL и других вполне конкретных значений может дать тот или иной ре-

зультат в зависимости от конкретной операции.

Таблица базы данных может иметь некоторые записи, имеющие не-

определенные значения. Такие значения появляются по различным причи-

нам, однако при этом могут возникать неоднозначные ситуации при извле-

чении данных. Чтобы их избежать, необходимо помнить, что при сравне-

нии любого определенного значения с NULL результат равен false, т.е.

любое определенное значение не равно NULL. То же самое происходит при

сравнении двух величин, значениями которых являются NULL, т.е. сравне-

ние двух неопределенных величин в результате дает false.

При проектировании баз данных можно указать, что некоторые

столбцы не могут иметь значение NULL, т.е их значения обязательно

должны быть определены (при определении столбца в операторе CREATE

16

TABLE указывается NOT NULL). Однако во многих случаях значения

NULL являются очень полезными. Так, например, возможно создать табли-

цу и ввести в нее сведения, которые имеются в данный момент. Затем, по

мере поступления новой информации, можно изменить значения NULL на

те, которые стали известны.

1.3.7. Преобразование типов

Чтобы выполнить какую-либо операцию над данными различных

типов, необходимо сделать преобразование типов. Точнее, необходимо

выполнить приведение данных одного типа к другому типу, чтобы участ-

вующие в операции данные были либо однотипными, либо их типы были

соответствующими.

Соответствующими типами являются:

строковые CHARACTER и CHARACTER VARYING;

все числовые типы;

дата, время, дата-время и соответствующие интервалы.

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

Приведение значения одного типа к другому осуществляется с по-

мощью функции CAST():

CAST (выражение AS тип);

Например: CAST ('1234.52' AS NUMERIC (9, 2));

CAST ('2005-10-03' AS DATE);

CAST (CURRENT_TIMESTAMP (2) AS CHAR (20));

17

Лабораторная работа 1

1. Соединиться с базой данных booktown на сервере баз дан-

ных server.

2. Просмотреть список имеющихся на сервере баз данных.

3. Просмотреть список зарегистрированных пользователей

слэш-командой \du и командами языка SQL:

SELECT *

FROM pg_user;

SELECT usename, usesysid

FROM pg_user;

4. Просмотреть список групп пользователей SELECT *

FROM pg_group;

5. Просмотреть список таблиц базы данных booktown.

6. Для следующих таблиц определить их структуру (перечень

полей и соответствующие им типы данных) и составить гра-

фическую схему данных (какие поля являются общими, свя-

зующими для таблиц). Предложить смысловую интерпрета-

цию для каждой таблицы и всех ее полей. Посмотреть все

данные таблицы можно оператором: SELECT *

FROM имя_таблицы;

Рабочие таблицы:

authors,

books,

customers,

editions,

publishers,

shipments,

stock,

subjects.

18

2. ПРОСТАЯ ВЫБОРКА ДАННЫХ

Пусть реляционная база данных, состоящая из одной или нескольких

таблиц, создана, и произведено подключение к ней. В этом случае типич-

ной практической задачей является получение (извлечение) нужных дан-

ных. Например, может потребоваться просто просмотреть все содержимое

какой-либо таблицы из базы данных или некоторых ее полей. При этом,

возможно, потребуются не все записи, а лишь те, которые удовлетворяют

заданным условиям. Однако чаще возникает более сложная задача извле-

чения данных сразу из нескольких таблиц. Данные из двух и более таблиц

необходимо скомпоновать в одну таблицу, чтобы представить ее для обо-

зрения, анализа или последующей обработки. Язык SQL предоставляет для

этого широкие возможности.

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

ца (итоговый набор записей), которая либо содержит запрошенные данные,

либо пуста, если данных, соответствующих запросу, не нашлось. Эта таб-

лица, называемая результатной, существует только во время сеанса работы

с базой данных и не присоединяется к числу таблиц, входящих в базу дан-

ных. Она не хранится на жестком диске компьютера подобно исходным

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

Выборка данных из нескольких таблиц, их обработка, а также ис-

пользование подзапросов (запросов, которые нужны в качестве промежу-

точных для получения окончательного результата) относятся к сложным

запросам. Под простым запросом будем подразумевать задачи выборки

данных из одной таблицы при относительно простых условиях отбора,

группировки и сортировки записей. Тем не менее, операторы SQL, приме-

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

запросах, направленных не только на получение, но и на изменение дан-

ных.

2.1. Структура оператора SELECT

Основное SQL-выражение для выборки данных имеет вид: SELECT списокСтолбцов FROM таблица;

Такой запрос возвращает таблицу, полученную из указанной в операторе

FROM путем выделения в ней только тех столбцов, которые определены в

операторе SELECT. Для выделения требуемых записей (строк) исходной

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

тором) WHERE. Оператор WHERE является наиболее часто используемым,

хотя и необязательным в SQL-выражениях. Кроме WHERE, в SQL-

19

выражениях используются и другие операторы, позволяющие уточнить за-

прос.

Для уточнения запроса на выборку данных служит ряд дополнитель-

ных операторов:

WHERE (где) – указывает записи, которые должны войти в результат-

ную таблицу (фильтр записей);

GROUP BY (группировать по) – группирует записи по значениям

определенных столбцов;

HAVING (имеющие, при условии) – указывает группы записей, кото-

рые должны войти в результатную таблицу (фильтр групп);

ORDER BY (сортировать по) – сортирует (упорядочивает) записи.

Эти операторы не являются обязательными. Их можно совсем не ис-

пользовать, или использовать лишь некоторые из них, или все сразу. Если

применяются несколько операторов, то в SQL-выражении они использу-

ются в указанном в списке порядке.

Таким образом, запрос данных из таблицы с применением всех пере-

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

FROM имяТаблиы

WHERE условиеПоиска

GROUP BY столбецГруппировки

HAVING условиеПоиска

ORDER BY условиеСортировки;

Порядок перечисления операторов в SQL-выражении не совпадает с

порядком их выполнения. Однако знание порядка выполнения операторов

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

ры SQL-выражения выполняются в следующем порядке, передавая друг

другу результат в виде таблицы:

1. FROM – выбирает таблицу из базы данных; если указано несколько таб-

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

лица передается для обработки следующему оператору.

2. WHERE – из таблицы выбираются записи, отвечающие условию поиска,

и отбрасываются все остальные.

3. GROUP BY – создаются группы записей, отобранных с помощью опера-

тора WHERE (если он присутствует в SQL-выражении); каждая группа

соответствует какому-нибудь значению столбца группирования. Стол-

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

операторе FROM, а не только тем, который указан в SELECT.

4. HAVING – обрабатывает каждую из созданных групп записей, оставляя

только те из них, которые удовлетворяют условию поиска; этот оператор

используется только вместе с оператором GROUP BY.

20

5. SELECT – выбирает из таблицы, полученной в результате применения

перечисленных операторов, только указанные столбцы.

6. ORDER BY – сортирует записи таблицы.

2.2. Форма оператора SELECT для простой выборки данных

Тривиальный запрос, возвращающий все данные (все столбцы и все

записи) из одной таблицы, формулируется так: SELECT *

FROM имяТаблицы;

Например, получим все сведения обо всех авторах: SELECT *

FROM authors;

Может потребоваться выбрать не все столбцы таблицы, а только не-

которые. Тогда SQL-запрос будет выглядеть так: SELECT списокСтолбцов

FROM имяТаблицы;

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

они определены в таблице, указанной в выражении FROM. Можно указать

все или только некоторые столбцы в любом порядке. Возможно также ука-

зать один и тот же столбец несколько раз.

Например, получим фамилии и имена всех авторов: SELECT last_name, first_name

FROM authors;

Сразу за оператором SELECT до списка столбцов можно применять

ключевые слова ALL (все) и DISTINCT (отличающиеся), которые указы-

вают, какие записи представить в результатной таблице. Если эти ключе-

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

записи, что также соответствует применению ключевого слова ALL. В слу-

чае использования DISTINCT в результатной таблице представляются

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

несколько идентичных записей, то из них выбирается только первая.

Например, получим все имена, которые встречаются среди авторов: SELECT DISTINCT first_name

FROM authors;

Существует и еще одна форма оператора DISTINCT с явным пере-

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

словом DISTINCT следует секция ON (списокСтолбцов).

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

указанием одной из фамилий, соответствующих каждому имени:

21

SELECT DISTINCT ON (first_name)

first_name, last_name

FROM authors;

Заголовки столбцов в результатной таблице можно переопределить

по своему усмотрению, назначив для них так называемые псевдонимы (си-

нонимы). Для этого в списке столбцов после соответствующего столбца

следует написать выражение вида: AS заголовокСтолбца

Назначение синонима не влияет на исходное поле и действует лишь в кон-

тексте итогового набора, возвращаемого запросом.

Например, SELECT last_name AS Фамилия, first_name AS Имя

FROM authors;

Псевдонимы также можно задать и для каждой таблицы после клю-

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

сразу (или с использованием слова AS) после имени соответствующей

таблицы. Псевдонимы таблиц, более короткие, чем их имена, удобно ис-

пользовать в сложных запросах.

Например, SELECT *

FROM authors a;

или SELECT *

FROM authors As a;

В списке столбцов оператора SELECT могут быть не только простые

поля, но и произвольные выражения (включающие вызовы функций или

различные операции с идентификаторами) и константы.

Например, получим в одном столбце и фамилию, и имя автора, ис-

пользуя оператор конкатенации (слияния) строк: SELECT last_name || ' ' || first_name AS name

FROM authors;

Команда SELECT также может использоваться для простого вычис-

ления и вывода результатов выражений и констант. В этом случае она не

содержит секции FROM.

Например, SELECT 2+2 AS "2 plus 2",

pi() AS "the pi function",

'PostgreSQL is more than a calculator!' AS

comment;

Перечень операторов и функций, доступных в СУБД PostgreSQL, см.

в приложении (П.5. Операторы, П.6. Функции).

22

2.3. Сортировка записей

Записи хранятся в таблицах в произвольном порядке. Более того, да-

же повторное выполнение запроса никоим образом не гарантирует одина-

кового порядка следования возвращаемых записей. Однако упорядочение

данных играет важную роль при выборке, поэтому в SQL поддерживается

конструкция ORDER BY, являющаяся гибким средством сортировки ито-

гового набора.

Секции ORDER BY передается список полей, разделенный запятыми

(или выражений, в которых используются поля). Переданный список зада-

ет критерий сортировки. Для каждого критерия сортировки могут допол-

нительно указываться ключевые слова ASC и DESC, управляющие типом

сортировки.

ASC. Записи сортируются по возрастанию заданного критерия (то

есть числа сортируются от меньших к большим, даты – от ранних к

поздним, а текст – по алфавиту). По умолчанию выбирается именно

этот способ сортировки, поэтому ASC используется лишь для

наглядности.

DESC. Записи сортируются по убыванию заданного критерия (то

есть числа сортируются от больших к меньшим, даты – от поздних

к ранним, а текст – в порядке, обратном алфавитному).

Например, получим фамилии и имена всех авторов с сортировкой по

фамилии: SELECT last_name, first_name

FROM authors

ORDER BY last_name;

При сортировке допускается использование полей, отсутствующих в

целевом списке оператора SELECT. Более того, если запрос связан с агре-

гированием, секция ORDER BY может содержать вызовы агрегатных

функций и выражения.

Например, получим фамилии и имена всех авторов с сортировкой по

идентификационному номеру: SELECT last_name, first_name

FROM authors

ORDER BY id;

При сортировке по нескольким выражениям сначала производится

упорядочивание итогового набора по первому (левому) критерию, а даль-

нейшие критерии применяются лишь в том случае, если сортировка по

первому критерию не обеспечивает однозначного результата.

Например, получим фамилии и имена всех авторов с сортировкой по

фамилии, а если фамилии совпадают, то и по именам:

23

SELECT last_name, first_name

FROM authors

ORDER BY last_name, first_name;

При сортировке по нескольким критериям для каждого критерия

можно задать свой тип упорядочивания.

Например, получим номера изданий и даты изданий так, чтобы но-

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

бы те, которые изданы недавно: SELECT edition, publication

FROM editions

ORDER BY edition ASC, publication DESC;

Секция ORDER BY обрабатывается перед удалением дубликатов

ключевым словом DISTINCT. Этот факт позволяет с помощью сортировки

составить запрос, аналогичный по результату использованию агрегатных

функций max() или min().

Например, получим даты последних изданий для каждого номера

издания: SELECT DISTINCT ON (edition) edition, publication

FROM editions

ORDER BY edition ASC, publication DESC;

2.4. Выбор интервалов записей

Количество записей, выбираемых запросом SQL, не ограничивается.

Обработка запроса, возвращающего несколько миллионов записей, займет

много времени, но сервер не остановится, пока не вернет весь итоговый

набор (или процесс не будет прерван извне).

В SQL предусмотрены ключевые слова LIMIT и OFFSET, упроща-

ющие выборку заданной части итогового набора.

Секция LIMIT ограничивает максимальное количество записей в

итоговом наборе (хотя размер итогового набора может быть меньше за-

данной величины).

Например, получим последние пять номеров isbn книг, которые

были изданы: SELECT isbn, publication

FROM editions

ORDER BY publication DESC

LIMIT 5;

При наличии секции OFFSET в итоговом наборе пропускается коли-

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

Например, получим isbn и даты изданий всех книг, кроме послед-

них пяти изданных:

24

SELECT isbn, publication

FROM editions

ORDER BY publication DESC

OFFSET 5;

Если заданы оба ключевых слова, и LIMIT, и OFFSET, то отсчет

ограничения, указанного в секции LIMIT, начинается после пропуска за-

писей в соответствии с секцией OFFSET.

Например, получим предпоследние (т.е. не учитывая самую послед-

нюю книгу) пять номеров isbn книг, которые были изданы: SELECT isbn, publication

FROM editions

ORDER BY publication DESC

LIMIT 5

OFFSET 1;

2.5. Условные выражения с оператором CASE

В обычных языках программирования имеются операторы условного

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

языке SQL таким оператором является CASE. Этот оператор возвращает

значение и, следовательно, может использоваться в выражениях. Он имеет

две основные формы.

2.5.1. Оператор CASE со значениями

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

CASE проверяемое_значение

WHEN значение1 THEN результат1

WHEN значение2 THEN результат2

...

WHEN значениеN THEN результатN

ELSE результатX

END

В случае, когда проверяемое_значение равно значение1, опе-

ратор CASE возвращает значение результат1, указанное после ключево-

го слова THEN. В противном случае проверяемое_значение сравнива-

ется с значение2, и если они равны, то возвращается значение резуль-

тат2. В противном случае проверяемое_значение сравнивается со

следующим значением, указанным после ключевого слова WHEN и т.д. Ес-

ли проверяемое_значение не равно ни одному из таких значений, то

25

возвращается значение результатХ, указанное после ключевого слова

ELSE.

Ключевое слово ELSE не является обязательным. Если оно отсут-

ствует и ни одно из значений, подлежащих сравнению, не равно проверяе-

мому значению, то оператор CASE возвращает NULL.

Например, вместо номера издания в виде числа выведем номер изда-

ния в виде текстовой строки: SELECT isbn,

CASE edition

WHEN 1 THEN 'first'

WHEN 2 THEN 'second'

WHEN 3 THEN 'third'

ELSE 'large then 3'

END AS edition_num

FROM editions;

2.5.2. Оператор CASE с условием поиска

Вторая форма оператора CASE предполагает его использование при

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

условию: CASE

WHEN условие1 THEN результат1

WHEN условие2 THEN результат2

...

WHEN условиеN THEN результатN

ELSE результатX

END

Оператор CASE проверяет, истинно ли условие1 для первой записи

в таблице. Если да, то CASE возвращает значение результат1. В про-

тивном случае для данной записи проверяется условие2. Если оно ис-

тинно, то возвращается значение результат2 и т.д. Если ни одно из

условий не выполняется, то возвращается значение результатХ, указан-

ное после ключевого слова ELSE.

Ключевое слово ELSE не является обязательным. Если оно отсут-

ствует и ни одно из условий не выполняется, оператор CASE возвращает

NULL. После того как оператор, содержащий CASE, выполнится для пер-

вой записи, происходит переход к следующей записи. Так продолжается до

тех пор, пока не будет обработан весь набор записей.

Например, вместо номера издания в виде числа выведем номер изда-

ния в виде текстовой строки:

26

SELECT isbn,

CASE

WHEN edition = 1 THEN 'first'

WHEN edition = 2 THEN 'second'

WHEN edition = 3 THEN 'third'

ELSE 'large then 3'

END AS edition_num

FROM editions;

2.6. Функция COALESCE

В ряде случаев, особенно в запросах на обновление данных (опера-

тор UPDATE), удобно использовать вместо громоздкого оператора CASE

более компактную функцию COALESCE.

Функция COALESCE(значение1, значение2, ..., значе-

ниеN) принимает список значений, которые могут быть как определен-

ными, так и неопределенными (NULL). Функция возвращает первое опре-

деленное значение из списка. Если все значения окажутся неопределенны-

ми, функция возвращает NULL.

Например, заменим все NULL-значения поля location на значение

'не определено':

SELECT id, subject,

coalesce(location, 'не определено')

FROM subjects;

27

Лабораторная работа 2

Подключиться к базе данных booktown и выполнить следующие

запросы:

1. Все сведения о книгах.

2. Все сведения об изданиях книг.

3. Код и название всех книг.

4. ISBN, номер издания, дата издания и тип обложки для всех изданий.

5. Неповторяющиеся коды издательств, выпускавших книги.

6. Неповторяющиеся коды тем, по которым написаны книги.

7. Для каждого кода ISBN получить прибыль магазина в случае продажи

всех имеющихся в наличии экземпляров.

8. Названия всех книг, упорядоченные по алфавиту.

9. Фамилии и имена всех покупателей, отсортированные по алфавиту

(если есть однофамильцы, то они должны быть отсортированы по

именам).

10. Список всех ISBN с указанием розничной цены, упорядоченный от

самых дорогих к самым дешевым.

11. Код ISBN и затраты магазина на закупку соответствующих имеющих-

ся в наличии книг. Упорядочить по стоимости закупки (всех имею-

щихся экземпляров).

12. Код ISBN, номер издания и дата издания для всех книг в таком поряд-

ке, чтобы сначала шли книги, издававшиеся наибольшее количество

раз. Книги с одним и тем же количеством изданий упорядочить по да-

те издания.

13. Код ISBN и имеющееся количество для десяти книг, в наибольшем

количестве имеющихся на складе.

14. Все данные о последних пяти покупках.

15. Все данные о первых семи покупках, не считая трех самых первых

(т.е. следующие семь после первых трех).

16. Самая дорогая цена (розничная) книги.

17. Самая малая разница между ценой закупки и ценой продажи.

18. Код ISBN и название типа обложки («твердая» / «мягкая») для всех

изданий. Упорядочить по названию типа обложки.

19. Код ISBN, цена закупки, цена продажи, величина наценки, процент

наценки и класс всех книг. Если цена продажи более, чем на 10 %

превышает цену закупки, то класс – «VIP», иначе – «эконом». Упоря-

дочить по убыванию процента наценки.

28

3. УТОЧНЕНИЕ ЗАПРОСА

3.1. Секция WHERE

Основное выражение для выборки данных имеет вид: SELECT списокСтолбцов

FROM списокТаблиц;

Такой запрос возвращает таблицу, полученную из указанной в опе-

раторе FROM путем выделения в ней только тех столбцов, которые опреде-

лены в операторе SELECT.

Для выделения требуемых записей (строк) исходной таблицы ис-

пользуется выражение, следующее за ключевым словом WHERE. Условия

поиска в операторе WHERE являются логическими выражениями, т.е. при-

нимающими одно из двух возможных значений – true (ИСТИНА) или

false (ЛОЖЬ).

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

У этих книг поле subject_id равно 4. Соответственно в секцию WHERE

включается оператор =, который проверяет это условие:

SELECT *

FROM books

WHERE subject_id = 4;

Выражение subject_id = 4 является истинным (имеет значение

true), если в текущей записи таблицы значение столбца subject_id

равно 4. В противном случае это выражение ложно (имеет значение

false). Одно и то же логическое выражение может быть истинным для

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

принимать еще и неопределенное значение. Это происходить тогда, когда

в выражении некоторые элементы имеют значение NULL. Таким образом,

SQL имеет дело не с классической двухзначной, а с трехзначной логикой.

Секция WHERE может содержать несколько условий, объединенных

логическими операторами (например, AND или OR) и возвращающими од-

но логическое значение.

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

кроме того, что они о компьютерах, написаны Марком Лутцем. Запрос

уточняется объединением двух условий при помощи логического операто-

ра AND: SELECT title

FROM books

WHERE subject_id = 4 AND author_id = 7805;

29

Первое условие проверяет, что книга посвящена компьютерным тех-

нологиям (поле subject_id равно 4), а второе – что автором книги явля-

ется Марк Лутц (поле author_id равно 7805). Объединение условий

уменьшает объем итогового набора.

Получим все книги, посвященные компьютерным технологиям или

искусству; в этом случае два условия объединяются логическим операто-

ром OR.

SELECT title

FROM books

WHERE subject_id = 4 OR subject_id = 0;

Прежнее первое условие (книги по компьютерной тематике) объеди-

няется со вторым условием: книги по искусству (поле subject_id рав-

но 0). В результате объем итогового набора увеличивается, каждая его за-

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

Количество условий, объединяемых в секции WHERE, не ограничено,

хотя при наличии двух и более условий обычно задается порядок выпол-

нения сравнений при помощи круглых скобок.

3.2. Предикаты

При составлении логических выражений используются специальные

ключевые слова и символы операций сравнения, которые называют преди-

катами. Наиболее часто используются предикаты сравнения, такие как (=),

(<), (>), (<>), (<=) и (>=). Однако имеются и другие. Далее приведен спи-

сок всех предикатов:

предикаты сравнения (=), (<), (>), (<>), (<=) и (>=);

BETWEEN;

IN, NOT IN;

LIKE, NOT LIKE;

IS NULL;

ALL, SOME, ANY;

EXISTS;

UNIQUE;

DISTINCT;

OVERLAPS;

MATCH;

SIMILAR.

30

3.2.1. Between

Предикат BETWEEN позволяет задать выражение проверки вхожде-

ния какого-либо значения в диапазон, определяемый граничными значени-

ями. Например, WHERE cost BETWEEN 100 AND 150

Здесь ключевое слово AND представляет собой логический союз И. Гра-

ничные значения (в примере это 100 и 150) входят в диапазон. Причем

первое граничное значение должно быть не больше второго.

Эквивалентным приведенному является выражение с предикатами

сравнения: WHERE cost >= 100 AND cost <= 150

Кроме данных числового типа, в выражениях с between можно ис-

пользовать данные следующих типов: символьные, битовые, даты-

времени. Например, чтобы выбрать записи, в которых фамилии авторов

находятся в диапазоне от A до G, можно использовать такое выражение:

SELECT first_name, last_name

FROM authors

WHERE last_name BETWEEN 'A' AND 'G';

3.2.2. IN и NOT IN

Предикаты IN и NOT IN применяются для проверки вхождения ка-

кого-либо значения в заданный список значений. Например, для выборки

записей о книгах некоторой тематики можно использовать такое выраже-

ние: SELECT title, author_id

FROM books

WHERE subject_id IN (7805, 0);

Если требуется получить данные о всех книгах не о компьютерах и

искусстве, то можно использовать предикат NOT IN:

SELECT title, author_id

FROM books

WHERE subject_id NOT IN (7805, 0);

3.2.3. LIKE и NOT LIKE

Предикаты LIKE и NOT LIKE применяются для проверки частично-

го соответствия символьных строк. Например, столбец Телефон в некото-

рой таблице содержит полные номера телефонов, и требуется выбрать

31

лишь те записи, в которых номера телефонов начинаются с 8112 или со-

держат такое сочетание цифр.

Критерий частичного соответствия задается с помощью двух симво-

лов-масок: знака процента (%) и подчеркивания (_). Знак процента означа-

ет любой набор символов, в том числе и пустой, а символ подчеркивания –

любой одиночный символ.

Например, чтобы выбрать записи об изданиях, у которых isbn

начинается с 044, можно использовать такое выражение: SELECT isbn, edition, publication

FROM edition

WHERE isbn LIKE '044%';

Если требуется выбрать записи о книгах про Python, то для этого

подойдет следующее выражение: SELECT title, author_id

FROM books

WHERE title LIKE '%Python%';

Если необходимо исключить все записи о книгах про Python, то

можно воспользоваться следующим выражением: SELECT title, author_id

FROM books

WHERE title NOT LIKE '%Python%';

3.2.4. SIMILAR

Предикат SIMILAR применяется для проверки частичного соответ-

ствия символьных строк. Эту же задачу можно решить и с помощью пре-

диката LIKE, однако в ряде случаев SIMILAR более эффективен.

Пусть в некоторой таблице имеется столбец OC, содержащий назва-

ния операционных систем. Нужно выбрать записи, соответствующие Win-

dows XP, Windows Vista и Windows 7. Тогда в выражении запроса можно

использовать такой оператор WHERE:

WHERE ОС SIMILAR TO 'Windows (XP|Vista|7)';

3.2.5. IS NULL

Предикат IS NULL применяется для выявления записей, в которых

тот или иной столбец не имеет значения. Например, для получения записей

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

следующее выражение:

32

SELECT id, subject

FROM subjects

WHERE location IS NULL;

Для получения записей, в которых столбец location содержит не-

которые определенные значения (т.е. отличные от NULL) можно использо-

вать аналогичное выражение, но с логическим оператором NOT:

SELECT id, subject

FROM subjects

WHERE location IS NOT NULL;

Не следует использовать предикаты сравнения с NULL, такие как

location = NULL.

3.2.6. OVERLAPS

Предикат OVERLAPS используется для определения, перекрываются

ли два интервала времени. Выражение с предикатом OVERLAPS можно за-

писать, например, так: (TIME '12:25:30', TIME '14:30:00') OVERLAPS

(TIME '12:45:00', INTERVAL '2' HOUR)

Поскольку временные интервалы в данном примере пересекаются, то пре-

дикат OVERLAPS возвращает значение true.

Предикаты для вложенных запросов ALL, SOME, ANY, EXISTS,

UNIQUE, DISTINCT будут рассмотрены в разделе "Сложные запросы".

Предикат MATCH применяется для проверки сохранения ссылочной

целостности при модификации данных, т.е. при добавлении, изменении и

удалении записей.

33

Лабораторная работа 3

Выполнить следующие запросы к базе данных booktown:

1. Вся информация о переиздании (т.е. не первое издание, а второе и вы-

ше) книг, так чтобы сначала списка шли книги, выдержавшие

наибольшее количество переизданий.

2. Вся информация об издании книг с типом h в порядке их публикации.

3. Информация об изданиях книг до XXI века.

4. Информация об имеющихся книгах на складе (stock). Отсортировать по

убыванию количества, отсутствующие книги не выводить.

5. Код ISBN и отпускная цена для книг с отпускной ценой в диапазоне от

20 до 30 в порядке возрастания цены.

6. Список покупателей, которых зовут Jean.

7. Код ISBN, имеющееся количество и отпускная цена для книг, имею-

щихся на складе в количестве, не меньшем 50, или с отпускной ценой,

меньшей 20.

8. Код ISBN, тип обложки и дата издания для книг в мягкой (бумажной)

обложке, изданных в период с 1990 по 2010 гг. Упорядочить по дате

издания.

9. Код ISBN, номер издания и дата издания для книг, изданных впервые

или в XXI веке.

10. Названия книг, написанных автором с кодом 1809 по теме с кодом 15.

11. Код ISBN и дата покупки для покупок в период с 10-го по 15 августа

2001 года. Отсортировать по дате покупки.

12. Названия книг и коды авторов для книг, написанных авторами с кода-

ми 1809, 7805, 1212, 15990 и 25041. Упорядочить по коду автора.

13. Названия книг и коды авторов для книг, написанных авторами, чьи но-

мера не 1809, 7805, 1212, 15990 и 25041. Упорядочить по коду автора.

14. Название темы и отдел для тем, расположенных в отделах Main St,

Black Raven Dr, Productivity Ave и Creativity St. Отсортировать по

названию темы.

15. Фамилия и имя авторов, имена которых начинаются на Marg.

16. Названия книг, в которых присутствует предлог in.

17. Названия книг, в которых присутствует The или the.

18. Названия книг, в которых нет ни The, ни the.

19. Фамилии авторов, чьи имена не известны.

20. Код темы, название темы и отдел для тем с кодом, большим 10, и из-

вестным отделом.

34

4. МНОГОТАБЛИЧНЫЕ ЗАПРОСЫ

4.1. Выбор источников в секции FROM

В секции FROM указывается источник данных – таблица или итого-

вый набор. Секция может содержать несколько источников, разделенных

запятыми. Результат подобного перечисления функционально эквивален-

тен перекрестному объединению.

Использование нескольких источников данных требует осторожно-

сти. В результате выполнения команды SELECT для нескольких источни-

ков без секций WHERE и JOIN, уточняющих связи между источниками,

возвращается полное декартово произведение источников. Итоговый набор

будет содержать все возможные комбинации записей из всех источников.

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

через запятую в секции FROM, используется секция WHERE.

Например, получим сведения о книгах и их авторах: SELECT books.id, title, authors.id, last_name

FROM books, authors

WHERE books.author_id = authors.id;

При использовании ссылок на имена полей, относящихся к разным

источникам, может возникнуть неоднозначность. Предположим, команда

SELECT получает исходные данные из таблиц books и authors. В каж-

дой из этих таблиц имеется поле с именем id. Без дополнительных уточ-

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

id в следующей команде:

SELECT id

FROM books, authors;

Для предотвращения неоднозначности в "полные" имена столбцов

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

называемый точечной записью (название связано с тем, что имя таблицы

отделяется от имени поля точкой). Например, books.id означает поле id

таблицы books.

Точечная запись обязательна только при наличии неоднозначности

между наборами данных. Ссылка может состоять только из имени поля –

при условии, что это имя уникально во всех наборах данных, перечислен-

ных в секции FROM. В приведенном выше примере поле title присут-

ствует только в таблице books, а поле last_name входит только в таб-

лицу authors, поэтому на их имена можно ссылаться без уточнения.

Источникам данных в секции FROM – таблицам, подзапросам и т.д. –

можно назначать синонимы в секции AS (по аналогии с отдельными поля-

35

ми). Синоним часто используется для упрощения точечной записи. Нали-

чие синонима для набора данных позволяет обращаться к нему при помо-

щи точечной записи, что делает команды SQL более компактными и

наглядными.

Например, получим сведения о книгах и их авторах с упрощением

точечной записи при помощи секции AS:

SELECT b.id, title, a.id, last_name

FROM books AS b, authors AS a

WHERE b.author_id = a.id;

Ключевое слово AS не является обязательным при назначении сино-

нима: SELECT b.id, title, a.id, last_name

FROM books b, authors a

WHERE b.author_id = a.id;

4.2. Операции соединения

Операции соединения наборов записей возвращают таблицы, записи

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

таблиц. Для этого используется оператор JOIN.

Довольно часто операции, основанные на операторе JOIN, называют

объединением таблиц (наборов записей). Однако термин "объединение"

лучше подходит для UNION – оператора теоретико-множественного объ-

единения записей, при котором записи исходных наборов не комбиниру-

ются (не соединяются) друг с другом, а просто к одному набору записей

добавляется другой набор. В случае оператора JOIN в результатную таб-

лицу попадают записи, полученные из разных наборов путем присоедине-

ния одной из них к другой. Поэтому операции, основанные на операторе

JOIN, будем называть операциями соединения таблиц (наборов записей).

4.2.1. Перекрестное соединение

Существуют несколько разновидностей соединения, которым соот-

ветствуют определенные ключевые слова, добавляемые к слову JOIN. Так,

например, декартово произведение является операцией перекрестного со-

единения. В SQL-выражении для обозначения этой операции используется

оператор CROSS JOIN. Результат перекрестного соединения принципи-

ально не отличается от перечисления источников через запятую.

Пусть в базе данных имеются следующие две таблицы:

36

Сотрудники (Номер_сотрудника, Фамилия, Имя, Но-

мер_отдела);

Отделы (Номер_отдела, Название).

Общим столбцом для этих таблиц является Номер_отдела. Декар-

тово произведение этих таблиц получается с помощью следующих эквива-

лентных запросов: SELECT *

FROM Сотрудники CROSS JOIN Отделы;

или SELECT *

FROM Сотрудники, Отделы;

На следующих рисунках показаны примеры таблиц Сотрудники и

Отделы, а также результат их декартового произведения.

Сотрудники

Номер_сотрудника Фамилия Имя Номер_отдела

1 Иванов Иван 1

2 Петров Петр 2

3 Сидоров Сидор 1

Отделы

Номер_отдела Название

1 Отдел автоматизации

2 Отдел кадров

Декартово произведение

Номер_

сотрудника

Фами-

лия Имя

Сотрудники.

Номер_

отдела

Отделы.

Номер_

отдела

Название

1 Иванов Иван 1 1 Отдел автома-

тизации

1 Иванов Иван 1 2 Отдел кадров

2 Петров Петр 2 1 Отдел автома-

тизации

2 Петров Петр 2 2 Отдел кадров

3 Сидоров Сидор 1 1 Отдел автома-

тизации

3 Сидоров Сидор 1 2 Отдел кадров

Синтаксис CROSS JOIN всего лишь более формально выражает от-

ношение между двумя наборами данных. Между синтаксисом CROSS

37

JOIN и простым перечислением таблиц через запятую нет никаких функ-

циональных различий.

В основе любого соединения наборов записей лежит операция их де-

картового произведения.

4.2.2. Естественное соединение

В полученном декартовом произведении интерес представляют не

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

значения (Сотрудники.Номер_отдела = Отделы.Номер_отдела).

Следовательно, в команде выборки с перекрестным соединением практи-

чески всегда должна присутствовать секция WHERE, уточняющая связи

между объединенными наборами данных. Кроме того, в результатной таб-

лице не нужны оба идентичных столбца, достаточно лишь одного из них.

Такая таблица и будет естественным соединением таблиц Сотрудники и

Отделы. Она получается с помощью следующего запроса:

SELECT Сотрудники.*, Отделы.Название

FROM Сотрудники, Отделы

WHERE Сотрудники.Номер_отдела = Отделы.Номер_отдела;

Данный запрос можно переписать, используя псевдонимы: SELECT T1.*, T2.Название

FROM Сотрудники T1, Отделы T2

WHERE T1.Номер_отдела = T2.Номер_отдела;

Эквивалентный запрос с оператором NATURAL JOIN:

SELECT T1.*, T2.Название

FROM Сотрудники T1 NATURAL JOIN Отделы T2;

Естественное соединение

Номер_

сотрудника Фамилия Имя Номер_отдела Название

1 Иванов Иван 1 Отдел автоматизации

2 Петров Петр 2 Отдел кадров

3 Сидоров Сидор 1 Отдел автоматизации

При естественном соединении, выполняемом с помощью оператора

NATURAL JOIN, проверяется равенство всех одноименных столбцов со-

единяемых таблиц.

38

4.2.3. Соединение по именам столбцов

Соединение по именам столбцов похоже на естественное соедине-

ние. Отличие состоит в том, что можно указать, какие одноименные

столбцы должны проверяться. В естественном соединении проверяются

все одноименные столбцы.

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

Коробки (Размер, Количество, Цвет);

Крышки (Размер, Количество, Цвет).

Предположим, нам нужны комплекты, в каждом из которых количе-

ства коробок и крышек одного размера совпадают, а их цвета могут быть

различными. Естественное соединение в этом случае не подойдет, по-

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

результатов не попадут комплекты из разноцветных коробок и крышек.

Поэтому следует использовать соединение по одинаковым именам только

столбцов Размер и Количество:

SELECT *

FROM Коробки JOIN Крышки USING (Размер, Количество);

После ключевого слова USING в круглых скобках указывается спи-

сок одноименных столбцов соединяемых таблиц, которые необходимо

проверять.

Приведенный выше запрос можно сформулировать иначе: SELECT *

FROM Коробки, Крышки

WHERE (Коробки.Размер = Крышки.Размер)

AND (Коробки.Количество = Крышки.Количество);

На следующих рисунках показаны таблицы Коробки и Крышки, а

также результат рассмотренного запроса.

Коробки Крышки

Размер Количество Цвет Размер Количество Цвет

3020 13 Белый 3020 13 Белый

3030 7 Белый 3030 3 Белый

3015 20 Синий 3015 20 Синий

2020 26 Красный 2020 26 Желтый

2020 29 Белый 2020 28 Красный

Комплекты

Размер Количество Цвет Размер Количество Цвет

3020 13 Белый 3020 13 Белый

3015 20 Синий 3015 20 Синий

2020 26 Красный 2020 26 Желтый

39

4.2.4. Условное соединение

Условное соединение позволяет соединить таблицы по произволь-

ным столбцам, не обязательно имеющим одинаковые имена. Кроме того, в

качестве условия соединения может выступать не только равенство, но во-

обще любое логическое выражение, которое записывается после ключево-

го слова ON. Если условие выполняется для текущей записи декартового

произведения исходных таблиц, то она входит в результатную таблицу.

Пусть в базе данных имеются следующие две таблицы:

Сотрудники (Номер, Фамилия, Имя, Номер_отдела);

Отделы (Номер, Название).

Тогда эти таблицы можно соединить: SELECT *

FROM Сотрудники JOIN Клиенты

ON (Номер_отдела = Отделы.Номер);

Допустимо также использовать для условного соединения инструк-

цию INNER JOIN ON.

Конструкция JOIN была включена в стандарт SQL для того, чтобы

условия соединения источников данных (условия ON) можно было отли-

чить от условий принадлежности записей к итоговому набору (условия

WHERE).

Например: SELECT *

FROM Сотрудники, Клиенты

WHERE (Номер_отдела = Отделы.Номер)

AND (Фамилия = 'Иванов');

и SELECT *

FROM Сотрудники JOIN Клиенты

ON (Номер_отдела = Отделы.Номер)

WHERE Фамилия = 'Иванов';

Две синтаксические формы функционально идентичны и возвраща-

ют одинаковые результаты. Синтаксис JOIN позволяет отделить критерий

связи источников от критерия выбора записей, поскольку связи определя-

ются только в секции ON. Это существенно упрощает чтение и модифика-

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

вия в секции WHERE.

40

4.2.5. Сложные соединения

Хотя одна секция JOIN соединяет всего два набора данных, на прак-

тике соединения не ограничиваются двумя источниками. За набором, со-

зданным посредством соединения, может следовать новая секция JOIN –

по аналогии с тем, как перечисляются через запятую источники данных.

Пример соединения нескольких источников данных: SELECT last_name, publisher, e.isbn, subject

FROM authors AS a

JOIN books AS b ON a.id = b.author_id

JOIN editions AS e ON b.id = e.book_id

JOIN publishers AS p ON e.publisher_id = p.id

JOIN subjects AS s ON b.subject_id = s.id;

Хотя таблица books участвует в соединении, ни одно из ее полей не

входит в итоговый набор. Включение таблицы books в секции JOIN

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

которых возвращаются в результате запроса, связываются с другими таб-

лицами через поле id таблицы books (кроме таблицы publishers, ко-

торая связывается с таблицей editions по полю publisher_id).

41

Лабораторная работа 4

Выполнить следующие запросы к базе данных booktown:

1. Код isbn, дата издания, цена продажи и количество экземпляров для

всех изданий на складе.

2. Дата покупки, код покупателя, дата издания, тип обложки для всех

покупок. Отсортировать по дате издания.

3. Дата покупки, фамилия и имя покупателя для всех покупок. Отсорти-

ровать по фамилии и имени покупателя.

4. Список авторов с названиями написанных ими книг, отсортированный

по авторам.

5. Список названий книг и фамилий их авторов с указанием темы, отсор-

тировать по названию книги.

6. Фамилия и имя покупателя, название купленной им книги для всех

покупок. Отсортировать по покупателям.

7. Все пары: название издательства, фамилия автора (произведение ко-

торого было издано данным издательством). Упорядочить по назва-

нию издательства.

8. Фамилия и имя покупателя, название издательства купленной им кни-

ги для всех покупок. Упорядочить по покупателю.

9. Список номеров ISBN и тип обложки для книг в бумажном переплете

с указанием издательств, выпустивших книгу; список отсортировать

по издательствам.

10. Фамилия автора и название тем, которые он отразил в своих произве-

дениях. Упорядочить по автору.

11. Код ISBN, название книги, фамилия автора, затраты магазина на за-

купку всех имеющихся в наличии экземпляров. Отсортировать так,

чтобы в начале списка шли самые малозатратные издания.

12. Название и число экземпляров книг, количество которых на складе

равно нулю. Упорядочить по названию.

13. Название и дата продажи книги, которая была куплена самой первой в

магазине.

14. Фамилия и имя автора книги, купленной предпоследней. Указать так-

же дату продажи.

15. Название книги, дата издания, первое или повторное издание для всех

изданий (если издание 1, то «первое»; иначе – «повторное»). Отсорти-

ровать по названию книги.

16. Название книги, издательство и тип обложки для книг, изданных из-

дательством Roc в твердом переплете. Упорядочить по названию кни-

ги.

17. Название и тема книг, относящихся к темам Science и Science Fiction.

Отсортировать по названию книги.

42

18. Названия книг, которые приобрела Annie Jackson (с указанием поку-

пателя).

19. Название и издатель книг, изданных не издательствами Ace Books,

Roc, Penguin, Doubleday, Random House.

20. Название книги и адрес издательства для книг, изданных не в городе

New York.

43

5. ИТОГОВЫЕ ЗАПРОСЫ

5.1. Агрегатные функции

Довольно часто требуется узнать, сколько записей соответствует то-

му или иному запросу, какова сумма значений некоторого числового

столбца, его максимальное, минимальное и среднее значение. Для этого

служат так называемые итоговые (статистические, агрегатные) функции.

Агрегатные функции – особый класс функций, применяемых сразу к не-

скольким записям набора данных, но возвращающим одно значение.

Обычно агрегатные функции используются в запросах с группировкой, но

также встречается их применение и в запросах без группирования. В этом

случае агрегатная функция обрабатывает все записи итогового набора.

Далее перечислены агрегатные функции, поддерживаемые в Post-

greSQL. Полный список агрегатных функций выводится в psql командой

\da.

avg(выражение) Среднее арифметическое значений выражения

для всех записей в группе

count(выражение) Количество записей в группе, для которых

значение выражения отлично от NULL

max(выражение) Максимальное значение выражения в группе

min(выражение) Минимальное значение выражения в группе

stddev(выражение) Среднеквадратичное отклонение значений вы-

ражения в группе

sum(выражение) Сумма значений выражения в группе

variance(выражение) Дисперсия значений выражения в группе

Термин выражение означает любой столбец в итоговом наборе или

любое выражение, выполняющее операцию с этим столбцом.

При использовании итоговых функций в списке столбцов в операто-

ре SELECT заголовки соответствующих им столбцов в результатной таб-

лице имеют вид Expr1001, Expr1002 и т.д. (или что-нибудь аналогич-

ное, в зависимости от реализации SQL). Однако возможно задать заголов-

ки для значений итоговых функций и других столбцов по своему усмотре-

нию. Для этого достаточно после имени столбца в операторе SELECT ука-

зать выражение вида AS заголовок_столбца.

Count(параметр) – возвращает количество записей, указанных в

параметре. Если требуется получить количество всех записей итогового

набора, то в качестве параметра следует указать символ звездочки (*). Ес-

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

44

ство записей, в которых этот столбец имеет значения, отличные от NULL.

Чтобы узнать, сколько различных значений содержит столбец, перед его

именем следует указать ключевое слово DISTINCT.

Например: SELECT count(location) AS set_locs,

count(ALL location) AS all_locs,

count(DISTINCT location) AS unique_locs,

count(*) AS all_rows

FROM subjects;

Результат запроса: set_locs all_locs unique_locs all_rows

15 15 7 16

Примеры использования других агрегатных функций: SELECT AVG(retail) AS средняя_цена

FROM stock;

SELECT MIN(reatail * 28.8) AS

минимальная_цена_в_долларах

FROM stock;

SELECT SUM(retail) AS общая_стоимость_редких_книг

FROM stock

WHERE stock < 10;

5.2. Группировка записей

Предложение GROUP BY в инструкции SELECT задает столбцы, ис-

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

группы содержат одно и то же значение заданного столбца (столбцов).

Выражение за ключевым словом GROUP BY может быть простым полем

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

полем. При перечислении нескольких полей или выражений, разделенных

запятыми, группировка записей производится по совпадению значений во

всех перечисленных выражениях. Появление секции GROUP BY в запросе

SQL приводит к тому, что все записи с одинаковым значением выражений,

заданных в предложении GROUP BY, группируются в одну запись. Если

предложение GROUP BY расположено после предложения WHERE, то со-

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

Необходимо понимать, что все целевые поля, указанные в секции

SELECT, участвующие в запросе с группировкой, но не указанные в сек-

45

ции GROUP BY, доступны лишь при выборке через агрегатную функцию.

Другими словами, при включении предложения GROUP BY в инструкцию

SELECT список выбора может состоять только из выражений, указанных в

предложении GROUP BY или из агрегатных функций.

Выведем количество книг, хранящихся в базе данных booktown для

каждого издательства: SELECT name AS publisher,

count(isbn) AS number_of_books

FROM editions AS e INNER JOIN publishers AS p

ON (e.publisher_id = p.id)

GROUP BY name;

Секция GROUP BY указывает на то, что записи объединенного набо-

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

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

count() подсчитывает в каждой группе количество непустых значений

поля isbn и возвращает результат – количество записей, объединенных в

каждую группу для одного издательства.

Получим количество книг, написанных авторами по каждой теме: SELECT last_name, first_name, subject,

count(title) AS number_of_books

FROM books AS b INNER JOIN authors AS a

ON (b.author_id = a.id)

INNER JOIN subjects AS s

ON(b.subject_id = s.id)

GROUP BY last_name, first_name, subject;

5.3. Отбор групп записей

Предложение HAVING, за которым следует условие отбора, опреде-

ляет группы строк, которые включаются в результатную таблицу. Условие

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

секции GROUP BY. Если некоторая группа не удовлетворяет условию от-

бора, то она не включается в результатную таблицу.

Разница между предложениями HAVING и WHERE заключается в том,

что условие отбора, заданное в предложении WHERE, применяется к от-

дельным записям перед объединением их в группы, а условие отбора пред-

ложения HAVING применяется к группам строк. Секция WHERE не может

содержать агрегатных функций. Условия же секции HAVING, наоборот,

основаны на агрегатных функциях, а не на условиях для отдельных запи-

сей.

46

Выведем количество книг, хранящихся в базе данных booktown,

для тех издательств, которые представлены двумя и более книгами: SELECT name AS publisher,

count(isbn) AS number_of_books

FROM editions AS e INNER JOIN publishers AS p

ON (e.publisher_id = p.id)

GROUP BY name

HAVING count(isbn)>1;

47

Лабораторная работа 5

Выполнить следующие запросы к базе данных booktown:

1. Общее количество книг на складе (stock).

2. Количество книг с розничной ценой выше 30.

3. Выручка магазина при реализации всех книг.

4. Средняя цена (cost) книги.

5. Средняя цена (cost) для имеющихся книг на складе (stock).

6. Даты наиболее ранней и наиболее поздней публикаций.

7. Количество совершенных покупок.

8. Количество покупателей, совершавших покупки.

9. Количество покупателей с различными фамилиями, совершавших по-

купки.

10. Количество авторов, написавших какие-либо книги.

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

12. Количество первых изданий, вторых и так далее. В таком же порядке.

13. Количество книг, которые приобрел каждый покупатель. Отсортиро-

вать по покупателю.

14. Список покупателей-однофамильцев с подсчетом их количества.

15. Количество кодов isbn, которые были изданы каждым издательством.

Отсортировать по названию издательства.

16. Количество книг различных названий, которые выпустило каждое из-

дательство. Отсортировать по названию издательства.

17. Количество кодов isbn, которые были изданы каждым издательством,

находящимся в городе New York. Отсортировать так, чтобы сначала

шли издательства, выпустившие наибольшее количество изданий (ко-

дов isbn).

18. Количество кодов isbn, которые были изданы каждым издательством,

находящимся в городе New York. Издательства, выпустившие менее

двух изданий (кодов isbn), не выводить. Отсортировать так, чтобы

сначала шли издательства, выпустившие наибольшее количество из-

даний (кодов isbn).

19. Первая дата публикации для каждого автора. Упорядочить по датам.

20. Фамилии авторов, чьи произведения не имеют изданий выше второго.

21. Фамилии авторов, все издания которых имеются в наличии в количе-

стве не менее 50 экземпляров.

22. Фамилии авторов, все книги которых выходили только в бумажной

обложке. Отсортировать по фамилии автора.

23. Наибольшее количество книг, написанных одним автором.

24. Наименьшее количество изданий, выпущенных одним издательством.

48

6. СЛОЖНЫЕ ЗАПРОСЫ

6.1. Теоретико-множественные операции

Над наборами записей, содержащихся в таблицах базы данных и/или

возвращаемых запросами, можно совершать теоретико-множественные

операции, такие как декартово произведение, объединение, пересечение и

вычитание.

6.1.1. Декартово произведение наборов записей

Запрос вида SELECT списокСтолбцов

FROM T1, T2, ..., Tn;

возвращает набор записей, полученный в результате декартового произве-

дения наборов записей из таблиц T1, T2, ..., Tn. Таблицы, указанные в

операторе FROM, могут быть как таблицами базы данных, так и виртуаль-

ными таблицами, возвращаемыми какими-нибудь запросами.

Иногда требуется получить декартово произведение таблицы самой

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

этой таблицы, например: SELECT списокСтолбцов

FROM MyTab T1, MyTab T2;

Попытка выполнить запрос: SELECT списокСтолбцов

FROM MyTab, MyTab;

приведет к ошибке.

В списке столбцов следует использовать полные имена с помощью

точечной записи.

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

ключевыми словами CROSS JOIN:

SELECT списокСтолбцов

FROM MyTab T1 CROSS JOIN MyTab T2;

Запросы на декартово произведение сами по себе очень редко ис-

пользуются. Они приобретают некоторый смысл, если применяются с сек-

цией WHERE.

Допустим, что имеется таблица Рейсы (Начальный_пункт, Ко-

нечный_пункт), содержащая сведения о том, из каких пунктов и в какие

можно попасть с помощью того или иного авиарейса.

49

Рейсы

Начальный_пункт Конечный_пункт

A B

A C

A F

B C

B G

B F

C E

C D

D H

Можно заметить, что из некоторых пунктов в другие можно попасть

только с пересадкой на другой рейс, т.е. через транзитный пункт. Следую-

щий запрос возвращает таблицу, содержащую сведения о достижимости

пунктов в точности через один транзитный пункт: SELECT T1.Начальный_пункт, T2.Конечный_пункт

FROM Рейсы T1, Рейсы T2

WHERE T1.Конечный_пункт = T2.Начальный_пункт;

Сначала запрос выполняет декартово произведение таблицы Рейсы

на эту же таблицу. В результате получается таблица с четырьмя столбца-

ми: T1.Начальный_пункт, T1.Конечный_пункт, T2.Начальный_

пункт, T2.Конечный_пункт. Затем из полученной таблицы выбирают-

ся такие записи, в которых T1.Конечный_пункт =

T2.Начальный_пункт. Это и есть пары пунктов, между которыми нахо-

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

ются только два: T1.Начальный_пункт и T2.Конечный_пункт. Ре-

зультат запроса приведен ниже.

Рейсы

Начальный_пункт Конечный_пункт

A C

A G

A F

A E

A D

B E

B D

C H

50

6.1.2. Объединение наборов записей

Нередко требуется объединить наборы записей двух или более таб-

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

писей, возвращаемых одним запросом, требуется добавить записи, возвра-

щаемые другим запросом. Для этого служит оператор UNION:

Запрос1

UNION

Запрос2;

При этом в результатной таблице остаются только отличающиеся за-

писи. Чтобы сохранить в ней все записи, следует после оператора UNION

написать ключевое слово ALL.

Например, таблицы Коробки и Крышки имеют однотипные столб-

цы Размер, Количество и Цвет. Тогда, чтобы получить общий список

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

прос: SELECT Размер, Количество, Цвет

FROM Коробки

UNION

SELECT Размер, Количество, Цвет

FROM Крышки;

Оператор UNION можно применять только к таблицам, удовлетво-

ряющим следующим условиям совместимости:

количества столбцов объединяемых таблиц должны быть равны;

данные в соответствующих столбцах объединяемых таблиц должны

иметь совместимые типы данных. Например, символьные (строко-

вые) типы CHAR и VARCHAR совместимы, а числовой и строковый

типы не совместимы.

Имена соответствующих столбцов и их размеры могут быть различ-

ными. Важно, чтобы количества столбцов были равны, а их типы были

совместимы.

Пусть требуется получить сведения о том, в какие пункты можно

попасть, сделав не более одной пересадки (т.е. без пересадок или с одной

пересадкой). Для этого достаточно объединить записи исходной таблицы

Рейсы с результатом запроса о достижимости через один промежуточный

пункт: SELECT Начальный_пункт, Конечный_пункт

FROM Рейсы

UNION

SELECT T1.Начальный_пункт, T2.Конечный_пункт

FROM Рейсы T1, Рейсы T2

WHERE T1.Конечный_пункт = T2.Начальный_пункт;

51

6.1.3. Пересечение наборов записей

Пересечение двух наборов записей осуществляется с помощью опе-

ратора INTERSECT, возвращающего таблицу, записи которой содержатся

одновременно в двух наборах: Запрос1

INTERSECT

Запрос2;

При этом в результатной таблице остаются только отличающиеся за-

писи. Чтобы сохранить в ней повторяющиеся записи, следует после опера-

тора INTERSECT написать ключевое слово ALL.

Если требуется получить список коробок, для которых есть совпа-

дающие по размеру, количеству и цвету крышки, то можно воспользовать-

ся следующим запросом: SELECT Размер, Количество, Цвет

FROM Коробки

INTERSECT

SELECT Размер, Количество, Цвет

FROM Крышки;

6.1.4. Вычитание наборов записей

Для получения записей, содержащихся в одном наборе и отсутству-

ющих в другом, служит оператор EXCEPT: Запрос1

EXCEPT

Запрос2;

Чтобы узнать, для всех ли коробок есть соответствующие им по раз-

меру, количеству и цвету крышки, можно воспользоваться следующим за-

просом: SELECT Размер, Количество, Цвет

FROM Коробки

EXCEPT

SELECT Размер, Количество, Цвет

FROM Крышки;

Возвращенные этим запросом записи будут содержать сведения о

коробках, для которых нет подходящих крышек. Если же запрос вернет

пустую таблицу, то это будет означать, что для всех коробок есть соответ-

ственные крышки.

52

6.2. Внешние соединения

Все соединения таблиц, рассмотренные ранее, являются внутренни-

ми. Во всех примерах вместо ключевого слова JOIN можно писать INNER

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

все записи, у которых нет соответствующих строк одновременно в обеих

исходных таблицах. При внешнем соединении (OUTER JOIN) несоответ-

ствующие строки сохраняются. В этом и заключается отличие внешнего

соединения от внутреннего.

В запросе, имеющем соединение, будем называть таблицу левой, ес-

ли ее имя в операторе запроса предшествует ключевому слову JOIN, и

правой, если ее имя следует за словом JOIN.

Внешнее соединение может сохранить записи, для которых не нахо-

дится соответствия в другом наборе. В этом случае недостающие поля за-

полняются значением NULL. Решение о том, войдет ли такая запись в ре-

зультат внешнего соединения, зависит от того, в каком из соединяемых

наборов (таблиц) отсутствуют данные, и от типа внешнего соединения.

Существуют три разновидности внешних соединений.

6.2.1. Левое внешнее соединение

Операция LEFT JOIN (LEFT OUTER JOIN) возвращает все строки

из левой таблицы, соединенные с теми строками из правой таблицы, для

которых выполняется условие соединения. Если во второй таблице нет та-

ких строк, то в качестве значений столбцов правой таблицы будут уста-

новлены значения NULL.

В базе данных booktown в таблице books содержится общая ин-

формация о книгах, а в таблице editions хранятся данные, относящиеся

к конкретному изданию – код ISBN, издатель и дата публикации. В табли-

цу editions входит поле book_id, связывающее ее с полем id, кото-

рое является первичным ключом таблицы books.

Допустим, требуется информация о каждой книге вместе со всеми

имеющимися кодами ISBN: SELECT title, isbn

FROM books INNER JOIN editions

ON (books.id = editions.book_id);

Если у книги нет печатного издания (или информация об этом изда-

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

в результат данного запроса.

Чтобы получить данные о каждой книге, следует воспользоваться

следующим запросом:

53

SELECT title, isbn

FROM books LEFT OUTER JOIN editions

ON (books.id = editions.book_id);

Теперь в итоговом наборе будут присутствовать и те книги, у кото-

рых отсутствуют коды ISBN. В этом запросе использовано левое внешнее

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

книг, для которых существуют или не существуют коды ISBN. Поскольку

таблица books стоит слева от ключевого слова JOIN, задача решается при

помощи левого внешнего соединения.

6.2.2. Правое внешнее соединение

Операция RIGHT JOIN (RIGHT OUTER JOIN) возвращает все

строки из правой таблицы, соединенные с теми строками из левой табли-

цы, для которых выполняется условие соединения. Если во второй таблице

нет таких строк, то в качестве значений столбцов правой таблицы будут

установлены значения NULL.

В качестве примера получим названия книг, у которых нет кодов

ISBN: SELECT title

FROM editions RIGHT JOIN books

ON (editions.book_id = books.id)

WHERE isbn IS NULL;

6.2.3. Полное внешнее соединение

Операция FULL OUTER JOIN выполняет одновременно и левое, и

правое внешние соединения. В итоговом наборе наряду с соответствую-

щими записями сохраняются и несоответствующие строки как из левой,

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

наборе, заполняются значением NULL.

Если бы помимо названий всех книг (в том числе и не имеющих ко-

дов ISBN) нас интересовали коды ISBN (в том числе и не соответствую-

щие зарегистрированным в базе данных книгам), следовало бы воспользо-

ваться полным внешним соединением: SELECT title, isbn

FROM books FULL OUTER JOIN editions

ON (books.id = editions.book_id);

Ключевое слово OUTER во внешних соединениях PostgreSQL являет-

ся необязательным. Определения LEFT JOIN, RIGHT JOIN и FULL

JOIN подразумевают внешнее соединение.

54

6.3. Подзапросы

Подзапросом называется команда SELECT, заключенная в круглые

скобки, которая выполняется в контексте другой команды SQL. Обычно

подзапросы содержатся в условии оператора WHERE или HAVING внешне-

го запроса. В свою очередь, подзапрос может содержать другой подзапрос

и т.д.

6.3.1. Простые подзапросы

Простые подзапросы характеризуются тем, что они формально никак

не связаны с содержащими их внешними запросами. Это обстоятельство

позволяет сначала выполнить подзапрос, результат которого затем исполь-

зуется для выполнения внешнего запроса. Кроме простых подзапросов,

существуют еще и связанные подзапросы.

Рассматривая простые подзапросы, следует выделить три частных

случая:

подзапросы, возвращающие единственное значение;

подзапросы, возвращающие список значений из одного столбца таб-

лицы;

подзапросы, возвращающие набор записей.

Работа с единственным значением

Пусть требуется выбрать данные о тех изданиях, цена которых

больше среднего значения. Это можно сделать с помощью следующего за-

проса: SELECT *

FROM editions

WHERE cost > (SELECT AVG(cost)

FROM editions);

В данном запросе сначала выполняется подзапрос (SELECT AVG(cost)

FROM editions). Он возвращает единственное значение (а не набор за-

писей) – среднее значение столбца cost. Точнее, данный подзапрос воз-

вращает единственную запись, содержащую единственное поле. Далее вы-

полняется внешний запрос, который выводит все столбцы таблицы edi-

tions и записи, в которых значение столбца cost больше значения, по-

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

подзапрос, а затем внешний запрос, использующий результат подзапроса.

55

Работа со списком значений из одного столбца

Рассмотрим применение подзапросов, возвращающих не единствен-

ное значение, а список значений из одного столбца. Получим все данные о

покупках, которые совершили покупатели с именем James: SELECT *

FROM shipments

WHERE customer_id IN (SELECT id

FROM customers

WHERE first_name = 'James');

Сначала выполняется подзапрос, возвращающий список идентифи-

каторов покупателей, которых зовут James. Далее, внешний запрос сравни-

вает значение поля customer_id из каждой записи таблицы shipments

с полученным списком. Если сравнение успешно (сравниваемое значение

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

Теперь сформулируем запрос, возвращающий коды ISBN, книги с

которыми никто не покупал: SELECT isbn

FROM editions

WHERE isbn NOT IN (SELECT isbn

FROM shipments);

Чтобы секция IN сравнивала несколько полей, следует сгруппиро-

вать их имена в круглые скобки в секции WHERE непосредственно перед

IN. Сгруппированные поля должны соответствовать полям целевого спис-

ка подзапроса как по количеству, так и по типу данных.

Например, получим данные обо всех книгах в бумажной обложке,

отсутствующих на складе: SELECT isbn, cost, retail

FROM stock

WHERE (isbn, stock) IN (SELECT isbn, 0

FROM editions

WHERE type = 'p');

Подзапрос к таблице editions группирует поле isbn с целочис-

ленной константой 0 для всех книг в бумажной обложке. Возвращаемые

подзапросом записи сравниваются с полем isbn и stock таблицы stock

с использованием ключевого слова IN.

Пусть подзапрос возвращает несколько записей. Тогда чтобы в усло-

вии внешнего оператора WHERE можно было использовать операторы

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

ALL и SOME (ANY).

Получим список книг с самой высокой ценой:

56

SELECT *

FROM stock AS s1

WHERE s1.retail >= ALL (SELECT s2.retail

FROM stock AS s2);

Подзапрос SELECT s2.retail FROM stock AS s2 возвращает

список цен всех книг. Выражение >= ALL означает, что внешний запрос

должен вернуть только те записи, в которых значение столбца retail

больше или равен каждого значения, возвращенного вложенным подзапро-

сом.

Итоговый набор книг будет иным, если вместо квантора ALL приме-

нить SOME или ANY:

SELECT *

FROM stock AS s1

WHERE s1.retail > SOME (SELECT s2.retail

FROM stock AS s2);

Этот запрос вернет список книг, цена которых выше цены хотя бы

одной какой-либо книги.

Работа с набором записей

Вообще говоря, подзапрос может быть вставлен не только в операто-

ры WHERE и HAVING, но и в оператор FROM. В этом случае подзапросу

необходимо присвоить псевдоним.

Допустим, что имеется таблица Рейсы (Начальный_пункт, Ко-

нечный_пункт), содержащая сведения о том, из каких пунктов и в какие

можно попасть с помощью того или иного авиарейса. Получим сведения, в

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

пересадок или с одной пересадкой), только из пункта А: SELECT *

FROM

(SELECT Начальный_пункт, Конечный_пункт

FROM Рейсы

UNION

SELECT T1.Начальный_пункт, T2.Конечный_пункт

FROM Рейсы T1, Рейсы T2

WHERE T1.Конечный_пункт = T2.Начальный_пункт) AS T

WHERE T.Начальный_пункт = 'A';

6.3.2. Связанные подзапросы

Связанные (коррелированные) подзапросы позволяют выразить бо-

лее сложные вопросы относительно сведений, хранящихся в базе данных.

При выполнении запросов, содержащих связанные подзапросы, нет такого

57

четкого разделения по времени выполнения между подзапросом и запро-

сом, как в случае простых подзапросов. В случае простых подзапросов

сначала выполняется подзапрос, а затем содержащий его запрос. При

наличии связанного подзапроса порядок выполнения запроса в целом

иной. Основной признак связанного подзапроса заключается в том, что он

не может быть выполнен самостоятельно, вне всякой связи с основным за-

просом. Формально этот признак обнаруживается в выражении сложного

запроса следующим образом: подзапрос ссылается на таблицу, которая

упоминается в основном запросе.

Рассмотрим некоторый абстрактный и, в то же время, типичный за-

прос, содержащий связанный подзапрос: SELECT T1.A

FROM T1

WHERE T1.B = (SELECT T2.B

FROM T2

WHERE T2.C = T1.C);

Данный запрос на выборку данных содержит подзапрос, сформули-

рованный в выражении, размещенном в основном запросе после ключево-

го слова WHERE. Запрос в целом использует две таблицы: T1 и T2, в кото-

рых есть столбцы с одинаковыми именами B и C и одинаковыми типами.

Подзапрос (SELECT T2.B FROM T2 WHERE T2.C = T1.C) обраща-

ется к этим же таблицам. Поскольку одна из таблиц (T1) фигурирует как в

подзапросе, так и во внешнем запросе, то подзапрос нельзя выполнить са-

мостоятельно, вне связи с внешним запросом. Поэтому выполнение запро-

са в целом (т.е. внешнего запроса) происходит следующим образом:

1. Сначала выделяется первая запись из таблицы T1, указанной в опе-

раторе FROM внешнего запроса (вся запись таблицы T1, а не только

значение столбца A). Эта запись называется текущей. Значения

столбцов для этой записи доступны и могут быть использованы в

подзапросе.

2. Затем выполняется подзапрос, который возвращает список значе-

ний столбца B таблицы T2 в тех записях, в которых значение

столбца C равно значению столбца C из таблицы T1.

3. Будем считать, что в этом примере подзапрос возвращает един-

ственное значение. Если это не так, то потребуется использование,

например, предикатов вместо оператора сравнения (=). Теперь вы-

полняется оператор WHERE основного запроса. Если значение

столбца B в текущей (выделенной) записи таблицы T1 равно значе-

нию, возвращенному подзапросом, то эта запись выделяется внеш-

ним запросом.

4. Оператор SELECT внешнего запроса выполняет проверку условия

своего оператора WHERE. Если оно истинно, то значение столбца A

58

текущей записи таблицы T1 помещается в результатную таблицу, в

противном случае запись игнорируется. Затем происходит переход

к следующей записи таблицы T1. Теперь для нее выполняется под-

запрос. Аналогичным образом все описанное происходит для каж-

дой записи таблицы T1.

Получим, например, список покупателей, когда-либо делавших по-

купки: SELECT last_name, first_name

FROM customers

WHERE (SELECT count(isbn)

FROM shipments

WHERE customer_id = customers.id) >= 1;

Как известно, запрос возвращает одну или несколько записей либо

не возвращает ничего. Рассмотрим пример, в котором требуется проверка

существования записей. Так, иногда требуется выборка записей из одной

таблицы при условии, что в другой таблице существует хотя бы одна соот-

ветствующая запись.

Итак, получим список покупателей, когда-либо делавших покупки: SELECT last_name, first_name

FROM customers

WHERE EXISTS (SELECT isbn

FROM shipments

WHERE customer_id = customers.id);

Аналогично, чтобы получить список покупателей, никогда не де-

лавших покупки, можно воспользоваться следующим запросом: SELECT last_name, first_name

FROM customers

WHERE NOT EXISTS (SELECT isbn

FROM shipments

WHERE customer_id = customers.id);

Предикат UNIQUE имеет такой же смысл, как и EXISTS, но при этом

для его истинности требуется, чтобы все записи в результатной таблице не

только существовали, но и были уникальны (т.е. не повторялись).

Предикат DISTINCT почти такой же, как и UNIQUE. Отличие этих

предикатов обнаруживается применительно к значениям NULL. Так, если в

результатной таблице все записи уникальны (предикат UNIQUE истинен),

то и предикат DISTINCT тоже истинен. С другой стороны, если в резуль-

татной таблице имеются хотя бы две неопределенные записи, то предикат

DISTINCT ложен, хотя предикат UNIQUE истинен.

59

6.4. Представления

При работе с SQL нередко возникают ситуации, когда один и тот же

запрос приходится использовать повторно. В подобных ситуациях обычно

используются представления (views). Представления могут строиться на

основе как простых и стандартных запросов к одной таблице, так и чрез-

вычайно сложных запросов, в которых задействовано несколько таблиц.

Представление можно рассматривать как хранимый запрос, на осно-

ве которого создается объект базы данных. Этот объект очень похож на

таблицу, но в его содержимом динамически отражается состояние только

тех записей, которые были заданы при создании представления. Представ-

ления не являются физическими объектами хранения данных. Данные в

представлениях, подобно в ответах на запрос SELECT, просто выбираются

из таблиц базы данных, т.е. представляются в том или ином виде. В дей-

ствительности за представлением стоит скрытый SQL-запрос. Работать с

представлением можно как с обычной таблицей. Однако любой запрос к

представлению в действительности инициирует скрытый запрос, который

комбинируется с пользовательским.

Представления, будучи созданы, могут быть доступны многим поль-

зователям и существуют в базе данных до тех пор, пока не будут принуди-

тельно удалены.

Представления создаются командой CREATE VIEW имяПредставления AS

запросSELECT;

Как и обычной таблице базы данных, представлению присваивается

имя, которое не должно совпадать ни с одним именем таблиц. За ключе-

вым словом AS следует SQL-выражение запроса на выборку данных.

Пусть требуется получить для каждого наименования книги количе-

ство ее покупок и дату последней покупки: SELECT title, count(*) AS num_shipped,

max(ship_date) AS last_date

FROM shipments JOIN editions USING (isbn)

JOIN books ON (book_id = books.id)

GROUP BY title

ORDER BY num_shipped DESC;

Запрос получается слишком громоздким, и часто вводить его вруч-

ную нежелательно. Создадим на базе этого запроса представление:

60

CREATE VIEW recent_shipments AS

SELECT title, count(*) AS num_shipped,

max(ship_date) AS last_date

FROM shipments JOIN editions USING (isbn)

JOIN books ON (book_id = books.id)

GROUP BY title

ORDER BY num_shipped DESC;

Представления значительно упрощают получение нужных данных.

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

команду SELECT: SELECT *

FROM recent_shipments;

Получим названия книг, которые были куплены в наибольшем коли-

честве: SELECT title

FROM recent_shipments

WHERE num_shipped = (SELECT max(num_shipped)

FROM recent_shipments)

ORDER BY title;

Некоторые современные СУБД поддерживают операции изменения

содержимого представлений – вставку, изменение и удаление записей. Од-

нако это возможно лишь в том достаточно редком случае, когда имеется

однозначное соответствие между столбцами представления и столбцами

таблицы базы данных. Для этого в операторе SELECT представления не

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

группировки, ключевого слова DISTINCT и т.п.

В PostgreSQL при попытке вызова команд INSERT, UPDATE или

DELETE для представления происходит ошибка.

Представления удаляются из базы данных командой DROP VIEW имяПредставления;

При удалении представления данные сохраняются без изменения.

Теряется только запрос, на котором основано представление.

61

Лабораторная работа 6

Следующие запросы к базе данных booktown рекомендуется наби-

рать в файлах (по одному запросу в файле). Запустить запрос из файла

можно командой \i имя_файла. Подзапросы и представления сопро-

вождать комментариями, поясняющими их назначение.

1. Пусть автор получает половину от стоимости (cost) каждой проданной

книги. Определить прибыль каждого автора. Отсортировать по авто-

рам.

2. Определить, сколько книг было на складе до продажи. Отсортировать

по кодам isbn.

3. Список тем, нашедших отражение в произведениях только одного ав-

тора. Отсортировать по названию темы.

4. Список покупателей, купивших более одной книги, но все на одну и

ту же тему. Отсортировать по покупателю.

5. Список покупателей, купивших книги и в твердой, и в бумажной об-

ложках. Отсортировать по покупателям.

6. Список тем, книги по которым выдержали наибольшее количество из-

даний.

7. Название самой популярной у покупателей темы (тем).

8. Код isbn, автор и издатель бестселлера(ов) – самой покупающейся

книги.

9. Издатель, средняя цена книг которого самая дешевая.

10. Для каждой темы определить, сколько книг издано в жесткой и сколь-

ко – в бумажной обложках. Отсортировать по теме.

11. Фамилии авторов, писавших на одну и ту же тему несколько раз. От-

сортировать по фамилии автора.

12. Список покупателей, покупавших одно и то же произведение не-

сколько раз. Отсортировать по покупателю.

13. Список авторов, не написавших ни одной книги. Отсортировать по ав-

тору.

14. Названия тем, которые никогда не были изданы. Упорядочить по

названию темы.

15. Коды ISBN книг с наименьшей разницей между ценой закупки и це-

ной продажи.

16. Название издательства (издательств), выпустивших наибольшее коли-

чество книг (с различными isbn).

17. Список издателей, книги которых хуже всего продаются.

18. Все различные пары кодов isbn, относящихся к одной и той же книге.

19. Все различные пары авторов, писавших на одну и ту же тему.

20. Все различные пары авторов, никогда не писавших на одну и ту же

тему.

62

7. КОМАНДЫ ИЗМЕНЕНИЯ ДАННЫХ

При создании и дальнейшем сопровождении базы данных обычно

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

изменения содержимого ячеек таблицы. В SQL для этого предусмотрены

операторы INSERT (вставить), DELETE (удалить) и UPDATE (изменить).

Запросы, начинающиеся с этих ключевых слов, не возвращают данные в

виде виртуальной таблицы, а изменяют содержимое уже существующих

таблиц базы данных. Запросы на модификацию данных могут содержать

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

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

7.1. Добавление новых записей

Для добавления (вставки) записи в таблицу служит оператор IN-

SERT, который имеет несколько форм:

INSERT INTO имяТаблицы VALUES (списокЗначений) –

вставляет пустую запись в указанную таблицу и заполняет эту запись

значениями из списка, указанного за ключевым словом VALUES. При

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

второе значение – во второй столбец и т.д. Порядок столбцов задается

при создании таблицы. Данная форма оператора INSERT не очень

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

INSERT INTO имяТаблицы (списокСтолбцов) VALUES

(списокЗначений) – вставляет пустую запись в указанную таблицу

и вводит в заданные столбцы значения из указанного списка. При этом

в первый столбец из списокСтолбцов вводится первое значение из

списокЗначений, во второй столбец – второе значение и т.д. Порядок

имен в списке можеть отличаться от их порядка, заданного при созда-

нии таблицы. Столбцы, которые не указаны в списке, заполняются зна-

чениями NULL.

INSERT INTO имяТаблицы (списокСтолбцов) SELECT ... –

вставляет в указанную таблицу записи, возвращаемые запросом на вы-

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

из другой таблицы. Например, INSERT INTO books

(id, title, author_id, subject_id)

SELECT book_id, title, author_id, subject_id

FROM book_queue

WHERE subject_id = 4;

63

7.2. Удаление записей

Для удаления записей из таблицы применяется оператор DELETE

(удалить): DELETE

FROM имяТаблицы

WHERE условие;

Данный оператор удаляет из указанной таблицы записи (а не отдель-

ные значения столбцов), которые удовлетворяют указанному условию.

Следующий запрос удаляет записи из таблицы stock, в которых

значение столбца stock равно нулю. Если подходящих записей несколь-

ко, все они будут удалены. DELETE

FROM stock

WHERE stock = 0;

В операторе WHERE может находиться подзапрос на выборку данных

(оператор SELECT). Подзапросы в операторе DELETE работают точно так

же, как и в операторе SELECT.

Операция удаления записей из таблицы является опасной в том

смысле, что связана с риском необратимых потерь данных в случае оши-

бок. Чтобы избежать неприятностей, перед удалением записей рекоменду-

ется сначала выполнить соответствующий запрос на выборку, чтобы про-

смотреть, какие записи будут удалены. Так, например, перед выполнением

рассмотренного ранее запроса на удаление не помешает выполнить соот-

ветствующий запрос на выборку: SELECT *

FROM stock

WHERE stock = 0;

Для удаления всех записей из таблицы достаточно использовать опе-

ратор DELETE без ключевого слова WHERE. При этом сама таблица со все-

ми определенными в ней столбцами остается и готова для вставки новых

записей. Например, DELETE

FROM stock;

7.3. Изменение данных

Для изменения значений столбцов таблицы применяется оператор

UPDATE (изменить, обновить). Чтобы изменить значения в одном столбце

таблицы в тех записях, которые удовлетворяют некоторому условию, сле-

дует выполнить такой запрос:

64

UPDATE имяТаблицы

SET имяСтолбца = значение

WHERE условие;

За ключевым словом SET (установить) следует выражение равен-

ства, в левой части которого указывается имя столбца, а в правой – выра-

жение, значение которого следует сделать значением данного столбца. Эти

установки будут выполнены в тех записях, которые удовлетворяют усло-

вию в операторе WHERE.

Чтобы одним оператором UPDATE установить новые значения сразу

для нескольких столбцов, вслед за ключевым словом SET записываются

соответствующие выражения равенства, разделенные запятыми.

Например: UPDATE publishers

SET name = 'O\'Reilly & Associates',

address = 'O\'Reilly & Associates, Inc. '

|| '101 Morris St, Sebastopol, CA 95472'

WHERE id = 113;

Использование оператора WHERE в операторе UPDATE не обязатель-

но. Если он отсутствует, то указанные в SET изменения будут произведены

для всех записей таблицы.

Операция изменения записей, как и их удаление, связана с риском

необратимых потерь данных в случае ошибок. Чтобы избежать подобных

неприятностей, перед обновлением записей рекомендуется выполнить со-

ответствующий запрос на выборку, чтобы просмотреть, какие записи бу-

дут изменены. Так, например, перед выполнением приведенного ранее за-

проса на обновление данных не помешает выполнить соответствующий

запрос на выборку: SELECT *

FROM publishers

WHERE id = 113;

Условие в операторе WHERE может содержать подзапросы, в том

числе и связанные.

Некоторые СУБД (например, PostgreSQL) имеют расширение стан-

дарта SQL, позволяющее обновлять одну таблицу данными из другой. В

этом случае команда UPDATE дополняется поддержкой секции FROM. Сек-

ция FROM позволяет получать входные данные из других наборов данных

(таблиц и подзапросов).

Например, обновим данные таблицы stock по данным таблицы

stock_backup:

65

UPDATE stock

SET retail = stock_backup.retail

FROM stock_backup

WHERE stock.isbn = stock_backup.isbn;

Секция WHERE описывает связь между обновляемой таблицей и ис-

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

isbn, поле retail в таблице stock обновляется значением из резервной

таблицы stock_backup.

Секция FROM поддерживает все разновидности синтаксиса JOIN,

что открывает широкие возможности обновления данных в существующих

наборах.

66

Лабораторная работа 7

1. Переключиться в БД с номером вашей группы (команда монитора:

\c имяБазыДанных) и создать в этой БД таблицу для хранения

данных о людях, характеризуемых фамилиями, именами, возрастом

(число прожитых лет), весом (в кг) и ростом (в см).

2. Внести в созданную таблицу данные о шести произвольных людях в

возрасте от 16 до 50 лет, имеющих вес от 40,5 до 99,5 кг и рост 150 –

195 см.

3. Создать вторую таблицу, включив в нее из первой таблицы данные о

людях старше 20 лет и выше 180 см.

4. Создать третью таблицу – копию первой таблицы, но не содержа-

щую столбца с именами людей.

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

данные о росте в дюймах, а весе – в фунтах (1 фунт = 454 г,

1 дюйм = 2,54 см).

6. Из третьей таблицы удалить строки, содержащие сведения о людях

моложе 20 лет.

7. Добавить в третью таблицу данные о фамилии и возрасте еще двух

произвольных человек.

8. Удалить из первой таблицы сведения о людях, чьи фамилии есть во

второй таблице.

9. Продемонстрировав все созданные таблицы преподавателю, уничто-

жить все таблицы.

67

8. ОПРЕДЕЛЕНИЕ ДАННЫХ

8.1. Создание таблиц

8.1.1. Оператор CREATE TABLE

Создание таблицы производится с помощью оператора CREATE

TABLE с указанием необходимых параметров.

Для создания таблицы необходимо указать ее имя и определить

столбцы. Определение столбца включает его имя и тип. Если указывается

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

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

определения столбца указываются друг за другом через пробел. Если со-

здаваемая таблица содержит несколько столбцов, то их определения разде-

ляются запятыми.

Далее приведен запрос на создание таблицы authors без ограниче-

ний: CREATE TABLE authors

(id INTEGER,

last_name TEXT,

first_name TEXT);

8.1.2. Ограничения для столбцов

NOT NULL Столбец не может содержать значение NULL, т.е.

значения этого столбца должны быть определен-

ными.

UNIQUE Значение, вводимое в столбец, должно отличаться

от всех остальных значений в этом столбце, т.е.

быть уникальным.

PRIMARY KEY Столбец является первичным ключом. В каждой

таблице только один столбец может быть первич-

ным ключом. Это означает, что он не может содер-

жать значение NULL, а вводимое в него значение

должно отличаться от всех остальных значений в

этом столбце. Таким образом, PRIMARY KEY яв-

ляется комбинацией NOT NULL и UNIQUE.

68

DEFAULT значение Устанавливает значение по умолчанию. Так, при

добавлении новой записи столбец с таким ограни-

чением автоматически получит указанное значе-

ние.

CHECK (условие) Позволяет производить проверку условия при вво-

де данных. Значение будет сохранено, если условие

выполняется, в противном случае – нет.

Создадим таблицу authors с использованием ограничений столб-

цов: CREATE TABLE authors

(id INTEGER PRIMARY KEY CHECK (id > 0),

last_name TEXT NOT NULL,

first_name TEXT);

8.1.3. Ограничения для таблиц

В ограничениях таблиц, в отличие от ограничений полей, могут

участвовать сразу несколько полей таблицы. Для ограничения таблицы

может быть задано имя. В будущем имя ограничения может пригодиться

для удаления ограничения (например, в секции DROP CONSTRAINT ко-

манды ALTER TABLE).

Определение ограничения для таблицы указывается после определе-

ния столбцов и состоит из необязательной секции CONSTRAINT

имяОграничения, за которой следует выражение, определяющее непо-

средственно само ограничение.

UNIQUE Ограничение означает, что комбинация значений

полей, перечисленных за ключевым словом

UNIQUE, принимает только уникальные значения.

Допускается многократное вхождение псевдозна-

чения NULL.

PRIMARY KEY В ограничении могут перечисляться несколько по-

лей, разделенных запятыми. Используется для со-

ставного первичного ключа.

CHECK (условие) Команды INSERT или UPDATE для записи завер-

шаются успешно лишь при выполнении заданного

условия. Может содержать ссылки на несколько

полей.

69

Создадим таблицу authors с использованием ограничений табли-

цы: CREATE TABLE authors

(id INTEGER,

last_name TEXT NOT NULL,

first_name TEXT,

CONSTRAINT id_pkey PRIMARY KEY (id),

CONSTRAINT id_check CHECK (id > 0),

CONSTRAINT name_uniq UNIQUE (last_name, first_name));

8.1.4. Внешние ключи

Внешний ключ – это столбец или группа столбцов, соответствующих

первичному ключу другой таблицы. Внешний ключ определяется как

ограничение столбца с помощью выражения REFERENCES внешня-

яТаблица (первичныйКлюч). Если первичныйКлюч в ограничении

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

Создадим таблицу books:

CREATE TABLE books

(id INTEGER PRIMARY KEY,

title TEXT NOT NULL,

author_id INTEGER REFERENCES authors (id),

subject_id INTEGER NOT NULL REFERENCES subjects);

Ограничение внешнего ключа может содержать дополнительные

секции ON DELETE и ON UPDATE. В этих секциях указывается, какую

операцию следует произвести с полем внешнего ключа, если будет удален

или изменен соответствующий первичный ключ. Возможные операции:

NO ACTION Если удаление (изменение) первичного ключа приводит

к нарушению целостности ссылок, происходит ошибка.

Используется по умолчанию, если операция не указана.

RESTRICT Аналогично NO ACTION.

CASCADE Удаление (обновление) всех записей, содержащих

ссылки на удаляемую (обновляемую) запись.

SET NULL Поля, содержащие ссылки на удаляемую (обновляемую)

запись, заменяются псевдозначениями NULL.

SET DEFAULT Полям, содержащим ссылки на удаляемую (обновляе-

мую) запись, присваивается значение по умолчанию.

Рассмотрим данные операции на примере создания таблицы books:

70

CREATE TABLE books

(id INTEGER PRIMARY KEY,

title TEXT NOT NULL,

author_id INTEGER REFERENCES authors (id)

ON DELETE NO ACTION ON UPDATE CASCADE,

subject_id INTEGER NOT NULL

REFERENCES subjects ON UPDATE CASCADE);

Ограничение внешнего ключа может быть и ограничением таблицы.

Если внешний ключ – составной, то единственный способ его задать – это

использовать ограничение таблицы. В случае ограничения таблицы опре-

деление ограничения предваряется ключевыми словами FOREIGN KEY

(списокПолей).

Создадим таблицу books с использованием ограничений таблицы в

качестве ограничений внешнего ключа: CREATE TABLE books

(id INTEGER PRIMARY KEY,

title TEXT NOT NULL,

author_id INTEGER,

subject_id INTEGER NOT NULL,

CONSTRAINT author_fk

FOREIGN KEY (author_id) REFERENCES authors (id)

ON DELETE NO ACTION ON UPDATE CASCADE,

FOREIGN KEY (subject_id) REFERENCES subjects

ON UPDATE CASCADE);

8.2. Удаление таблиц

Удалить таблицу из базы данных можно следующим образом: DROP TABLE имяТаблицы;

Использование команды DROP TABLE требует осторожности, по-

скольку удаление таблицы приводит к уничтожению всех хранящихся в

ней данных.

8.3. Модификация таблиц

Модификация таблицы – это изменение ее структуры. Для модифи-

кации таблиц предназначена команда ALTER TABLE. Реализация ALTER

TABLE в PostgreSQL 7.1.x поддерживает следующие типы модификации:

создание полей;

назначение и отмена значений по умолчанию;

71

переименование таблицы;

переименование полей;

добавление ограничений.

8.3.1. Создание полей

Для создания нового поля в команду ALTER TABLE включается

секция ADD COLUMN:

ALTER TABLE имяТаблицы

ADD COLUMN имяСтолбца типСтолбца;

Ключевое слово COLUMN не является обязательным.

Предположим, в таблицу books базы данных booktown потребо-

валось включить новое поле publication для хранения даты публика-

ции: ALTER TABLE books

ADD publication date;

8.3.2. Назначение и отмена значений по умолчанию

Назначать и отменять значения по умолчанию для отдельных полей

относительно легко. Для этого используется команда ALTER TABLE с

секцией ALTER COLUMN:

ALTER TABLE имяТаблицы

ALTER COLUMN имяСтолбца

SET DEFAULT значение;

или ALTER TABLE имяТаблицы

ALTER COLUMN имяСтолбца

DROP DEFAULT;

Ключевое слово COLUMN не является обязательным.

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

умолчанию для поля edition (номер издания) таблицы editions;

ALTER TABLE editions

ALTER COLUMN edition

SET DEFAULT 1;

ALTER TABLE editions

ALTER edition

DROP DEFAULT;

72

8.3.3. Переименование таблицы

Переименование таблиц осуществляется командой ALTER TABLE с

секцией RENAME:

ALTER TABLE имяТаблицы

RENAME TO новоеИмя;

Таблицу можно переименовывать сколько угодно раз, это никак не

отражается на состоянии хранящихся в ней данных. В некоторых ситуаци-

ях переименования нежелательны – например, если таблица используется

внешним приложением.

Переименуем таблицу books в таблицу literature:

ALTER TABLE books

RENAME TO literature;

8.3.4. Переименование полей

Изменять имена полей можно без изменения данных, хранящихся в

таблице. Однако, переименование полей – довольно опасная операция, по-

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

лей. Если программа обращается к полю по имени, то переименование мо-

жет нарушить ее работоспособность. Команда переименования полей име-

ет следующий синтаксис: ALTER TABLE имяТаблицы

RENAME COLUMN имяПоля TO новоеИмя;

Ключевое слово COLUMN не является обязательным. По двум иден-

тификаторам, разделенным ключевым словом TO, PostgreSQL может опре-

делить, что команда переименования относится к одному полю, а не таб-

лице.

Например, ALTER TABLE stock

RENAME COLUMN stock TO is_in_stock;

8.3.5. Добавление ограничений

После создания таблицы сохраняются некоторые возможности до-

бавления ограничений. В PostgreSQL 7.1.x команда ALTER TABLE с сек-

цией ADD CONSTRAINT позволяет определять для полей существующих

таблиц только ограничения внешнего ключа и проверки (CHECK). Команда

создания новых ограничений имеет следующий синтаксис: ALTER TABLE имяТаблицы

ADD CONSTRAINT имяОграничения ограничение;

73

Синтаксис ограничения зависит от типа ограничения.

Создадим ограничение внешнего ключа для таблицы editions

(связанной с полем id таблицы books):

ALTER TABLE editions

ADD CONSTRAINT foreign_book

FOREIGN KEY (book_id) REFERENCES books (id);

Добавим ограничение для проверки поля type:

ALTER TABLE editions

ADD CONSTRAINT type_check CHECK (type IN (‘p’, ‘h’));

74

Лабораторная работа 8

Все работы по созданию и модификации таблиц следует выполнять в

базе данных с номером вашей группы.

1. Создать таблицу для хранения данных о студентах с полями: фами-

лия, номер зачетки, адрес, год поступления в университет, номер

специальности, номер группы; ввести ограничения первичного клю-

ча, отсутствия пустых значений для фамилии и года поступления,

значение специальности по умолчанию 0220100.

2. Заполнить данными созданную таблицу (не менее 5 записей), при

вводе попытаться ввести записи с дублирующимися номерами зачет-

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

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

ствия и реакцию на них сервера БД (что происходит и почему). При-

вести в отчете окончательный вид созданной таблицы.

3. Создать таблицу для хранения данных о сдаче студентами различных

экзаменов по дисциплинам с оценками и заполнить ее данными

(каждый студент сдает не менее трех экзаменов); задать первичный

ключ в таблице; обеспечить выполнение условий целостности дан-

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

зачетные книжки, а при удалении записей о студентах удалялись бы

и записи о сданных ими экзаменах (каскадное удаление).

Продемонстрировав все созданные таблицы преподавателю, уни-

чтожить таблицы.

75

ПРИЛОЖЕНИЯ

П.1. Возможности PostgreSQL

PostgreSQL – объектно-реляционная система управления базами

данных, разработка которой в различных формах ведется с 1977 года. В

1996 году был осуществлен переход на распространение PostgreSQL с от-

крытыми исходными текстами. В настоящее время над проектом Post-

greSQL активно работает группа разработчиков со всего мира.

PostgreSQL считается самой совершенной СУБД, распространяемой

на условиях открытых исходных текстов. В PostgreSQL реализованы мно-

гие возможности, традиционно встречавшиеся только в масштабных ком-

мерческих продуктах:

объектно-реляционная модель позволяет задействовать сложные

процедуры и системы правил, например, контроль параллельного до-

ступа, поддержку многопользовательского доступа, транзакции, оп-

тимизацию запросов, поддержку и наследование массивов;

простота расширения: в PostgreSQL поддерживаются пользователь-

ские операторы, функции, методы доступа и типы данных;

полноценная поддержка SQL;

проверка целостности ссылок;

поддержка внутренних процедурных языков;

архитектура «клиент-сервер».

П.2. Консоль psql

Система PostgreSQL, как и большинство сетевых СУБД, основана на

парадигме “клиент-сервер”. Центральное место в PostgreSQL занимает

процесс postmaster, предназначенный не для прямого взаимодействия с

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

клиентов.

При запуске службы (service) PostgreSQL процесс postmaster начина-

ет работать в фоновом режиме, прослушивая заданный порт TCP/IP в ожи-

дании подключений со стороны клиентов.

Существует несколько интерфейсов, через которые клиент подклю-

чается к процессу postmaster. В лабораторных работах используется psql –

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

PostgreSQL.

Запуск psql осуществляется командой:

76

psql -h host_name db_name [-U user_name]

Если пользователь зарегистрирован администратором БД и база дан-

ных с именем db_name имеется на сервере, то соединение произойдет, что

отразится в командной строке: db_name=>

В лабораторных работах host_name – это server, а db_name –

booktown.

Команды консоли psql делятся на две группы:

команды языка SQL для работы с данными в базе;

внутренние команды psql, начинающиеся с символа ‘\’.

Некоторые полезные команды клиента psql:

\? Справка по командам psql

\с база_данных Подключение к другой базе данных

\dt Список таблиц в текущей базе данных

\d имя_таблицы Структура таблицы

\h команда Справка по командам sql

\i имя_файла Чтение входных данных из файла

\l Список имеющихся на сервере баз данных

\o файл Перенаправление вывода в файл

\q Выход из psql

\t Режим выдачи дополнительной информации о таб-

лице

\z имя_таблицы Права доступа к таблице

П.3. Команды SQL

П.3.1. Перечень команд SQL СУБД PostgreSQL

Команды SQL всегда начинаются с действия – слова или группы

слов, описывающих выполняемую операцию. Кроме того, команда SQL

обычно содержит одну или несколько секций, уточняющих ее смысл.

Основные действия PostgreSQL:

CREATE DATABASE Создание новой базы данных

CREATE INDEX Создание нового индекса для столбца таблицы

CREATE SEQUENCE Создание новой последовательности в существую-

щей базе данных

77

CREATE TABLE Создание новой таблицы в существующей базе

данных

CREATE TRIGGER Создание нового определения триггера

CREATE VIEW Создание нового представления для существующей

таблицы

SELECT Выборка записей из таблицы

INSERT Вставка одной или нескольких новых записей в

таблицу

UPDATE Модификация данных в существующих записях

DELETE Удаление существующих записей из таблицы

DROP DATABASE Уничтожение существующей базы данных

DROP INDEX Удаление индекса столбца из существующей таб-

лицы

DROP SEQUENCE Уничтожение существующего генератора последо-

вательности

DROP TABLE Уничтожение существующей таблицы

DROP TRIGGER Уничтожение существующего определения тригге-

ра

DROP VIEW Уничтожение существующего представления

CREATE USER Создание в системе новой учетной записи пользо-

вателя PostgreSQL

ALTER USER Модификация существующей учетной записи

пользователя PostgreSQL

DROP USER Удаление существующей учетной записи пользова-

теля PostgreSQL

GRANT Предоставление прав доступа к объекту базы дан-

ных

REVOKE Лишение прав доступа к объекту базы данных

CREATE FUNCTION Создание новой функции SQL в базе данных

CREATE LANGUAGE Создание нового определения языка в базе данных

CREATE OPERATOR Создание нового оператора SQL в базе данных

CREATE TYPE Создание нового типа данных SQL в базе данных

П.3.2. Форматирование команд SQL

Команды SQL состоят из последовательности элементов – лексем.

Лексемы могут находиться в одной или нескольких строках, поскольку

модуль лексического разбора PostgreSQL игнорирует лишние пропуски (в

том числе разрывы строк).

78

Приведем пример команды SQL, которая в первом случае задана в

одной строке, а во втором повторяется с разбивкой на несколько строк.

SELECT * FROM my_list;

SELECT *

FROM

my_list;

Лексемы второй команды разделены дополнительными пробелами и

символами новой строки. PostgreSQL игнорирует лишние пробелы и раз-

рывы строк, вследствие чего команды являются синтаксически эквива-

лентными. Следует пользоваться этим фактом и разбивать длинную ко-

манду SQL на несколько строк, чтобы упростить ее чтение. Для таких про-

стых команд, как в приведенном выше примере, это не нужно, но разбие-

ние пригодится при работе со сложными командами SQL с многочислен-

ными секциями, выражениями и условиями.

П.3.3. Выполнение запросов

В psql существует два способа ввода и выполнения запросов. В ин-

терактивном режиме запросы обычно вводятся непосредственно в пригла-

шении командной строки (то есть из стандартного ввода). Команда psql \i

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

Чтобы передать PostgreSQL команду SQL, следует просто ввести ее в

приглашении. Весь вводимый текст накапливается до тех пор, пока ввод не

будет завершен символом точки с запятой (;). Ввод команды не прерыва-

ется даже разрывами строк, что позволяет распределить запрос по не-

скольким строкам.

Если в предыдущей строке присутствует символ, требующий парно-

го завершителя (например, круглой скобки или кавычки), этот символ

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

манду CREATE TABLE с открывающей круглой скобкой и перейти на дру-

гую строку, то приглашение будет выглядеть следующим образом: booktown=# CREATE TABLE employees (

booktown(#

Ввод команды продолжается. Открывающая круглая скобка в при-

глашении psql напоминает о том, что в команду необходимо включить за-

крывающую круглую скобку.

79

П.3.4. Ключевые слова и идентификаторы

Ключевыми словами называются зарезервированные термины SQL,

имеющие особый синтаксический смысл для сервера (INSERT, UPDATE,

SELECT, DELETE и т.д.).

Каждая команда SQL начинается с ключевого слова, хотя многие

ключевые слова сами по себе не являются законченными командами.

Например, конструкция INSERT INTO является действительной коман-

дой SQL, а слово INTO является зарезервированным ключевым словом,

которое не имеет смысла вне контекста.

Идентификаторы представляют собой имена переменных для ссылки

на объекты базы данных. Имена идентификаторов произвольно назнача-

ются при создании базы данных. В PostgreSQL идентификаторы могут свя-

зываться с базами данных, таблицами, полями, индексами, представления-

ми, последовательностями, правилами, триггерами и функциями.

Защищенные идентификаторы

Хотя обычно это и не требуется, идентификаторы могут заключаться

в кавычки, указывающие на их буквальную интерпретацию. Например,

просмотр всех полей таблицы с именем states обычно производится

следующей простой командой: SELECT * FROM states;

Аналогичного эффекта можно добиться, заключив идентификатор в

кавычки: SELECT * FROM “states”;

Применение кавычек к идентификаторам, записанным символами

нижнего регистра, ни на что не влияет. Однако попытка защитить иденти-

фикатор stAtes в следующей команде приводит к неудаче:

SELECT * FROM “stAtes”;

Дело в том, что команда приказывает PostgreSQL найти таблицу с

именем stAtes (вместо states). Другими словами, заключение иденти-

фикатора в кавычки требует, чтобы интерпретатор PostgreSQL интерпре-

тировал его буквально.

Все незащищенные идентификаторы преобразуются к нижнему ре-

гистру. Любая смешанная комбинация символов разных регистров

(stAtEs, STATES) при отсутствии кавычек перед выполнением команды

автоматически приводится к виду states.

Обязательная защита идентификаторов

Идентификаторы должны обязательно заключаться в кавычки только

в двух случаях: если идентификатор объекта базы данных совпадает с

ключевым словом или в его имени присутствует хотя бы одно прописная

80

буква. В любом из этих случаев идентификатор должен защищаться как

при создании объекта, так и при последующих ссылках на него в командах

SELECT, DELETE или UPDATE и т.д.

Если не заключить в кавычки идентификатор, совпадающий с клю-

чевым словом, PostgreSQL выдаст сообщение об ошибке, поскольку иден-

тификатор интерпретируется как ключевое слово.

Структура имен идентификаторов

Максимальная длина ключевых слов и идентификаторов PostgreSQL

равна 31 символу. В процессе лексического разбора все ключевые слова и

идентификаторы большей длины автоматически усекаются. Идентифика-

торы начинаются с любой буквы английского алфавита (a – z) или с сим-

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

(0 – 9) и символов подчеркивания. Ключевые слова не могут начинаться

или завершаться символом подчеркивания, но для имен идентификаторов

это разрешено. Ни ключевые слова, ни идентификаторы не могут начи-

наться с цифры.

Заключение идентификатора в кавычки позволяет «преодолеть» пра-

вило игнорирования регистра символа. То же относится и к правилу, со-

гласно которому идентификатор не может начинаться с цифры. Более того,

имена таблиц могут содержать некоторые символы, которые обычно счи-

таются недопустимыми (например, пробелы или амперсанды, хотя присут-

ствие кавычек, разумеется, запрещено).

Защита идентификаторов при помощи кавычек выручает во многих

нестандартных ситуациях, но чтобы команды SQL были стандартными и

хорошо адаптировались для других платформ, следует стараться по воз-

можности придерживаться стандартов ANSI/ISO.

П.3.5. Комментарии

Комментарием называется фрагмент обычного текста, оформленный

специальным образом и внедренный в код SQL. Комментарии не влияют

на выполнение программы, поскольку PostgreSQL удаляет их из входного

потока и интерпретирует как обычные пропуски. Существует две разно-

видности комментариев: однострочные и многострочные.

Однострочные комментарии начинаются с двух дефисов (--) и либо

находятся в отдельной строке, либо следуют за лексемами SQL (модуль

лексического разбора PostgreSQL не считает комментарии лексемами, а

все символы, следующие за последовательностью --, интерпретирует как

пропуски).

81

SELECT ‘Test’ -- This can follow valid SQL tokens

-- or be on a line of its own.

AS example;

Многострочные комментарии начинаются с последовательности /*

и завершаются последовательностью */. Такой способ оформления ком-

ментариев хорошо знаком программистам С, но между интерпретатором

PostgreSQL и компилятором С существует одно принципиальное различие:

комментарии PostgreSQL могут быть вложенными. Иначе говоря, если

внутри многострочного комментария имеется другой многострочный ком-

ментарий, то закрывающая последовательность */ внутреннего коммента-

рия не закрывает внешний комментарий. SELECT ‘Multitest’ /* This comment extends across

* numerous lines, and can be

* /* nested safely */ */

AS example;

П. 4. Типы данных PostgreSQL 7.1.

П.4.1. Перечень типов данных

Символьные типы

character(n), char(n) – символьная строка фиксированной дли-

ны, дополненная пробелами до n символов. Занимает в памяти (4 + n)

байт;

character varying(n), varchar(n) – символьная строка пере-

менной длины, максимальный размер равен n. Занимает в памяти до

(4 + n) байт;

text – строка переменной длины, максимальный размер не ограничен.

Числовые типы

integer, int, int4 – целые числа в интервале от –2 147 483 648 до

2 147 483 647. Занимает в памяти 4 байта;

smallint, int2 – целые числа в интервале от –32 768 до 32 767. За-

нимает в памяти 2 байта;

bigint, int8 – целые числа в интервале от –9 223 372 036 854 775 807

до 9 223 372 036 854 775 807. Занимает в памяти 8 байт;

numeric(p,s), decimal(p,s) – целые и вещественные числа из p

цифр (всего) и s цифр в дробной части. Тип numeric (также называе-

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

больших или малых значений с фиксированной точностью, задаваемой

82

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

ность и масштаб. Точность определяет максимальное количество цифр

(включая цифры в дробной части), а масштаб определяет количество

цифр только в дробной части. Если параметры не заданы, по умолча-

нию точность равна 30, а масштаб – 6. Максимальная точность (а сле-

довательно, и максимальный размер), задаваемая таким образом, равна

1000. На практике 1000 цифр обычно вполне достаточно. В отличие от

вещественных чисел, при попытке вставить в поле numeric число, не

входящее в интервал допустимых значений, происходит ошибка пере-

полнения. В остальном допускается вставка любого числа, не наруша-

ющего заданной точности. Например, в поле numeric(11,6) можно

безопасно сохранить значение 9.99999999 с лишними цифрами в

дробной части (хотя оно будет округлено до 10.000000). С другой

стороны, попытка сохранения числа 99999.99999999 завершается

неудачей;

real, float4 – вещественные числа, 6 значащих цифр, неограничен-

ный размер (с ограниченной точностью);

double precision, float8, float – вещественные числа, 15 зна-

чащих цифр, неограниченный размер (с ограниченной точностью). За-

нимает в памяти 8 байт;

money – вещественные числа с двумя цифрами в дробной части в ин-

тервале от –21 474 836.48 до 21 474 836.47 для представления денежных

величин. Занимает в памяти 4 байта. Тип считается устаревшим и ис-

пользовать его не рекомендуется. Вместо типа money следует исполь-

зовать тип numeric с масштабом 2 и точностью, достаточной для

представления максимальной необходимой величины (включая 2 циф-

ры для дробной части);

serial – целые числа в интервале от 0 до 2 147 483 647 с автоматиче-

ским приращением. Занимает в памяти 4 байта. Хотя тип serial не

относится к числу стандартных типов, он часто используется при созда-

нии в таблице полей-идентификаторов, содержащих уникальное значе-

ние для каждой записи. В типе serial объединены функциональные

возможности 4-байтового типа integer, индекса и последовательно-

сти.

Логические и двоичные типы данных

boolean, bool – отдельная логическая величина (true или false);

bit(n) – битовая последовательность фиксированной длины (ровно n

бит);

bit varying(n), varbit(n) – битовая последовательность пере-

менной длины (до n бит).

83

Типы даты и времени

date – календарная дата (год, месяц и день) от 4 713 г. до н.э. до

32 767 г. н.э. Занимает в памяти 4 байта;

time – время суток без часового пояса от 00:00:00 до 23:59:59.99. За-

нимает в памяти 4 байта;

time with time zone – время суток с часовым поясом от

00:00:00+12 до 23:59:59.99–12. Занимает в памяти 4 байта;

timestamp with time zone, timestamp – календарная дата и

время с часовым поясом от 1 903 г. н.э. до 2 037 г. н.э. Занимает в памя-

ти 8 байт.

Встроенные константы даты и времени:

current – текущее время обработки транзакции, не привязывается к

конкретному времени и возвращает текущее системное время;

now – фиксированное время обработки транзакции;

today – полночь текущего дня;

tomorrow – полночь следующего дня;

yesterday – полночь предыдущего дня;

infinity – абстрактная константа, более "поздняя" по сравнению со

всеми допустимыми значениями даты и времени;

-infinity – абстрактная константа, более "ранняя" по сравнению со

всеми допустимыми значениями даты и времени;

epoch – 1970-01-01 00:00:00+00 ("день рождения" Unix).

Интервальный тип

interval – фиксированный интервал времени. Сам по себе тип in-

terval представляет лишь количественную величину, не связанную с

определенными начальным или конечным моментом. Интервалы часто

используются в сочетании с типами даты и времени для вычисления но-

вой величины посредством сложения или вычитания. Кроме того, они

могут пригодиться для быстрого вычисления точного промежутка вре-

мени между двумя датами или моментами времени, для чего одна вели-

чина вычитается из другой.

Синтаксис определения интервалов: длина1 единица1 [длина 2 единица2 ...] [ago]

Здесь:

длина – продолжительность интервала, заданная в виде целого или

вещественного (для микросекунд) числа. Интерпретация числа опреде-

ляется следующим параметром;

единица – единица, в которой измеряется заданный интервал. Разре-

шены следующие ключевые слова: second, minute, hour, day,

84

week, month, year, decade, century, millenium. Также допуска-

ются сокращения (любой длины при условии однозначной интерпрета-

ции) и формы множественного числа;

ago – необязательное ключевое слово указывает, что описываемый пе-

риод времени предшествует некоторому моменту, а не следует после

него.

Примеры использования значений типа интервал: date('1980-06-25') + interval('21 years 8 days')

date('1980-06-25') - interval('21 years 8 days ago')

Геометрические типы

box – прямоугольник на плоскости;

line – бесконечная линия на плоскости;

lseg – отрезок на плоскости;

circle – круг с заданным центром и радиусом;

path – замкнутая или разомкнутая геометрическая фигура на плоско-

сти;

point – точка на плоскости;

polygon – замкнутый многоугольник на плоскости.

Сетевые типы

cidr – спецификация сети IP;

inet – сетевой IP-адрес с необязательными битами подсети;

macaddr – МАС-адрес (например, аппаратный адрес адаптера

Ethernet).

Системные типы

oid – идентификатор объекта (записи);

xid – идентификатор транзакции.

П.4.2. Преобразование типов

В PostgreSQL поддерживаются три отдельных варианта синтаксиса

преобразования (приведения типов), то есть механизма приведения данных

от одного типа к другому. В команде SQL преобразование типов позволяет

явно задать тип создаваемой константы (вместо его косвенного определе-

ния по правилам языка).

Приведение строковой константы к другому типу может выполнять-

ся любым из трех способов:

тип 'значение'

85

'значение' :: тип

CAST ('значение' AS тип)

Числовые константы преобразуются в символьную строку следую-

щими способами:

значение :: тип

CAST (значение AS тип)

Здесь значение представляет константу, тип которой требуется из-

менить, а тип – новый тип этой константы.

Преобразование к другому типу данных не ограничивается одними

константами. Поля набора данных, возвращаемого запросом SQL, также

могут преобразовываться к другому типу, при этому используются следу-

ющие формы синтаксиса:

идентификатор :: тип

CAST (идентификатор AS тип)

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

любому другому типу. Например, не существует осмысленного преобразо-

вания символьной строки abcd в двоичную последовательность типа bit.

Недопустимые попытки преобразования приводят к ошибкам PostgreSQL.

Кроме синтаксических форм преобразования типа существуют неко-

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

Имена этих функций часто совпадают с именами итоговых типов (напри-

мер, text()), хотя существуют и узкоспециализированные варианты

(например, bitfromint4()).

П.4.3. Константы

При работе с базами данных многие объекты хранятся на диске, а

для обращения к ним используются идентификаторы (имена таблиц, полей

и функций). Однако неизбежно настанет момент, когда в систему потребу-

ется передать новые данные – например, при вставке новых записей, при

формировании секций с критериями удаления или модификации или при

вычислениях на базе существующих записей. Такие данные передаются в

виде констант, также иногда называемых "литералами". Константы пред-

назначены для "буквального" представления данных в командах SQL (вме-

сто ссылки на них по идентификатору).

Константы с косвенной типизацией автоматически распознаются

модулем лексического разбора PostgreSQL по их синтаксису. В PostgreSQL

поддерживаются пять вариантов констант с косвенной типизацией:

строковые константы;

битовые последовательности;

целочисленные константы;

86

вещественные константы;

логические константы.

Строковые константы

Строковая константа представляет собой произвольную последова-

тельность символов, заключенную в апострофы, например 'Louisa

May'. Этот факт порождает следующую семантическую проблему: если в

самой последовательности символов встречается апостроф, граница стро-

ковой константы будет определена неверно. Чтобы экранировать апостроф

в строке (то есть обеспечить его интерпретацию как литерал), следует по-

ставить два апострофа подряд, например 'PostgreSQL''s great!'.

PostgreSQL также позволяет экранировать апострофы обратной косой чер-

той в стиле языка С, например 'PostgreSQL\'s great!'.

Битовые последовательности

Битовые последовательности предназначены для представления дво-

ичных величин в виде произвольной последовательности нулей и единиц.

Как и строковые константы, битовые последовательности заключаются в

апострофы, но начинаются обязательно с префикса В (в верхнем или ниж-

нем регистре), например B'00000000'. По наличию этого символа Post-

greSQL определяет, что строка является битовой последовательностью, а

не обычной символьной строкой.

В соответствии с синтаксисом PostgreSQL открывающий апостроф

должен следовать сразу же после префикса В, а битовая последователь-

ность не может содержать других символов, кроме 0 и 1.

Целочисленные константы

В PostgreSQL целочисленной константой считается любая лексема,

состоящая из цифр (без десятичной точки) и не заключенная в апострофы.

Вещественные константы

Вещественные константы используются для представления не толь-

ко целых, но и дробных величин.

Существуют несколько форматов представления вещественных кон-

стант:

##.##

##e[+-]##

[##].##[e[+-]##]

##.[##][e[+-]##]

Запись ## означает одну или несколько цифр.

В первом формате до десятичной точки и после нее должна стоять

хотя бы одна цифра. Это необходимо для того, чтобы модуль лексического

87

анализа PostgreSQL опознал значение как вещественную, а не целочислен-

ную константу. В других форматах хотя бы одна цифра должна стоять до

или после экспоненты, обозначенной буквой е. Наличие десятичной точки

и/или экспоненты отличает вещественные константы от целочисленных.

Логические константы

Допустимые обозначения логических констант: true, false, 't',

'f', 'true', 'false', 'y', 'n', 'yes', 'no', '1', '0'.

П.5. Операторы

В PostgreSQL поддерживаются стандартные операторы и функции

SQL, определенные в стандарте ANSI/ISO, – математические операторы,

основные функции форматирования текста, выделение компонентов да-

ты/времени и т.д. Кроме того, в PostgreSQL реализованы многочисленные

нестандартные расширения, в том числе операторы поиска по регулярным

выражениям (здесь не рассматриваются) и универсальная функция форма-

тирования данных to_char().

Операторы – это лексемы, предназначенные для выполнения опера-

ций с константами и идентификаторами и возвращающие результаты этих

операций. Некоторые ключевые слова SQL тоже считаются операторами

из-за воздействия на данные в командах SQL.

Действия, выполняемые оператором, зависят от контекста его при-

менения. Область применения операторов чрезвычайно широка, от выпол-

нения математических операций и конкатенации строк до разнообразных

сравнений.

П.5.1. Правила использования операторов

Оператор работает с одним операндом или с двумя операндами.

Большинство операторов работает с двумя операндами, между которыми

ставится сам оператор (например, a + b). Такие операторы называются

бинарными. Операторы, работающие с одним операндом, называются

унарными; в этом случае оператор либо предшествует операнду, либо сле-

дует за ним.

Некоторые операторы имеют несколько интерпретаций в зависимо-

сти от типа данных, к которым они применяются. С другой стороны, часть

операторов не имеет смысла для некоторых типов данных.

Например, оператор сложения (+) может использоваться для сумми-

рования двух целочисленных величин, но он не может прибавить целое

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

88

операторов в PostgreSQL указывается причина ошибки. Эта информация

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

П.5.2. Строковые операторы

Операторы сравнения строк

= Возвращает true, если первая строка точно совпадает со второй

!= Возвращает true, если первая строка не совпадает со второй

<> Идентичен оператору !=

< Возвращает true, если при лексикографической сортировке пер-

вая строка предшествует второй

<= Возвращает true, если при лексикографической сортировке пер-

вая строка предшествует второй или их значения совпадают

> Возвращает true, если при лексикографической сортировке вто-

рая строка предшествует первой

>= Возвращает true, если при лексикографической сортировке вто-

рая строка предшествует первой или их значения совпадают

Все операторы сравнения строк возвращают логическое значение

(true или false). Лексикографическая сортировка последовательно

сравнивает символы строк и определяет, какой из символов "больше" дру-

гого. Если начальные символы двух строк совпадают, проверяются следу-

ющие символы (слева направо). Перебор продолжается до тех пор, пока не

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

"больший" символ выбирается сравнением ASCII-кодов.

Конкатенация

Оператор конкатенации или, другими словами, оператор слияния

(||) играет важную роль при форматировании выходных данных. Он мо-

жет использоваться в командах SQL всюду, где могут использоваться кон-

станты. Допускается последовательная конкатенация строковых значений,

для этого перечисляемые строковые константы или идентификаторы раз-

деляются операторами ||.

Например, SELECT 'The Title: ' || title ||

', by ' || first_name || ' ' || last_name

FROM books, authors

WHERE books.author_id = authors.id;

89

П.5.3. Числовые операторы

Числовые операторы PostgreSQL делятся на три категории:

Математические операторы выполняют математическую опера-

цию с одним или двумя операндами и возвращают значение числового ти-

па.

Операторы сравнения проверяют заданное соотношение между

двумя числовыми величинами (например, что одна величина больше дру-

гой) и возвращают результат проверки в виде типа boolean.

Двоичные операторы работают на уровне отдельных битов, то есть

единиц и нулей в двоичном представлении.

Математические операторы

Математические операторы используются в целевых списках, в сек-

ции WHERE команды SELECT и вообще везде, где встречаются числовые

данные.

Оператор Синтаксис Описание

+ a+b Суммирование числовых величин a и b

- a-b Вычитание числовой величины b из a

* a*b Умножение числовых величин a и b

/ a/b Деление числовой величины a на b

% a%b Остаток от деления a на b

^ a^b Возведение a в степень b

|/ |/a Квадратный корень из a

||/ ||/a Кубический корень из a

! a! Факториал a

!! !!a Факториал a (отличается от постфиксного опера-

тора только расположением)

@ @a Модуль (абсолютное значение) a

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

от деления преобразуем к типу numeric с усечением до двух цифр в

дробной части. Из результата вычтем единицу, чтобы результат выражался

в доле меньше 1. SELECT isbn,

(retail/cost)::numeric(3.2)-1 AS margin

FROM stock

ORDER BY margin DESC;

Операторы сравнения

Операторы сравнения работают со значениями таких типов, как in-

teger или text, но всегда возвращают результат типа boolean. Они

90

часто встречаются в секции WHERE, но могут использоваться в любом кон-

тексте, в котором действителен тип boolean.

< Возвращает true, если левое значение меньше правого

> Возвращает true, если левое значение больше правого

<= Возвращает true, если левое значение меньше правого или

равно ему

>= Возвращает true, если левое значение больше правого или

равно ему

= Возвращает true, если левое значение равно правому

<> или != Возвращает true, если левое значение не равно правому

Сравнение с использованием ключевых слов

Ключевое слово BETWEEN (также иногда называемое оператором)

позволяет проверить, входит ли значение в некоторый интервал.

Например, получим книги, цена которых находится в интервале от

10 до 17 долларов: SELECT isbn

FROM stock

WHERE cost BETWEEN 10 AND 17;

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

<= в сочетании с оператором >=:

SELECT isbn

FROM stock

WHERE cost>=10 AND cost<=17;

П.5.4. Двоичные операторы

Оператор Синтаксис Описание

& a&b Поразрядная конъюнкция двоичных представле-

ний a и b (которые могут быть заданы в виде це-

лых чисел)

| a|b Поразрядная дизъюнкция двоичных представле-

ний a и b (которые могут быть заданы в виде це-

лых чисел)

# a#b Поразрядная операция исключающей дизъюнкции

двоичных представлений a и b (которые могут

быть заданы в виде целых чисел)

~ ~b Поразрядное отрицание, возвращает инвертиро-

ванную битовую последовательность b

91

<< b<<n Сдвиг b влево на n разрядов

>> b>>n Сдвиг b вправо на n разрядов

При сдвиге битовых последовательностей исходная длина строки не

изменяется, а разряды, выходящие за левый или правый край последова-

тельности, отсекаются. При использовании операторов &, | или # битовые

операнды должны иметь одинаковую длину.

Например, сдвинем число 8 на два разряда вправо: SELECT b'1000'>>2 AS "8 shifted right";

П.5.5. Логические операторы

Ключевые слова AND, OR и NOT являются логическими (булевыми)

операторами. Обычно они используются для операций с логическими

условиями в командах SQL, особенно в секциях WHERE и HAVING.

a b a AND b a OR b NOT a

true true true true false

true false false true false

true NULL NULL true false

false false false false true

false NULL false NULL true

NULL NULL NULL NULL NULL

П.5.6. Операторы и NULL

Если таблица содержит значения NULL, можно воспользоваться спе-

циальными операторами сравнения, чтобы учесть поля NULL при выборке

или игнорировать их. Конструкция IS NULL проверяет, содержит ли по-

ле значение NULL. Обратное условие проверяется конструкцией IS NOT

NULL.

Например, найдем авторов, у которых отсутствуют данные об имени: SELECT last_name, first_name

FROM authors

WHERE first_name IS NULL;

Все остальные операторы сравнения для операнда NULL возвращают

NULL, поскольку NULL никогда не бывает больше или меньше другой ве-

личины, отличной от NULL. Для псевдозначения NULL ни один оператор

92

сравнения (кроме IS NULL) не возвращает true, NULL не может участ-

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

П.5.7. Приоритет операторов

При работе с большими выражениями, содержащими несколько опе-

раторов, полезно знать, в каком порядке выполняются операторы. Непра-

вильно полагать, что операторы выполняются слева направо в порядке из

следования в выражении.

Приоритет операторов SQL:

Оператор Синтаксис Описание

:: значение :: тип Явное преобразование ти-

па

. таблица.поле Разделитель имен таблицы

и столбца

- -значение Унарный минус

^ основание ^ степень Возведение в степень

*, /, % значение1 * значение2 Умножение, деление и

остаток

+, - значение1 + значение2 Сложение и вычитание

IS значение IS признак Сравнение с true или false

IS NULL значение IS NULL Сравнение с NULL

IS NOT NULL значение IS NOT NULL Проверка несовпадения с

NULL

Прочее - Все остальные пользова-

тельские и встроенные

операторы, не входящие

ни в одну из категорий

IN значение IN набор Проверка принадлежности

к заданному набору

BETWEEN значение BETWEEN a AND b Проверка принадлежности

к интервалу [a, b]

LIKE, ILIKE строка LIKE шаблон Проверка совпадения

шаблона со строкой

<, >, <=, >= значение1 < значение2 Сравнение по критериям

"меньше", "больше",

"меньше либо равно",

"больше либо равно"

= значение1 = значение2 Проверка равенства

NOT NOT значение Логическое отрицание

93

AND значение1 AND значение2 Логическая конъюнкция

OR значение1 OR значение2 Логическая дизъюнкция

П.6. Функции

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

полнения программных операций в командах SQL. Функции всегда воз-

вращают одно значение, применяемое в команде SQL, из которой была вы-

звана функция.

П.6.1. Использование функций

При вызове функции в команде SQL указывается имя функции, по-

сле которого в круглых скобках перечисляются аргументы. В качестве ар-

гументов могут передаваться константы, допустимые идентификаторы или

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

ному типу данных полностью зависит от вызываемой функции. За именем

функции практически всегда обязательно следуют круглые скобки, даже

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

ны только для функций current_date, current_time и cur-

rent_timestamp.

Вызовы функций могут быть вложенными – при условии, что тип

данных, возвращаемый внутренней функцией, совместим с типом соответ-

ствующего аргумента внешней функции. Допускается вложение вызовов

на произвольную глубину.

В PostgreSQL существует множество стандартных функций, работа-

ющих со встроенными типами данных. Полный список функций выводит-

ся командой \df в клиенте psql. Кроме того, в PostgreSQL поддерживается

возможность определения пользовательских функций при помощи коман-

ды CREATE FUNCTION.

П.6.2. Математические функции

abs(x) Модуль (абсолютное значение) x

acos(x) Арккосинус x

asin(x) Арксинус x

atan(x) Арктангенс x

atan2(x, y) Арктангенс x/y

cbrt(x) Кубический корень x

94

ceil(x) Минимальное целое число, не меньшее x (округление в

верхнюю сторону)

cos(x) Косинус x

cot(x) Котангенс x

degrees(r) Количество градусов в r радиан

exp(x) Константа e (2,71823...) в степени x

floor(x) Максимальное целое число, не большее x (округление в

нижнюю сторону)

ln(x) Натуральный логарифм x (функция, обратная exp(x))

log(b, x) Логарифм x по основанию b

log(x) Десятичный логарифм x

mod(x, y) Остаток от деления x/y

pi() Возвращает константу (3,14159...)

pow(x, y) x в степени y

radians(d) Количество радиан в d градусов

random() Псевдослучайное число в интервале от 0,0 до 1,0

round(x) Число x, округленное до ближайшего целого

sin(x) Синус x

sqrt(x) Квадратный корень x

tan(x) Тангенс x

trunc(x) Целая часть x

trunc(x, s) Значение x, усеченное до s цифр в дробной части

П.6.3. Строковые функции

ascii(s) ASCII-код символа, переданного в

виде строковой переменной s

btrim(s [, t]) Строка s, в начале и конце которой

удалены все символы, входящие в

строку t (если аргумент t не задан,

усекаются начальные и конечные

пропуски – пробелы, символы табу-

ляции и т.д.)

char_length(s) Длина строки s в символах

chr(n) Символ с ASCII-кодом n

s ilike(f) true, если выражение f совпадает

(без учета регистра символов) с s

initcap(s) Строка s, в которой первая буква

каждого слова преобразуется к верх-

нему регистру

95

length(s) Длина строки s в символах

s like(f) true, если выражение f совпадает

с s

lower(s) Строка s, преобразованная к нижне-

му регистру

lpad(s, n [, c]) Строка s, дополненная слева содер-

жимым строки c (или пробелами, ес-

ли аргумент c не задан) до длины n

(или усеченная справа до n симво-

лов)

ltrim(s [, f]) Строка s, в начале которой удалены

все символы, входящие в строку f

(если аргумент f не задан, усекаются

начальные пропуски – пробелы, сим-

волы табуляции и т.д.)

octet_length(s) Длина строки s в байтах

position(b IN s) Позиция подстроки b в строке s (от-

счет начинается с 1)

repeat(s, n) Строка s, повторенная n раз

rpad(s, n [, c]) Строка s, дополненная справа со-

держимым строки с (или пробела-

ми, если аргумент с не задан) до

длины n (или усеченная слева до n

символов)

rtrim(s [, f]) Строка s, в конце которой удалены

все символы, входящие в строку f

(если аргумент f не задан, усекаются

конечные пропуски – пробелы, сим-

волы табуляции и т.д.)

strpos(s, b) Позиция подстроки b в строке s

(отсчет начинается с 1)

substr(s, n [, l]) Выделяет из строки s подстроку,

начинающуюся с позиции n (отсчет

начинается с 1). Необязательный ар-

гумент l определяет максимальную

длину подстроки в символах

substring(s FROM n FOR l) Выделяет из строки s подстроку,

начинающуюся с позиции n (отсчет

начинается с 1). Необязательный ар-

гумент l определяет максимальную

длину подстроки в символах

96

to_ascii(s, f) Строка s, преобразованная из рас-

ширенной кодировки f в ASCII

translate(s, f, r) Строка s, в которой все символы,

входящие в строку f, заменяются со-

ответствующими символами строки r

trim(направление f FROM s) Строка s, в начале и/или конце кото-

рой удалены все символы, входящие

в строку f. В аргументе направле-

ние передается ключевое слово SQL,

определяющее направление усечения

(LEADING, TRAILING или BOTH)

upper(s) Строка s, преобразованная к верхне-

му регистру

П.6.4. Функции для работы с датой и временем

current_date Текущая дата в виде значения типа date

current_time Текущее время в виде значения типа time

current_timestamp Текущие дата и время в виде значения типа

timestamp

date_part(s, t) Выделяет из значения типа timestamp компо-

нент даты или времени, определяемый строкой s

date_part(s, i) Выделяет из значения типа interval компо-

нент даты или времени, определяемый строкой s

date_trunc(s, t) Значение типа timestamp, усеченное до точно-

сти s. Под усечением понимается удаление всех

компонентов, детализация которых превышает

заданную

extract(k FROM t) Выделяет из значения типа timestamp компо-

нент даты или времени, определяемый ключе-

вым словом k

extract(k FROM i) Выделяет из значения типа interval компо-

нент даты или времени, определяемый ключе-

вым словом k

isfinite(t) true, если значение типа timestamp соответ-

ствует конечной величине (не invalid и не

infinity)

97

isfinite(i) true, если значение типа interval соответ-

ствует конечной величине (не infinity)

now() Текущие дата и время в виде значения типа

timestamp. Эквивалент константы now

timeofday() Текущие дата и время в виде значения text

Компоненты типов timestamp и interval, использующиеся в

функциях date_part(), date_trunc(), extract():

century Год, разделенный на 100 (не совпадает с текущим ве-

ком!)

day День месяца (от 1 до 31) для типа timestamp, продол-

жительность интервала в днях для типа interval

decade Год, разделенный на 10

dow День недели (от 0 до 6), начиная с воскресенья. Для ти-

па interval не поддерживается

doy День года (от 1 до 366). Для типа interval не под-

держивается

epoch Количество секунд от начала эпохи (1 января 1970 г.)

для типа timestamp, продолжительность интервала в

секундах для типа interval

hour Час в значении типа timestamp

microseconds Количество миллионных долей в дробной части секунд

для значения типа timestamp

millenium Год, разделенный на 1000 (не совпадает с текущим ты-

сячелетием!)

milliseconds Количество тысячных долей в дробной части секунд для

значения типа timestamp

minute Минуты в значении типа timestamp или interval

month Месяц в значении типа timestamp или остаток от де-

ления продолжительности интервала в месяцах на 12

для типа interval

quarter Квартал (от 1 до 4) для значений типа timestamp

second Секунды в значении типа timestamp или interval

week Номер недели в году для значений типа timestamp. В

стандарте ISO-8601 первая неделя года определяется

как неделя, в которую входит 4 января

year Год в значении типа timestamp или interval

98

П.6.5. Функции преобразования типа

bitfromint4(n) Преобразует число в битовую последователь-

ность

bittoint4(b) Преобразует битовую последовательность в де-

сятичное представление

to_char(n, f) Преобразует число в строку в формате f

to_char(t, f) Преобразует значение типа timestamp в строку

в формате f

to_date(s, f) Преобразует строку в формате даты f в значение

типа date

to_number(s, f) Преобразует строку в формате даты f в значе-

ние типа numeric

to_timestamp(s, f) Преобразует строку в формате даты f в значение

типа timestamp

timestamp(d) Преобразует значение типа date к типу

timestamp

timestamp(d, t) Преобразует два значения типов date и time к

типу timestamp

Функция to_char() для чисел

Функция to_char(), вызываемая с аргументом n типа numeric и

аргументом f типа text, форматирует число n в строку типа text. Стро-

ка f описывает формат выходного значения. Форматная строка f состоит

из метасимволов, вместо которых PostgreSQL подставляет представляемые

или значения.

Метасимволы форматирования чисел, используемые функциями

to_char() для чисел и to_number():

9 Цифра

0 Цифра или начальный/конечный ноль, если количество цифр в

f превышает количество цифр в n; может использоваться для

принудительного вывода цифр в левой или правой части ре-

зультата

. Точка, отделяющая целую часть числа от дробной. Число мо-

жет содержать только одну точку

, Запятая. Число может содержать несколько запятых, использу-

емых для разделения групп разрядов (тысячи, миллионы и т.д.)

D Десятичный разделитель (например, точка), определяемый в

локальном контексте

G Разделитель групп разрядов (например, запятая), определяе-

мый в локальном контексте

99

PR Если PR находится в конце строки f, для отрицательных зна-

чений n результат заключается в угловые скобки

SG Знак плюс (+) или минус (-) в зависимости от значения n

MI Знак минус (-), если число n является отрицательным

PL Знак плюс (+), если число n является положительным

S Знак плюс (+) или минус (-), определяемый в локальном кон-

тексте

L Денежный знак, определяемый в локальном контексте

RN Римские цифры для значений n в интервале от 1 до 3999

TH, th Суффикс числительного для числа n (например, 4th или 2nd)

V Для каждого метасимвола 9 после V добавляется лишний ноль,

то есть фактически происходит умножение на степень 10

FM Из числа удаляются все начальные и завершающие нули (со-

зданные символами 9, но не 0), а также все лишние пробелы

Если количество цифровых позиций, обозначенных метасимволом 9

в форматной строке, превышает количество цифр в числе n, лишние пози-

ции заполняются пробелами. Если лишние цифровые позиции обозначены

метасимволом 0, лишние позиции заполняются нулями.

Если количество заданных цифровых позиций меньше необходимого

для представления целой части числа, то во всех заданных позициях будет

выведен символ #. Следовательно, в форматную строку необходимо вклю-

чить максимальное количество цифр, которые могут быть получены в ре-

зультате форматирования.

В форматной строке можно свободно использовать любые символы,

не являющиеся метасимволами (например, символ $ и др.). В отформати-

рованной строке они выводятся без изменений.

Чтобы метасимвол интерпретировался в форматной строке букваль-

но (то есть как литерал), его следует заключить в кавычки. А чтобы вклю-

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

экранировать двумя обратными косыми чертами.

Например: SELECT to_char(1.0 '9th "Place"'),

to char(2.2, '9th "Place"'),

to_char(10, '99V99th "\\"Place\\""');

выведет 1st Place 2nd Place 1000th "Place"

Метасимволы форматирования даты и времени, использующиеся в

функциях to_char() для типа timestamp, to_date() и

to_timestamp():

HH, HH12 Час (от 1 до 12)

100

HH24 Час (от 1 до 23)

MI Минуты (от 0 до 59)

SS Секунды (от 0 до 59)

SSSS Секунды, прошедшие с полуночи (от 0

до 86 399)

AM, PM, A.M, P.M Обозначение части суток в верхнем ре-

гистре с необязательным разделением

символов точками

am, pm, a.m, p.m Обозначение части суток в нижнем ре-

гистре с необязательным разделением

символов точками

TZ, tz Часовой пояс в верхнем или нижнем

регистре

CC Век, представленный двумя цифрами

(не равен году, разделенному на 100!)

Y, YY, YYY, YYYY, Y.YYY Последняя цифра, две цифры, три или

четыре цифры года (с необязательным

включением запятой)

BC, AD, B.C, A.D Признак эры в верхнем регистре

bc, ad, b.c, a.d Признак эры в нижнем регистре

MONTH, Month, month Полное название месяца, дополненное

справа пробелами до 9 символов и за-

писанное либо в верхнем регистре, ли-

бо с начальной прописной буквой, либо

в нижнем регистре

MON, Mon, mon Сокращенное трехбуквенное обозначе-

ние месяца, записанное либо в верхнем

регистре, либо с начальной прописной

буквой, либо в нижнем регистре

MM Номер месяца (от 1 до 12)

RN, rn Номер месяца в римской записи (от I до

XII), в верхнем или нижнем регистре

DAY, Day, day Полное название дня недели, допол-

ненное справа пробелами до 9 симво-

лов и записанное либо в верхнем реги-

стре, либо с начальной прописной бук-

вой, либо в нижнем регистре

DY, Dy, dy Сокращенное двухбуквенное обозначе-

ние дня недели, записанное либо в

верхнем регистре, либо с начальной

прописной буквой, либо в нижнем ре-

гистре

101

DDD, DD, D День года (от 1 до 366), день месяца (от

1 до 31) или день недели (от 1 до 7,

начиная с воскресенья)

W Неделя месяца (от 1 до 5, с первого дня

месяца)

WW Неделя года (от 1 до 53, с первого дня

года)

IW Неделя года в стандарте ISO (с первого

четверга нового года)

TH, th Суффикс для предшествующего числа

в верхнем или нижнем регистре

fm Из строки удаляются все лишние нули

и пробелы

Суффикс TH и префикс FM должны непосредственно примыкать к

тому значению, которое они модифицируют. Например, FMDay, DDTH.

Запрос SELECT to_char(publication, 'FMMonth FMDDth, YYYY'),

to_char(publication, 'YYYY-MM-DD'),

to_char(publication, 'Y.YYY "years" A.D.')

FROM editions

LIMIT 1;

выведет March 1st, 1957 1957-03-01 1,957 years A.D.

102

СПИСОК ЛИТЕРАТУРЫ

1. Андон Ф. Язык запросов SQL. Учебный курс/ Ф. Андон, В. Резниченко.

– Спб. ; Киев : Питер : Изд. группа BHV, 2006. – 415с. : ил. – ISBN 5-

469-00394-9.

2. Грофф Джеймс Р., Вайнберг П. Энциклопедия SQL.-3-е изд. –СПб. :

Питер, 2003. – 895с. : ил+1 CD. – ISBN 966-552-103-9;5- 88782-077-2.

3. Дунаев В.В. Базы данных. Язык SQL – СПб. : БХВ-Петербург, 2006. –

288. : ил. ISBN 5-94157-823-7.

4. Моисеенко С. И. SQL. Задачи и решения / С. И. Моисеенко. – Спб. : Пи-

тер, 2006. – 255с. : ил. – ISBN 5-469-01362-6.

5. Полякова Л. Н. Основы SQL : учеб. пособие / Л. Н. Полякова – 2-е изд.,

испp. – М. : Интернет-Университет Информационных Технологий :

БИНОМ. Лаборатория знаний, 2007. – 223с. : ил. – (Основы информа-

ционных технологий). – ISBN 978-5-94774-649-5 ; 978-5-9556-0101-4.

6. СУБД : язык SQL в примерах и задачах : учеб. пособие для вузов /

И. Ф. Астахова, В. М. Мельников, А. П. Толстобров, В. В. Фертиков. –

М. : Физматлит, 2007. – 168с. : ил. – (Информационные и компьютер-

ные технологии). – ISBN 978-5-9221-0816-4.

7. Уорсли Дж., Дрейк Дж. PostgreSQL. Для профессионалов (+ CD). –

СПб. : Питер, 2003. – 496 с. : ил. ISBN 5-94723-337-1.

103

Для заметок

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

_______________________________________________________________

104

Учебное издание

Мотина Надежда Владимировна

Язык SQL

Методические указания к лабораторным работам

по курсам «Базы данных» и «Управление данными»

Технический редактор: Н.В. Мотина

Компьютерная верстка: О.В. Воробьева

Корректор: С. Н. Емельянова

Подписано в печать Формат 6090/16

Гарнитура Times New Roman. Усл. п.л.

Тираж 68 экз. Заказ № +4747

Адрес издательства:

Россия, 180000, Псков, ул. Л. Толстого, д. 4

Издательство ПсковГУ

Recommended