3 ОСНОВНЫЕ КОМАНДЫ SQL 3.1 Общие положения Изложенные выше механизмы РМД легли в основу языков манипулирования данными. Заметим, что крайне редко РА или РИ принимаются в качестве полной основы какого-либо языка РБД. Обычно язык основывается на некоторой смеси алгебраических и логических конструкций. Реализация концепции операций, ориентированных на табличное представление данных, позволило создать компактный язык с небольшим набором предложений – SQL. Этот язык может использоваться как интерактивный для выполнения запросов и как встроенный для построения прикладных программ. В современных СУБД обычно поддерживается единый интегрированный язык SQL, содержащий разнообразные средства для обеспечения базового пользовательского интерфейса при работе с БД. В нем можно выделить следующие группы команд: 1) команды определения данных (Data Definition Commands), которые служат для создания, изменения, удаления таблиц и индексов, а также для определения схемы БД; 2) команды манипулирования данными (Data Manipulation Commands) для изменения данных (редактирование существующих данных, добавление и удаление записей); 3) команды выборки данных (Data Query Commands) для выборки существующих данных; 4) команды управления транзакциями (Transaction Control Commands) для сохранения или отката изменений в БД; 5) команды управления данными (Data Control Commands) для проверки целостности БД, предоставления и отмены привилегий на доступ к данным. При этом SQL предоставляет и другие возможности, например, выполнение вычислений и преобразований, упорядочение записей и группировку данных. Особенность команд SQL cостоит в том, что они ориентированы в большей степени на конечный результат обработки данных, чем на процедуру этой обработки. SQL сам определяет, где находятся данные, какие индексы и последовательности операций следует использовать для их эффективного выполнения. Рассмотрим синтаксис основных команд SQL. При изложении материала будем использовать следующие обозначения: – звездочка (*) означает "все" и употребляется в обычном для программирования смысле, т.е. "все случаи, удовлетворяющие определению"; – квадратные скобки ([]) означают, что конструкции, заключенные в эти скобки, являются необязательными, т.е. могут быть опущены; – фигурные скобки ({}) означают, что конструкции, заключенные в эти скобки, должны рассматриваться как целые синтаксические единицы; эти скобки позволяют уточнить порядок разбора синтаксических конструкций, 28 заменяя обычные скобки, используемые в синтаксисе SQL; – многоточие (...) указывает на то, что непосредственно предшествующая ему синтаксическая единица факультативно может повторяться один или более раз; – прямая черта (|) означает наличие выбора из двух или более возможностей; например, конструкция [термин_1 | термин_2] означает, что можно выбрать один из двух терминов (или термин_1, или термин_2); при этом термин_1 выбирается по умолчанию; отсутствие всей этой конструкции будет восприниматься как выбор термин_1; – точка с запятой (;) завершающий элемент предложений SQL; этот знак должен присутсвовать после каждой команды; – запятая (,) используется для разделения элементов списков; – пробелы ( ) могут вводиться для повышения наглядности между любыми синтаксическими конструкциями предложений SQL; – прописные латинские буквы и символы используются для написания конструкций языка SQL и должны записываться без изменений; – строчные буквы используются для написания конструкций, которые должны заменяться конкретными значениями, выбранными пользователем, причем для определенности отдельные слова этих конструкций связываются между собой символом подчеркивания (_); – термины таблица, поле, ... заменяют с целью сокращения термины имя_таблицы, имя_поля, ... соответственно, – сочетание знаков ::= означает, что синтаксис должен иметь указанный вид. При составлении команд рекомендуется их комментировать. Комментарии в SQL обычно начинаются с двойного дефиса и заканчиваются символом новой строки. 3.2 Команды определения данных Команды определения данных иногда выделяют как отдельный язык DDL (Data Definition Language). Эти команды дают возможность создавать объекты БД (таблицы и индексы), определять их структуру, устанавливать свойства полей и поддержки целостности данных по ссылкам. Рассмотрим синтаксис команды создания таблицы. CREATE TABLE <имя таблицы> (<эл_табл> [{,<эл_табл>}...]) <Эл_табл> ::= <определение поля> | <определение ограничения на таблицу> <Определение поля> ::=<имя поля> <тип данных> [DEFAULT { <литерал> | NULL } ] раздел умолчания [NOT NULL [UNIQUE | PRIMARY KEY] ограничение на поле | [FOREIGN KEY(поле) REFERENCES <ссылочные таблицы и поля>] спецификация ссылок | [CHECK (<условии поиска>)] проверочное ограничение 29 Тип данных определяется реализацией. По стандарту имеем <Тип данных> ::=CHAR[ACTER] [(<длина>)] , строки символов | NUMERIC [(<точность> [,<масштаб>])] точный числовой тип | DEC[IMAL] [(<точность> [,<масштаб>])] | INT[EGER] | SMALLINT | FLOAT [(<точность>)] приближенный цифровой тип| | REAL | DOUBLE PRECISION <Длина> ::= <целое без знака>, которое должно быть больше 0 , если длина пропущена, то она предполагается равной 1. <Точность> ::= <целое без знака>, которое должно быть больше 0, если точность пропущена, то значение определяется в реализации. <Масштаб> ::= <целое без знака>, если он не указан, то предполагается 0. Если раздел умолчания отсутствует или в нем не указано NOT NULL, то неявно вводится DEFAULT NULL. В качестве <литерала> используется или символьная строка, или число в зависимости от типа данных поля. Рассмотрим ограничения для таблицы, которые фактически проверяются после выполнения каждого оператора SQL. <Определение ограничения на таблицу> ::= [UNIQUE | PRIMARY KEY (<имя поля> [{,<имя поля>}...])] уникальность | [FOREIGN KEY ( <имя поля> [{,<имя поля>}...] REFERENCES <имя таблицы> [(<имя поля> [{,<имя поля>}...)]] ограничения на ссылки | [CHECK (<условие поиска>)] проверочное ограничение Рассмотрим пример создания таблицы тСотрудники. Ее логическая структура приведена в табл. 3.1. Таблица 3.1 Логическая структура тСотрудники № Поле Тип 1 Код сотрудника Ч 2 Фамилия Т 3 Имя Т 4 Отчество Т 5 Пол Т 6 Дата рождения Д 7 Город Т 8 Дата приема Д 8 Дата увольнения Д Для удобства изложения примеры в данном разделе будем номеровать порядковыми числами. В конце команды не будем ставить никаких знаков (точка з запятой или точка). Также никаких знаков не будем применять при переносе команд по строкам. 30 Для удобства далее вместо полных имен будем использовать сокращения: тСотрудники → тС Код сотрудника → Код_с Дата рождения → Д_рожд Фамилия → Фам Дата приема → Д_пр Отчество → От Дата увольнения → Д_ув Команда создания тС 1) CREATE TABLE тС (Код_с INT NOT NULL , Фам C(15) NOT NULL, Имя C(15) NOT NULL, От C(15) NOT NULL, Д_рожд D NOT NULL, Пол C(1) NOT NULL DEFAULT 'Ж' CHECK (пол='Ж' OR пол='М'), Город C(10) DEFAULT 'Донецк' , Д_пр D NOT NULL, Д_ув D) В процессе изучения студент должен самостоятельно определить результаты выполнения команд, т.е. составить заголовок таблицы-результата и ее тело. Команда изменения таблиц ALTER TABLE используется для модификации существующей таблицы, например, для добавления полей или изменения ограничений на таблицу. 2) ALTER TABLE тС; ADD PRIMARY KEY Код_с Команда создания индексов CREATE INDEX позволяет определять простые и составные индексы, устанавливать ключи. Следует заметить, что синтаксис команд определения данных в различных СУБД может иметь отличия от стандарта. Для удаления объектов из БД используются команды: – удаления пустой таблицы DROP TABLE <имя таблицы>; – удаление индекса DROP INDEX <имя индекса>. Допустим создана копия тС с именем тС2. 3) DROB TABLE тC2. 3.3 Команды манипулирования данными В состав группы команд SQL, которые предназначены непосредственно для манипулирования реляционными данными и таблицами, входят операторы (команды): – вставки записей; – удаления записей; – модификации данных. 31 Синтаксис оператора вставки имеет вид INSERT INTO <имя_таблицы> [(<список полей>)] {VALUES (<список значений>)} [WHERE <спецификация выбора записей>] где <список значений> ::=<значение> [{,<значение>...}], <значение> ::= <спецификация значения> | NULL Если <список полей> не указывается, то в поля новой записи значения вносятся в том порядке, в котором эти поля созданы. При этом те поля, значения которых пропущены, принимают значения по умолчанию или NULL. 4) INSERT INTO тС VALUES (1, 'Андреев', 'Андрей', 'Андреевич', , , NULL) В случаях, когда необходимо ввести значения полей не во все поля, используется <список полей>. В этом случае число <значений> в <списке значений> должно быть равно числу имен в <списке полей>, а типы данных совпадать. 5) INSERT INTO тС (Код_с, Фам, Имя, От) VALUES (5, 'Андреев', 'Андрей', 'Андреевич') Допустим в результате манипулирования в тС были введены данные о 10 сотрудниках. Исходное состояние приведено в таблице 3.2. Таблица 3.2 Исходное состояние тС Код_с 1 2 3 4 5 6 7 8 9 10 Фам Андреев Борисов Васильев Владимиров Андреев Иванов Борисов Иванова Никитов Яковлева Имя Андрей Борис Василий Владимир Андрей Иван Борис Елена Никита Яна От Пол Д_рожд Андреевич М 01.01.1980 Борисович М 12.12.1982 Васильевич М 11.11.1981 Владимирович М 09.09.1979 Андреевич М 02.01.1980 Иванович М 05.05.1980 Борисович М 06.06.1986 Ивановна Ж 03.01.1980 Никитович М 09.09.1980 Яковлевна Ж 07.07.1987 Город Макеевка Макеевка Макеевка Донецк Макеевка Донецк Марьинка Донецк Донецк Макеевка Д_пр Д_ув 01.01.2007 01.12.2006 01.12.2006 01.12.2006 20.02.2007 01.02.2007 01.01.2007 01.12.2006 01.12.2006 31.01.2007 01.12.2006 15.02.2007 15.02.2006 С помощью команды INSERT можно извлечь записи из одной таблицы и разместить их в другой. 6) INSERT INTO тС2 SELECT * FROM тС WHERE Город = 'Донецк' При этом таблица тС2 должна быть предварительно создана и иметь структуру, идентичную таблице тС. Для обновления значений наиболее часто применяется поисковый оператор модификации, который имеет следующий формат 32 UPDATE <имя_таблицы> SET <установка> [{,<установка>}...] [WHERE <спецификация выбора записей>] где <установка>представляет собой выражение вида <имя_поля> ={ <значение> | NULL } 7) UPDATE тС2 SET Код_с = Код_с*2 WHERE Код_с>5 Поисковый оператор удаления имеет формат: DELETE FROM <ИД> [WHERE <спецификация выбора записей>] Если не указана опция отбора записей, то удаляются все строки ИД. 8) DELETE FROM тС2 WHERE Код_с>100 9) DELETE FROM тС2. 3.4 Команда выборки данных Одной из главных функций SQL считается выполнение выборки. Поэтому рассмотрим этот процесс подробно. Выборка – это обращение к БД с целью извлечь данные в виде, удобном для пользователя. Для выборки применяются запросы к БД. Иногда в SQL выделяют даже раздел, который называют языком запросов к данным DQL (Data Query Language). Фактически этот раздел языка ANSI SQL представлен только одной командой – SELECT. Но эта команда достаточно обширна. Она является ядром языка SQL. и используется для реализации операций проекции, ограничения, расширения. Для пользователя РБД оператор SELECT является, пожалуй, одним из наиболее главных и полезных операторов языка SQL. Этот оператор позволяет производить: – выбор данных (отбор записей и полей); – вычисления и сравнения; – упорядочение записей при выводе содержимого таблиц; – группирование данных и применение к этим группам специальных групповых операций. Источником данных (ИД) для запроса могут быть РТ или ранее созданные запросы. После выполнения запроса на выборку создается набор записей в виде временной рабочей таблицы, содержащей данные, которые отбираются из ИД согласно заданным условиям. В большинстве случаев с набором записей можно работать точно так же, как с таблицей: можно просматривать, выбирать и даже обновлять информацию. Однако в отличие от реальной таблицы, этот набор записей физически не существует в БД. Запрос с точки зрения пользователя можно рассматривать как шаблон, который создает набор записей из ИД только во время своего выполнения. При отсутствии данных результат представляет пустой набор записей. 33 Синтаксис инструкции SELECT определяется конструкциями, используемыми при реализации функций выборки. Инструкция в общем виде использует пять частей, которые делятся на две группы: основная часть SELECT [предикат] <список полей> выбрать FROM <список ИД> из дополнительные части [WHERE <спецификация выбора записей>] где [[GROUP BY <спецификация группировки>] группируя по [HAVING <спецификация выбора групп>]] имея [ORDER BY <спецификация сортировки>] упорядочить по. Рассмотрим синтаксис инструкции по частям. При этом учтем следующее: – инструкция языка SQL – это предложение (команда, оператор); – отдельные составные части инструкции (список полей, спецификация) – это опции предложения; – любая спецификация – это фраза, отвечающая требованиям синтаксиса предложения. Из синтаксиса видно, что – основная часть команды SELECT …FROM обязательна; – опция предикат необязательна – дополнительные части WHERE, GROUP BY, ORDER BY необязательны, они следуют за FROM; – опция HAVING не может применяться без GROUP BY. Рассмотрим опцию SELECT [предикат] <список полей>. Эта опция в основной части предложения позволяет выбрать данные из указанных столбцов и выполнить перед выводом их преобразование в соответствии с указанными выражениями или функциями. Предикат предназначен для ограничения числа возвращаемых записей. Предикат::= [ [ALL] все (обычно по умолчанию) | DISTINCT позволяет отобрать различные записи, исключает записи, содержащие повторяющиеся данные в отдельных полях; в результат включаются только уникальные значения каждого из полей, указанных в списке | TOP N ] отображение N первых записей. Список полей предназначен для определения тех полей, которіе отражаются в результате. <Список полей> ::= { эл_SELECT элемент списка [, эл2_SELECT] ...} Отметим, что для разделения элементов списка используются запятые. Рассмотрим синтаксис конструкции для элемента списка эл_SELECT::= 34 [ИД.] *| отбор всех полей | значение | SQL_функция | системная_переменная В свою очередь Значение ::= [ИД.] поле имя поля [AS псевдоним] заголовок поля [,[ИД.] полеК имя К-ого поля [AS псевдонимК] … ] заголовок К-ого поля | (выражение) | переменная | константа Текстовые константы должны заключаться в апострофы или двойные кавычки. Выражение::= ({[[+] |–] {значение | функция_СУБД}[+|–|*|**]} ... ) Функция_СУБД – это любая существующая функция. Для преобразования или вычисления значений могут применяться общеизвестные функции или выражения, содержащие такие функции. В качестве функции_СУБД могут также применяться специальные групповые (агрегирующие, статистические) SQL-функции, которые определяют одно значение по множеству значений поля-аргумента. SQL_функция ::= {SUM сумма | AVG среднее значение | MIN минимальное значение | MAX максимальное значение | COUNT} количество ( [[ALL] | DISTINCT] [ИД.] поле ) аргумент | ([ALL] выражение). Из SQL-функций можно составлять любые выражения, но их вложенность не допускается. Если вычисляются SQL-функции или выражения, содержащие такие функции, в список полей могут только те поля, которые являются аргументами SQL-функций. Наличие других полей в списке не допустимо. Ключевое слово DISTINCT используется для исключения полейдубликатов перед применением функций. Для функций МАХ и MIN это слово излишне. Для подсчета всех без исключения записей в таблице, включая дубликаты, используется специальная функция SQL_функция ::= COUNT(*). С этой функцией слово DISTINCT не допускается. Отметим специфику обработки неопределенных (пустых) значений (Null35 значения). Если значение аргумента – пустое множество, то – при наличии слова DISTINCT эти записи не учитываются; – функция COUNT возвратит значение нуль; – функция COUNT (*) обработает все записи так же, как обычные значения; – другие функции обычно возвращают Null-значение. Опция FROM <список ИД> определяет перечень тех ИД, из которых берутся поля для включения в результат запроса. Рассмотрим примеры применения команды SELECT c опциями SELECT и FROM. В качестве списка ИД будем рассматривать только один ИД, а именно тС. Таким образом, Список ИД::= тС. В процессе изучения команды выборки студент должен самостоятельно определить результаты выполнения команд, т.е. составить заголовок таблицырезультата и ее тело. Рекомендуется также указать, какую команду РА реализует соответствующая команда. Итак, наша первая команда выборки на SQL 10) SELECT * FROM тС → выборка всех сотрудников, выводятся все поля и все записи из тС, порядок вывода полей соответствует структуре тС, результат приведен в табл. 3.2. Определение “выборка сотрудников” конечно означает не выборку самих сотрудников, а выборку информации о них. Так как в качестве ИД взята тС, опция FROM тС будет присутствовать во всех командах данного подраздела Приведем примеры реализации операции проекции. 11) SELECT Код_с, Фам, Имя, От FROM тС 12) SELECT Фам FROM тС 13) SELECT DISTINCT Фам FROM тС Приведем примеры реализации операции расширения путем формирования вычисляемых полей. Рассчитаем возраст сотрудников по формуле год(дата_текущая) – год(д_рожд). 14) SELECT Код_с, Фам, (год(дата_текущая) – год(д_рожд)) “ вычисление возраста FROM тС Третье поле фактически не имеет имени. Задание имени результирующего поля не обязательно, но рекомендуется. В данном предложении год( ) – это встроенная функция конкректной СУБД. Обычно эта функция реализуется как year( ), а текущая дата – как date(). Таким образом обычно для реальных СУБД 15) SELECT Код_с, Фам, year(date()) – year(д_рожд) FROM тС или с заданием заголовка 36 16) SELECT Код_с, Фам, ’возраст=’, year(date()) – year(д_рожд) FROM тС Наиболее удобный результат дает команда 17) SELECT Код_с, Фам, year(date()) – year(д_рожд) Аs Возраст FROM тС 18) SELECT Фам, Сount(Код_с) FROM тС Данная команда ошибочна, так как список полей наряду с SQL-функцией содержит поле Фам, которое не является аргументом SQL-функции. Правильный синтаксис имеет команда 19) SELECT Count(Код_с) FROM тС. 10 20) SELECT Count(Код_с) AS КвоС, 10 Max([Д_рожд]) AS MaxДр, Count([Д_ув]) AS КвоУвол, 3 Min([Д_ув]) AS MinДув, FROM тС. Рассмотрим синтаксис других опций. Сначала рассмотрим опцию, которая используется для упорядочения записей ORDER BY <спецификация сортировки>. Спецификация сортировки задается фразой, определяющей список полей для упорядочения. Фраза имеет следующий синтаксис: <спецификация сортировки>::= {[ИД.] поле | ном_элем_SELECT} [[ASC] | DESC] [,{[ИД.] поле2 | ном_элем_SELECT2} [[ASC] | DESC]] ... Рассмотрим примеры применения опции ORDER. 21) SELECT Код_с, Фам, Имя, От FROM тС ORDER BY Код_с Обычно применяется более удобная для пользователя сортировка списков по трем полям 22) SELECT Код_с, Фам, Имя, От FROM тС ORDER BY Фам, Имя, От. Для реализации операции ограничения за счет задания условий отбора (выбора) записей используется опция WHERE <спецификация выбора записей>. Спецификация выбора записей задается фразой, которая включает набор условий для отбора записей <спецификация выбора записей>::= [NOT] WHERE_усл1 [[AND|OR][NOT] WHERE_усл2]... Как видно из синтаксиса, критерий отбора строк может формироваться из одного условия или из нескольких условий, соединенных логическими операторами AND, OR, [NOT]. 37 Для случая двух условий назначение логических операторов следующее: AND – должны удовлетворяться оба условия ; OR – должно удовлетворяться одно из условий; AND NOT – должно удовлетворяться первое условие (усл1) и не должно второе условие (усл2); OR NOT – или должно удовлетворяться усл1 или не должно удовлетворяться усл2. При отборе существует приоритет AND над OR: сначала выполняются все операции AND и только после этого выполняются операции OR. Для условия отбора можно записать следубщий синтаксис WHERE_усл ::= знач { = | <> | < | <= | | = } { знач | (подзапрос) } знач_1 [NOT] BETWEEN знач_2 AND знач_3 между знач [NOT] IN { ( конст [,конст]... ) | (подзапрос) } принадлежит знач IS [NOT] NULL не определено [ИД.] поле [NOT] LIKE 'строка_символов' похоже на [ESCAPE 'символ'] не включает EXISTS (подзапрос) существует При сравнении обычно действуют следующие правила обработки условий: – числа сравниваются алгебраически; отрицательные числа считаются меньшими, чем положительные, независимо от их абсолютной величины; – строки символов сравниваются в соответствии с их представлением в коде, используемом в конкретной СУБД, например, в коде ASCII; – если сравниваются две строки символов, имеющих разные длины, то перед выполнением операции сравнения их длина уравнивается до большей за счет добавления пробелов справа в короткой строке. Для получения желаемого результата условия отбора должны быть заданы в правильном порядке, который можно организовать введением скобок. Рассмотрим примеры применения опции WHERE. 23) SELECT Фам, Д_рожд FROM тС WHERE Д_рожд = '01-01-1980' символьная строка 24) SELECT Фам, Д_рожд FROM тС WHERE Д_рожд BETWEEN '01-01-1980' AND '31-12-1980' В операторе BETWEEN знач_2 должно быть меньше или равно знач_3. 25) SELECT Фам FROM тС WHERE Д_рожд = '01-01-1980' AND Город = “Донецк”; 26) SELECT * FROM тС WHERE Город= “Донецк” OR Город= “Макеевка”. В последнем примере для краткой записи последовательности отдельных сравнений, соединенных операторами OR, можно применить форму IN 27) SELECT * FROM тС WHERE Город IN (“Донецк”, “Макеевка”). При использовании в условии формы LIKE 'строка_символов' 38 интерпретация зависит от заданных символов так: символ _ (подчеркивание) заменяет любой одиночный символ; символ % (процент) заменяет любую последовательность из N символов, где N может быть нулем; все другие символы означают сами себя. Например 28) SELECT * FROM тС WHERE Город LIKE “М%” Очень редко, но в поля вносятся знаки “_” и “%”. В этом случае для их поиска применяются дополнительные escape-символы, которые должны предшествовать знакам. Рассмотрим образец поиска вида LIKE ‘_/_а’ ESCAPE ‘/’. В этом выражении символ '/’ объявлен escape-символом. Первый символ “_” в заданном шаблоне поиска будет соответствовать, как и ранее, любому символу в проверяемой строке. Второй символ “_”, следующий после escapeсимвола, будет интерпретироваться как обычное подчеркивание. Аналогично, символ 'а' будет интерпретироваться как буква а. Для проверки содержимого поля на наличие в нем Null-значения предназначены специальные операторы IS NUll (является пустым) и IS NOT NULL (является не пустым). Другие операторы сравнения использовать нельзя. 29) SELECT * FROM тС WHERE Д_ув Like ' %' результат Null 30) SELECT * FROM тС WHERE Д_ув IS NULL При использовании функций происходит расчет их значений по всему набору записей, определенных условием отбора 31) SELECT Фам, COUNT(Код_с) FROM тС WHERE Город = “Донецк” ошибка 32) SELECT COUNT(Код_с) As Количество FROM тС WHERE Город = “Донецк” Рассмотрим опцию, которая применяется для группировки записей GROUP BY <спецификация группировки>. Спецификация группировки записей используется при создании группировочных запросов и задается фразой вида <спецификация группировки>::= [ИД.] поле имя поля [,[ИД.] полеK] ... имя K-го поля Группирование записей инициирует перекомпоновку записей по группам, каждая из которых имеет одинаковое значение в полях, включенных в спецификации групировки. 33) SELECT Фам FROM тС GROUP BY Фам В результате этой команды происходит исключение записей-дубликатов. 34) SELECT Город FROM тС GROUP BY Город. К группам данных можно применить агрегирующие SQL-функции. Для 39 этого их нужно указать в списке полей вывода. Применение SQL-функций приводит к замене всех значений группы на единственное значение, определенной SQL-функцией (сумма, количество и т.п.). Группирование записей позволяет реализовать реляционную операцию подведения итогов. 35) SELECT Фам, Count(Код_с) AS Кол FROM тС GROUP BY Фам В этой команде происходит группировка по полю Фам, которое включено в список полей вывода. 36) SELECT Город, COUNT(Код_с) FROM тС GROUP BY Город Надо учитывать, что опция GROUP BY не предполагает упорядочение. Поэтому рекомендуется одновременно с ней применять и опцию ORDER BY. 37) SELECT Город, COUNT(Код_с) FROM тС GROUP BY Город ORDER BY Город Рассмотрим опцию отбора групп записей: HAVING <спецификация выбора групп>. В результат попадают только те группы, которые удовлетворяют заданной спецификации выбора групп. Ее синтаксис подобен синтаксису спецификации выбора записей: <спецификация выбора групп>::= [NOT] HAVING_усл [[AND|OR][NOT] HAVING_усл2]... Синтаксис HAVING_усл почти не отличается от синтаксиса WHERE_усл. Только наряду со значениями в этих условиях могут использоваться SQLфункции. HAVING_усл ::= знач { = | < | < | <= | | = } { знач | (подзапрос) | SQL_функция } {знач_1 | SQL_функция_1} [NOT] BETWEEN {знач_2 | SQL_функция_2} AND {знач_3 | SQL_функция_3} {знач | SQL_функция} [NOT] IN { ( конст [,конст]... ) | (подзапрос) } {знач | SQL_функция} IS [NOT] NULL [табл.] поле [NOT] LIKE 'строка_символов' [ESCAPE 'символ'] EXISTS (подзапрос) Рассмотрим пример с опцией HAVING. 38) SELECT * FROM тС GROUP BY Город HAVING COUNT (*) < 5 Мы рассмотрели команды с одним ИД – тС. В общем виде в качестве источника запроса могут использоваться несколько ИД. Причем, в качестве ИД могут использоваться не только базовые таблицы РБД, хранящиеся в физической памяти машины, но и результаты выполнения ранее созданных запросов, которые в основном представляются в виде виртуальных (временных, рабочих) таблиц. Некоторые СУБД дают возможность создавать представления БД или курсоры, которые фактически 40 являются хранимыми в РБД запросами с именованными полями. С их помощью создаются виртуальные таблицы, позволяющие пользователям иметь свой взгляд на данные без увеличения их объема в БД. В списке источников команды SELECT должны быть перечислены все ИД, из которых берутся поля для формирования запроса: Список ИД ::={таблица | запрос | представление} [псевдоним] [,{таблица2 | запрос2 | представление2} [псевдоним2]] ... где псевдоним служит для временного (на момент выполнения запроса) переименования и (или) создания рабочей копии ИД. При включении в запрос полей нескольких ИД небходимо указывать полные имена полей в виде <имя ИД>. <имя поля>, например, тС.Код_с. При включении в запрос нескольких ИД можно нестрого утверждать, что опция FROM соответствует их произведению. Следовательно, можно сделать вывод, что команда SELECT языка SQL реализует значительную часть операций РА. При этом можно определить следующее соответствие опций команды SELECT и операций РА: – SELECT ↔ проекция и расширение; – FROM ↔ произведение; – WHERE ↔ ограничение. Иными словами, совместная инструкция SELECT-FROM-WHERE представляет собой проекцию выборки произведения. В общем случае выборка может содержать объединение нескольких других ранее созданных выборок. Стандарт SQL дает следующую расширенную формулировку: Оператор SELECT ::= подзапрос [UNION объединить [ALL] подзапрос] ... В качестве подзапросов могут участвовать объекты, перечисленные в списке ИД. Команда допускает общую опцию сортировки ORDER BY. 3.5 Реализация операций реляционной алгебры Еще раз последовательно рассмотрим основные операции РА на примерах. Для каждой операции РА выполним следующие действия: 1) составим реляционное выражение; 2) определим результат выполнения операции (теоретический); 3) составим SQL-команду запроса для реализации указанной операции. При подготовке конспекта запросы были реализованы средствами СУБД. Идентичность теоретического и практического результатов позволил сделать выводы о правильной реализации операций РА средствами SQL-команд. Рассмотрим сначала унарные операции. В качестве примера рассмотрим таблицу тG 41 A B C D 1 B1 C1 D1 3 B3 C1 D1 4 B4 C2 D2 8 B8 C6 D2 10 B1 C1 D3 Для наглядности имена полей выделены жирным шрифтом, а числа в значениях поля В выбраны такими, что они соответствует значениям поля А. Исключение составляет запись А=10, когда В=1 (т.е. 10 без 0). Данная таблица относится к РТ. Сформулируем ее основные свойства: 1) кардинальное число (количество записей) – 5; 2) степень (количество полей ) – 4; 3) ключевое поле – А; 4) таблицы упорядочены по полю А; 5) функциональные зависимости отсутствуют. Ограничение тG Where A>3 A B C D 4 B4 C2 D1 8 B8 C6 D3 10 B1 C1 D2 Реализация SELECT тG.* FROM тG WHERE (тG.A>3) Напомним, что для получения РТ в результате запроса обязательно необходимо исключать повторяющиеся записи. Это можно выполнять путем применения предикатов или группировки. Проекция тG [B, C] B C B1 C1 B3 C1 B4 C2 B8 C6 Для получения требуемой проекции применим SQL-команду с группировкой: SELECT тG.B, тG.C FROM тG ROUP BY тG.B, тG.C Далее рассмотрим бинарные операции. Для этого рассмотрим две таблицы: тG и тQ. тQ A B C 1 B1 C1 2 B2 C1 3 B3 C1 4 B4 C2 5 B5 C3 Для тQ очевидны следующие свойства РТ: 1) кардинальное число – 5; 42 2) степень – 3; 3) ключевое поле – А; 4) таблица упорядочены по полю А. Будем считать, что задана только часть тQ и в целом значение любого поля не зависит от значения другого, т.е. в тQ отсутствуют функциональные зависимости. Большинство свойств у тG и тQ одинаковы, за исключением разной степени, т.е. количества полей. Для выполнения основных операций добьемся совместимости таблиц по типу и уравняем количество полей. Исключим из тG поле D и создадим не запрос, а новую таблицу тR. Для этого применим операцию проекции, исключающую поле D тR := тG [A,B,C] A B C 1 B1 C1 3 B3 C1 4 B4 C2 8 B8 C6 10 B1 C1 Проекцию можно, как и ранее, осуществить за счет выборки с группировкой. Для разнообразия применим SQL-команду с предикатом: SELECT DISTINCT тG.A, тG.B, тG.C INTO тR FROM тG ORDER BY тG.A. Отметим, что предикат DISTINCTROW в данном случае запроса к одной таблице был бы проигнорирован. Теперь таблицы тR и тQ совместимы по типу. С ними можно проводить бинарные операции РА. Для удобства результаты будем сортировать по полю А, но опцию порядочения ORDER BY тR.A [,тQ.A] в SQL-команду и конечный знак (;) записывать не будем. Объединение тR Union тQ A B C 1 B1 C1 2 B2 C1 3 B3 C1 4 B4 C2 5 B5 C3 8 B8 C6 10 B1 C1 Для правильного практического результата можно применить одну из двух команд: SELECT тR.* FROM тR UNION SELECT тQ.* FROM тQ SELECT * FROM тR UNION SELECT * FROM тQ 43 Пересечение тR Intersect тQ A B C 1 B1 C1 3 B3 C1 4 B4 C2 Для правильного результата можно применить одну из двух команд: а) пересечение за счет общего объединения по полю А SELECT тR.A, тR.B, тR.C FROM тQ INNER JOIN тR ON тQ.A=тR.A б) пересечение за счет условий отбора SELECT тR.A, тR.B, тR.C FROM тR, тQ WHERE ((тR.A=тQ.A) AND (тR.B=тQ.B) AND (тR.C=тQ.C)) Разность тR Minus тQ A B C 8 B8 C6 10 B1 C1 Для правильной практической реализации запроса достаточно проверить только одно поле на значение Null SELECT тR.A, тR.B, тR.C FROM тR LEFT JOIN тQ ON тR.A = тQ.A WHERE (тQ.B Is Null) Разность тQ Minus тR A B C 2 B2 C1 5 B5 C3 SELECT тQ.* FROM тQ LEFT JOIN тR ON тQ.A = тR.A WHERE (тR.B Is Null) Произведение может применяться только к таблицам, которые не имеют одинаковых имен полей. Так как мы оперируем с полными именами полей, включающими и имена полей, и имена источников, то можно считать, что это условие выполняется. тR Times тQ тR.A тR.B тR.C тQ.A тQ.B тQ.C 1 B1 C1 1 B1 C1 1 B1 C1 2 B2 C1 1 B1 C1 3 B3 C1 1 B1 C1 4 B4 C2 44 1 3 3 3 3 3 4 4 4 4 4 8 8 8 8 8 10 10 10 10 10 B1 B3 B3 B3 B3 B3 B4 B4 B4 B4 B4 B8 B8 B8 B8 B8 B1 B1 B1 B1 B1 C1 C1 C1 C1 C1 C1 C2 C2 C2 C2 C2 C6 C6 C6 C6 C6 C1 C1 C1 C1 C1 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 B5 B1 B2 B3 B4 B5 B1 B2 B3 B4 B5 B1 B2 B3 B4 B5 B1 B2 B3 B4 B5 C3 C1 C1 C1 C2 C3 C1 C1 C1 C2 C3 C1 C1 C1 C2 C3 C1 C1 C1 C2 C3 Ниже приведены три идентичные команды, которые дают одинаковый результат а) SELECT тR.*, тQ.* FROM тR, тQ б) SELECT тR.A, тR.B, тR.C, тQ.A, тQ.B, тQ.C FROM тR, тQ в) SELECT * FROM тR, тQ; Соединение R Join Q по С тR.A тR.B C тQ.A тQ.B 1 B1 C1 1 B1 1 B1 C1 2 B2 1 B1 C1 3 B3 3 B3 C1 1 B1 3 B3 C1 2 B2 3 B3 C1 3 B3 4 B4 C2 4 B4 10 B1 C1 1 B1 10 B1 C1 2 B2 10 B1 C1 3 B3 SELECT тR.A, тR.B, тR.C, тQ.A, тQ.B FROM тR INNER JOIN тQ ON тR.C = тQ.C 45 Условное больше-соединение по А тR Join тQ WHERE тR.A > тQ.A тR.A тR.B тR.C тQ.A тQ.B тQ.C 3 B3 C1 1 B1 C1 3 B3 C1 2 B2 C1 4 B4 C2 1 B1 C1 4 B4 C2 2 B2 C1 4 B4 C2 3 B3 C1 8 B8 C6 1 B1 C1 8 B8 C6 2 B2 C1 8 B8 C6 3 B3 C1 8 B8 C6 4 B4 C2 8 B8 C6 5 B5 C3 10 B1 C1 1 B1 C1 10 B1 C1 2 B2 C1 10 B1 C1 3 B3 C1 10 B1 C1 4 B4 C2 10 B1 C1 5 B5 C3 SELECT * FROM тR, тQ WHERE тR.A > тQ.A Условное равно-соединение по А тR Join тQ WHERE тR.A = тQ.A тR.A тR.B тR.C тQ.A тQ.B тQ.C 1 B1 C1 1 B1 C1 3 B3 C1 3 B3 C1 4 B4 C2 4 B4 C2 SELECT * FROM тR, тQ WHERE тR.A=тQ.A Композиция тR + тQ (по В) тR.A тR.C тQ.A тQ.C 1 C1 1 C1 3 C1 3 C1 4 C2 4 C2 10 C1 1 C1 SELECT тR.A, тR.C, тQ.A, тQ.C FROM тR, тQ WHERE тR.B = тQ.B 46