SQL1

         

АГРЕГАТЫ, ПОСТРОЕННЫЕ НА СКАЛЯРНОМ ВЫРАЖЕНИИ


До этого вы использовали агрегатные функции с одиночными полями как аргументами. Вы можете также использовать агрегатные функции с аргументами, которые состоят из скалярных выражений, включающих одно или более полей. (Если вы это делаете, DISTINCT не разрешается.)

Предположим, что таблица Заказов имеет ещё один столбец, который хранит предыдущий неуплаченный баланс (поле blnc) для каждого заказчика. Вы должны найти этот текущий баланс добавлением суммы приобретений к предыдущему балансу.

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

SELECT MAX (blnc + (amt)) FROM Orders;

Для каждой строки таблицы этот запрос будет складывать blnc и amt для данного заказчика и выбирать самое большое значение, которое он найдёт. Конечно, пока заказчики могут иметь несколько заказов, их неуплаченный баланс оценивается отдельно для каждого заказа. Возможно, заказ с более поздней датой будет иметь самый большой неуплаченный баланс. Иначе старый баланс должен быть выбран, как в запросе выше.

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



ALL ВМЕСТО DISTINCT


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



ANY И ALL ВМЕСТО EXISTS С NULL


Значения NULL также имеют некоторые проблемы с операторами вроде этих. Когда SQL сравнивает два значения в предикате, одно из которых пустое (NULL), то результат неизвестен (смотрите Главу 5). Неизвестный предикат подобен неверному и является причиной того, что строка не выбирается, но работать он будет иначе в некоторых похожих запросах, в зависимости от того, используют они ALL или ANY вместо EXISTS.

Рассмотрим наш предыдущий пример:

SELECT * FROM Customers WHERE rating > ANY (SELECT rating FROM Customers WHERE city = 'Rome');

и ещё один пример:

SELECT * FROM Customers outer WHERE EXISTS (SELECT * FROM Customers inner WHERE outer.rating > inner.rating AND inner.city = 'Rome');

В общем, эти два запроса будут вести себя одинаково. Но предположим, что появилось пустое (NULL) значение в столбце rating таблицы Заказчиков:

CNUM CNAME CITY RATING SNUM



2003 Liu SanJose NULL 1002

В варианте с ANY, где оценка Liu выбрана основным запросом, значение NULL делает предикат неизвестным, а строка Liu не выбирается для вывода. Однако в варианте с NOT EXISTS, когда эта строка выбрана основным запросом, значение NULL используется в предикате подзапроса, делая его неизвестным в каждом случае. Это означает что подзапрос не будет производить никаких значений и EXISTS будет неправилен. Это, естественно, делает оператор NOT EXISTS верным. Следовательно, строка Liu будет выбрана для вывода. Это основное расхождение, в отличие от других типов предикатов, где значение EXISTS, независимо от того, верно оно или нет, всегда неизвестно. Всё это является аргументом в пользу варианта формулировки с ANY. Мы не считаем, что значение NULL является выше, чем допустимое значение. Более того, результат будет тот же, если мы будем проверять для более низкого значения.



АВТОМАТИЧЕСКИЕ ВНЕШНИЕ ОБЪЕДИНЕНИЯ


В Главе 14 мы обсуждали внешнее объединение и показывали вам, как выполнять его, используя команду UNION. Некоторые программы баз данных имеют более непосредственный способ выполнения внешних объединений. В некоторых реализациях вводимый знак " + " после предиката может выводить строки, которые удовлетворяют условию, так же как и строки, которые ему не удовлетворяют. В условии предиката может содержаться поле, совпадающее для обеих таблиц, и NULL-значения будут вставлены там, где такого совпадения не будет найдено.

Например, предположим, вы хотите видеть ваших продавцов и соответствующих им заказчиков, не исключая тех продавцов, которым не назначено ни одного заказчика (хотя такого нет в наших типовых таблицах, но в действительности это возможно):

SELECT a.snum, sname, cname FROM Salespeople a, Customers b WHEREa.snum = b.snum(+);

Это является эквивалентом следующего объединения (UNION):

SELECT a.snum, sname, cname FROM Salespeople a, Customers b WHERE a.snum = b.snum

UNION

SELECT snum, sname, '_ _ _ _ _ _ _ _ _ _' FROM Salespeople WHERE snum NOT IN (SELECT snum FROM Customers);

Предполагается, что подчёркивания будут отображены NULL-значениями (см. команду FORMAT ранее в этом приложении, где описывалось отображение NULL-значениями).



BEGIN DECLARE SECTION (НАЧАТЬ РАЗДЕЛ ОБЪЯВЛЕНИЙ)


Синтаксис

EXEC SQL BEGIN DECLARE SECTION <SQL term> <host-language variable declarations> EXEC SQL END DECLARE SECTION <SQL term>

Эта команда создает главный раздел программы для объявления в ней главных переменных, которые будут использоваться во вкладываемых операторах SQL. Переменная SQLCODE должна быть включена как одна из объявляемых переменных главного языка.



БОЛЬШЕ ПСЕВДОНИМОВ


Хотя объединение таблицы с собой это первая ситуация, когда ясна необходимость наличия псевдонимов, вы не ограничены в их использовании тем, чтобы только отличать копию одной таблицы от её оригинала. Вы можете использовать псевдонимы в любое время, когда вы хотите создать альтернативные имена для ваших таблиц в команде. Например, если ваши таблицы имеют очень длинные и сложные имена, вы могли бы определить простые односимвольные псевдонимы, типа a и b, и использовать их вместо имён таблиц в предложении SELECT и предикате. Они будут также использоваться с соотнесенными подзапросами (обсуждаемыми в Главе 11).



БУЛЕВЫ ОПЕРАЦИИ


Основные булевы операции также распознаются в SQL. Выражения Буля являются или верными/true, или неверными/false, подобно предикатам. Булевы операции связывают одно или более верных/неверных значений и производят единственное верное или неверное значение.

Стандартными булевыми операциями, распознаваемыми в SQL, являются AND, OR и NOT.

=============== SQL Execution Log ============ | | | SELECT * | | FROM Customers | | WHERE rating > 200; | | ============================================= | | snum cname city rating snum | | ----- -------- -------- ----- ----- | | 2004 Crass Berlin 300 1002 | | 2008 Cirneros San Jose 300 1007 | =============================================

Рисунок 4.1 Использование операции "больше" (>)

Существуют другие, более сложные булевы операции (типа "исключающее ИЛИ"), но они могут быть сформированы из этих трёх простых операций - AND, OR, NOT.

Как вы можете понять, булева логика верно/неверно основана на цифровой компьютерной операции; и фактически весь SQL (или любой другой язык) может быть сведён до уровня булевой логики.

Булевы операции, и как они работают:

AND берет два булевых значения (в форме A AND B) как аргументы и оценивает, верны ли они оба.

OR берет два булевых значения (в форме A OR B) как аргументы и оценивает, верен ли один из них.

NOT берет одиночное булево значение (в форме NOT A) как аргумент и заменяет его значение с неверного на верное или с верного на неверное (инвертирует).

Связывая предикаты с булевыми операциями, вы можете значительно расширить их возможности. Предположим, вы хотите видеть всех заказчиков в San Jose, которые имеют оценку (рейтинг) выше 200:

SELECT * FROM Customers WHERE city = " San Jose' AND rating > 200;

Вывод для этого запроса показан на Рисунке 4.2. Имеется только один заказчик, который удовлетворяет этому условию.

=============== SQL Execution Log ============ | | | SELECT * | | FROM Customers | | WHERE city = 'San Jose' | | AND rating > 200; | | ============================================= | | сnum cname city rating snum | | ------ -------- -------- ---- ----- | | 2008 Cirneros San Jose 300 1007 | =============================================


Рисунок 4.2 SELECT, использующий AND

Если же вы используете OR, вы получите всех заказчиков, которые находились в San Jose или (OR) которые имели оценку выше 200.

SELECT * FROM Customers WHERE city = " San Jose' OR rating > 200;

Вывод для этого запроса показан на Рисунке 4.3.

=============== SQL Execution Log ============ | | | SELECT * | | FROM Customers | | WHERE city = 'San Jose' | | OR rating > 200; | | ============================================= | | сnum cname city rating snum | | ----- ------- -------- ----- ------ | | 2003 Liu San Jose 200 1002 | | 2004 Grass Berlin 300 1002 | | 2008 Cirneros San Jose 300 1007 | =============================================

Рисунок 4.3 SELECT, использующий OR

NOT может использоваться для инвертирования булевых значений.

Имеется пример запроса с NOT:

SELECT * FROM Customers WHERE city = " San Jose' OR NOT rating > 200;

Вывод этого запроса показан на Рисунке 4.4.

=============== SQL Execution Log ============ | | | SELECT * | | FROM Customers | | WHERE city = 'San Jose' | | OR NOT rating > 200; | | ============================================= | | cnum cname city rating snum | | ------ -------- ------ ----- ----- | | 2001 Hoffman London 100 1001 | | 2002 Giovanni Rome 200 1003 | | 2003 Liu San Jose 200 1002 | | 2006 Clemens London 100 1001 | | 2008 Cirneros San Jose 300 1007 | | 2007 Pereira Rome 100 1004 | =============================================

Рисунок 4.4 SELECT, использующий NOT

Все записи, за исключением Grass, были выбраны. Grass не был в San Jose, и его оценка была больше, чем 200, так что он потерпел неудачу при обеих проверках. В каждой из других строк встретился тот или другой, или оба критерия.

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

rating NOT > 200

Он выдаст другую отметку. А как SQL оценит следующее?



SELECT * FROM Customers WHERE NOT city = " San Jose' OR rating > 200;

NOT применяется здесь только к выражению city = 'SanJose', или к выражению rating > 200 тоже? Как уже было сказано, правильный ответ будет прежним: SQL может применять NOT с булевым выражением, которое идёт только сразу после него. Вы можете получить другой результат при команде:

SELECT * FROM Customers WHERE NOT(city = " San Jose' OR rating > 200);

Здесь SQL понимает круглые скобки как означающие, что всё внутри них будет вычисляться в первую очередь и обрабатываться как единое выражение с помощью всего, что снаружи них (это является стандартной интерпретацией, как в математике). Другими словами, SQL берет каждую строку и определяет, соответствует ли истине равенство city = 'San Jose' или равенство rating > 200.

Если любое условие верно, булево выражение внутри круглых скобок верно. Однако, если булево выражение внутри круглых скобок верно, предикат как единое целое неверен, потому что NOT преобразует верно в неверно и наоборот.

Вывод для этого запроса показан на Рисунке 4.5. Имеется намеренно усложнённый пример. Сможете ли вы проследить его логику (вывод показан на Рисунке 4.6)?

SELECT * FROM Orders WHERE NOT ((odate = 10/03/1990 AND snum >1002) OR amt > 2000.00);

=============== SQL Execution Log ============ | | | SELECT * | | FROM Customers | | WHERE NOT (city = 'San Jose' | | OR rating > 200); | | ============================================= | | cnum cname city rating snum | | ----- -------- ------- ----- ------ | | 2001 Hoffman London 100 1001 | | 2002 Giovanni Rome 200 1003 | | 2006 Clemens London 100 1001 | | 2007 Pereira Rome 100 1004 | =============================================

Рисунок 4.5 SELECT, использующий NOT и вводное предложение

=============== SQL Execution Log ============== | | | SELECT * | | FROM Orders | | WHERE NOT ((odate = 10/03/1990 AND snum > 1002) | | OR amt > 2000.00); | | =============================================== | | onum amt odate cnum snum | | ------ -------- ---------- ----- ----- | | 3003 767.19 10/03/1990 2001 1001 | | 3009 1713.23 10/04/1990 2002 1003 | | 3007 75.75 10/04/1990 2004 1002 | | 3010 1309.95 10/06/1990 2004 1002 | =================================================



Рисунок 4.6 Полный (комплексный) запрос

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

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

Вот подробное объяснение того, как пример выше был вычислен. Наиболее глубоко вложенные булевы выражения, в предикате это odate = 10/03/1990 и snum > 1002, объединяются с помощью AND, формируя одно булево выражение, которое будет оценено как верное для всех строк, в которых встретились оба эти условия. Это составное булево выражение (которое мы будем называть булево номер 1, или B1, для краткости) объединяется с выражением (amt) > 2000.00 (B2) с помощью OR, формируя третье выражение (B3), которое является верным для данной строки, если или B1 или B2 верны для этой строки.

B3 полностью содержится в круглых скобках, которым предшествует NOT, формируя последнее булево выражение (B4), которое является условием предиката.

Таким образом, B4 - предикат запроса - будет верен всякий раз, когда B3 неправилен. B3 неправилен всегда, когда B1 и B2 оба неверны. B1 неправилен для строки, если дата строки заказа не 10/03/1990 или если значение snum не больше, чем 1002. B2 неправилен для всех строк, значение суммы приобретений которых не превышает 2000.00. Любая строка со значением выше 2000.00 сделает B2 верным; в результате B3 будет верен, а B4 - нет. Следовательно, все эти строки будут удалены из вывода.

Из оставшихся, строки, которые на 3 октября имеют snum > 1002 (такие как строки для onum 3001 на 3 октября с snum = 1007), делают B1 верным с помощью верного B3 и неверного предиката запроса. Они будут также удалены из вывода. Вывод показан для строк, которые оставлены.


ЧТО ДЕЛАЕТ ANSI?


Как мы уже сказали во Введении, стандарт SQL определяется с помощью кода ANSI (Американский Национальный Институт Стандартов). SQL не изобретался ANSI. Это, по существу, изобретение IBM. Но другие компании подхватили SQL сразу же. По крайней мере одна компания (Oracle) отвоевала у IBM право на рыночную продажу SQL-продуктов.

После того как появился ряд конкурирующих программ SQL на рынке, ANSI определил стандарт, к которому они должны быть приведены. (Определение таких стандартов и является функцией ANSI). Однако после этого появились некоторые проблемы. Возникли они, в результате стандартизации ANSI, в виде некоторых ограничений. Так как не всегда ANSI определяет то, что является наиболее полезным, то программы пытаются соответствовать стандарту ANSI, не позволяя ему ограничивать их слишком сильно. Это, в свою очередь, ведет к случайным несогласованностям. Программы Баз Данных обычно придают ANSI SQL дополнительные особенности и часто ослабляют многие ограничения. Поэтому распространённые разновидности ANSI будут также рассмотрены. Хотя мы, очевидно, не сможем рассмотреть каждое исключение или разновидность, удачные идеи имеют тенденцию к внедрению и использованию в различных программах, даже когда они не определены стандартом ANSI. ANSI это вид минимального стандарта, и вы можете делать больше, чем он позволяет, хотя и должны выполнять его указания при выполнении задач, которые он определяет.



ЧТО НЕ МОГУТ ДЕЛАТЬ ПРЕДСТАВЛЕНИЯ?


Имеется большое количество типов представлений (включая многие из наших примеров в этой главе), которые являются доступными только для чтения. Это означает, что их можно запрашивать, но они не могут подвергаться действиям команд модификации. (Мы будем рассматривать эту тему в Главе 21.) Имеются также некоторые виды запросов, которые недопустимы в определениях представлений.

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

ОБЪЕДИНИТЬ (UNION) и ОБЪЕДИНИТЬ ВСЁ (UNION ALL) не разрешаются.

УПОРЯДОЧИТЬ ПО (ORDER BY) никогда не используется в определении представлений.

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



ЧТО СЛУЧИТСЯ, ЕСЛИ ВЫ ВЫПОЛНИТЕ КОМАНДУ МОДИФИКАЦИИ?


Давайте условимся, что все внешние ключи созданные в наших таблицах примеров, объявлены и предписаны с ограничениями внешнего ключа следующим образом:

CREATE TABLE Salespeople (snum integer NOT NULL PRIMARY KEY, sname char(10) NOT NULL, city char(10), comm decimal);

CREATE TABLE Customers (cnum integer NOT NULL PRIMARY KEY, cname char(10) NOT NULL, city char(10), rating integer, snum integer, FOREIGN KEY (snum) REFERENCES Salespeople, UNIQUE (cnum, snum) ;

CREATE TABLE Orders (cnum integer NOT NULL PRIMARY KEY, amt decimal, odate date NOT NULL, cnum integer NOT NULL snum integer NOT NULL FOREIGN KEY (cnum, snum) REFERENCES CUSTOMERS (cnum, snum);



ЧТО ТАКОЕ АГРЕГАТНЫЕ ФУНКЦИИ?


Запросы могут производить обобщённое групповое значение полей точно так же, как и значение одного поля. Это делается с помощью агрегатных функций. Агрегатные функции производят одиночное значение для всей группы таблицы.

Вот список этих функций:

COUNTвыдаёт количество строк или не-NULL значений полей, которые выбрал запрос.

SUMвыдаёт арифметическую сумму всех выбранных значений данного поля.

AVGвыдаёт усреднение всех выбранных значений данного поля.

MAXвыдаёт наибольшее из всех выбранных значений данного поля.

MINвыдаёт наименьшее из всех выбранных значений данного поля.



ЧТО ТАКОЕ "ПОЛЬЗОВАТЕЛЬ"?


SQL обычно находится в компьютерных системах, которые имеют больше чем одного пользователя и, следовательно, должен различать их (ваше семейство PC может иметь любое число пользователей, но оно обычно не имеет способов, чтобы отличать одного пользователя от другого).

Обычно в такой системе каждый пользователь имеет некий вид кода проверки прав, который идентифицирует его или её (терминология изменяется). В начале сеанса с компьютером пользователь входит в систему (регистрируется), сообщая компьютеру, кто этот пользователь, идентифицируясь с помощью определенного ID (Идентификатора). Любое количество людей, использующих ID доступа, являются отдельными пользователями; и, аналогично, один человек может представлять большое количество пользователей (в разное время), используя различные идентификаторы доступа к SQL. Действия в большинстве сред SQL приведены к специальному Идентификатору доступа, который точно соответствует определённому пользователю. Таблица или другой объект принадлежит пользователю, который имеет над ним полную власть. Пользователь может или может не иметь привилегии на выполнение действия над объектом. Для наших целей мы договоримся, что любой пользователь имеет необходимые привилегии для выполнения любого действия, пока мы не возвратимся специально к обсуждению привилегий в Главе 22. Специальное значение USER (ПОЛЬЗОВАТЕЛЬ) может использоваться как аргумент в команде. Оно указывает на доступный Идентификатор пользователя, выдавшего команду.



ЧТО ТАКОЕ ПРЕДСТАВЛЕНИЕ?


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

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



ЧТО ТАКОЕ "РЕЛЯЦИОННАЯ БАЗА ДАННЫХ"?


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

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

Предположим, что вы должны сформатировать эту адресную книгу в виде таблицы со строками и столбцами. Каждая строка (называемая также записью) будет соответствовать определённой личности; каждый столбец будет содержать значение для каждого типа данных: имени, телефонного номера и адреса, представляемых в каждой строке.

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

Gerry Farish(415)365-8775127 Primrose Ave.,SFCelia Brock(707)874-3553246 #3rd St.,SonomaYves Grillet(762)976-3665778 Modernas,Barcelona

То, что вы получили, является основой реляционной базы данных, как и было определено в начале этого обсуждения, а именно - двухмерной (строка и столбец) таблицей информации.

Однако РБД редко состоят из одной таблицы. Такая таблица меньше, чем файловая система. Создав несколько таблиц взаимосвязанной информации, вы сможете выполнять более сложные и мощные операции с вашими данными. Мощность БД зависит от связи, которую вы можете создать между фрагментами информации, а не от самого фрагмента информации.



ЧТО ТАКОЕ - ВЛОЖЕНИЕ SQL?


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

В основном вы будете использовать команды SQL для работы в таблицах баз данных, передачи результатов вывода в программу и получение ввода из программы, в которую они вкладываются, обобщённо ссылаясь к главной программе (которая может или не может принимать их из диалога или посылать обратно в диалог пользователя и программы).



ЧТО ТАКОЕ ЗАПРОС?


Запрос это команда, которую вы даёте вашей программе базы данных и которая сообщает ей, что нужно вывести определённую информацию из таблиц в память. Эта информация обычно посылается непосредственно на экран компьютера или терминала, которым вы пользуетесь, хотя в большинстве случаев её можно также послать на принтер, сохранить в файле (как объект в памяти компьютера) или предоставить как вводную информацию для другой команды или процесса.



CLOSE CURSOR (ЗАКРЫТЬ КУРСОР)


Синтаксис

EXEC SQL CLOSE CURSOR <cursor name> <SQL term>;

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



COMMIT (WORK) (ПОДТВЕРДИТЬ (ТРАНЗАКЦИИ))


Синтаксис

COMMIT WORK;

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



CREATE INDEX (СОЗДАТЬ ИНДЕКС)


(*NONSTANDARD*) (НЕСТАНДАРТНАЯ)

Синтаксис

CREATE [UNIQUE] INDEX <Index name>
ON <table name> (<column list>);

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



CREATE SYNONYM (*NONSTANDARD*) (СОЗДАТЬ СИНОНИМ) (*НЕСТАНДАРТНЫЙ*)


Синтаксис

CREATE IPUBLICl SYNONYM <synonym> FOR
<owner>.<table name>;

Эта команда создает альтернативное (синоним) имя таблицы. Синоним принадлежит его создателю, а сама таблица - обычно другому пользователю. Используя синоним, его владелец может не ссылаться на таблицу её полным (с включением имени владельца) именем. Если PUBLIC указан, синоним принадлежит каталогу SYSTEM и, следовательно, доступен всем пользователям.



CREATE TABLE (СОЗДАТЬ ТАБЛИЦУ)


Синтаксис

CREATE TABLE <table name>
({<column name> <data type>[<size>]

[<colconstralnt> . . .]
[<defvalue>]} . , . . <tabconstraint> . , . .);

Команда создает таблицу в базе данных. Эта таблица будет принадлежать её создателю. Столбцы будут рассматриваться в поимённом порядке.

<data type> определяет тип данных, которые столбец будет содержать. Стандарт <data type> описывается в Приложении B; все прочие используемые типы данных <data type> обсуждались в Приложении C. Значение размера <size> зависит от типа данных <data type>.

<colconstraint> и <tabconstraint> налагают ограничения на значения, которые могут быть введены в столбце.

<defvalue> определяет значение (по умолчанию), которое будет вставлено автоматически, если никакого другого значения не указано для этой строки. (См. в Главе 17 подробности о самой команде CREATE TABLE и в Главах 18 И 19 - подробности об ограничениях и о <defvalue>).



CREATE VIEW (СОЗДАТЬ ПРОСМОТР)


Синтаксис

CREATE VIEW <table name>

AS <query>

[WITH CHECK OPTION];

Просмотр обрабатывается как любая таблица в командах SQL. Когда команда ссылается на имя таблицы <table name>, запрос <query> выполняется, и его вывод соответствует содержанию таблицы, указанной в этой команде.
Некоторые просмотры могут модифицироваться, что означает, что команды модификации могут выполняться в этих просмотрах и передаваться в таблицу, на которую была ссылка в запросе <query>. Если указано предложение WITH CHECK OPTION, эта модификация должны также удовлетворять условию предиката <predicate> в запросе <query>.



DECLARE CURSOR (ОБЪЯВИТЬ КУРСОР)


Синтаксис

EXEC SQL DECLARE <cursor name> CURSOR FOR
<query><SQL term>

Эта команда связывает имя курсора <cursor name> с запросом <query>. Когда курсор открыт (см. OPEN CURSOR ), запрос <query> выполняется, и его результат может быть выбран (командой FETCH) для вывода. Если курсор - модифицируемый, таблица, на которую ссылается запрос <query>, может получить изменение содержания с помощью операции модификации в курсоре (См. в Главе 25 о модифицируемых курсорах).



ДЕЙСТВИЕ ОГРАНИЧЕНИЙ


Как ограничения воздействуют на возможность и невозможность использования команды модификации DML? Для полей, определённых как внешние ключи, ответ довольно простой: любые значения, которые вы помещаете в эти поля командой INSERT или UPDATE, должны уже быть представлены в их родительских ключах. Вы можете помещать пустые (NULL) значения в эти поля, несмотря на то что значения NULL непозволительны в родительских ключах, если они имеют ограничение NOT NULL. Вы можете удалять (DELETE) любые строки с внешними ключами, не используя родительские ключи вообще.

Поскольку затронут вопрос об изменении значений родительского ключа, ответ, по определению ANSI, ещё проще, но, возможно, несколько более ограничен: любое значение родительского ключа, на который ссылаются с помощью значения внешнего ключа, не может быть удалено или изменено. Это означает, например, что вы не можете удалить заказчика из таблицы Заказчиков, пока он ещё имеет заказы в таблице Заказов. В зависимости от того, как вы используете эти таблицы, это может быть или желательно, или хлопотно. Однако это, конечно, лучше, чем иметь систему, которая позволит вам удалить заказчика с текущими заказами и оставить таблицу Заказов ссылающейся на несуществующих заказчиков. Смысл этой системы ограничения в том, что создатель таблицы Заказов, используя таблицу Заказчиков и таблицу Продавцов как родительские ключи, может наложить значительные ограничения на действия в этих таблицах. По этой причине вы не сможете использовать таблицу которой вы не распоряжаетесь (т.е. не вы её создавали и не вы являетесь её владельцем), пока владелец (создатель) этой таблицы специально не передаст вам на это право (что объясняется в Главе 22).

Имеются некоторые другие возможные действия изменения родительского ключа, которые не являются частью ANSI, но могут быть найдены в некоторых коммерческих программах. Если вы хотите изменить или удалить текущее ссылочное значение родительского ключа, имеются три возможности:

*    Вы можете ограничить или запретить изменение (способом ANSI), обозначив, что изменения в родительском ключе ограничены.


*    Вы можете сделать изменение в родительском ключе и тем самым сделать изменения во внешнем ключе автоматическим, что называется каскадным изменением.

*    Вы можете сделать изменение в родительском ключе и установить внешний ключ в NULL автоматически (полагая, что NULL разрешены во внешнем ключе), что называется пустым изменением внешнего ключа.

Даже в пределах этих трёх категорий вы можете не захотеть обрабатывать все команды модификации таким способом. INSERT, конечно, к делу не относится. Она помещает новые значения родительского ключа в таблицу, так что ни одно из этих значений не может быть вызвано в данный момент. Однако вы можете захотеть позволить модификациям быть каскадными, но без удалений, и наоборот.

Лучшей может быть ситуация, которая позволит вам определять любую из трёх категорий, независимо от команд UPDATE и DELETE. Мы будем, следовательно, ссылаться на эффекты модификации (update effects) и эффекты удаления (delete effects), которые определяют, что случится, если вы выполните команды UPDATE или DELETE в родительском ключе. Эти эффекты, о которых мы говорили, называются: Ограниченные (RESTRICTED) изменения, Каскадируемые (CASCADES) изменения и Пустые (NULL) изменения.

Фактические возможности вашей системы должны строго соответствовать стандарту ANSI - это эффекты модификации и удаления, оба автоматически ограниченные - для более идеальной ситуации, описанной выше. В качестве иллюстрации мы покажем несколько примеров того, что вы можете делать с полным набором эффектов модификации и удаления. Конечно, эффекты модификации и удаления, являющиеся нестандартными средствами, испытывают недостаток в стандартном синтаксисе. Синтаксис, который мы используем здесь, прост в написании и будет служить в дальнейшем для иллюстрации функций этих эффектов.

Для полноты эксперимента позволим себе предположить, что вы имеете причину изменить поле snum  таблицы Продавцов в случае, когда наша таблица Продавцов изменяет разделы. (Обычно изменение первичных ключей это не то, что мы рекомендуем делать практически. Просто это ещё один из доводов, чтобы иметь первичные ключи, которые не умеют делать ничего другого, кроме как действовать как первичные ключи: они не должны изменяться.)



Когда вы изменяете номер продавца, вы хотите, чтобы были сохранены все его заказчики. Однако, если этот продавец покидает свою фирму или компанию, вы можете не захотеть удалить его заказчиков при удалении его самого из БД. Взамен вы захотите убедиться, что заказчики назначены кому-нибудь ещё. Чтобы сделать это, вы должны указать UPDATE с Каскадируемым эффектом, и DELETE с Ограниченным эффектом.

CREATE TABLE Customers (cnum integer NOT NULL PRIMARY KEY, cname char(10) NOT NULL, city char(10), rating integer, snum integer REFERENCES Salespeople, UPDATE OF Salespeople CASCADES, DELETE OF Salespeople RESTRICTED);

Если вы теперь попробуете удалить Peel из таблицы Продавцов, команда будет недопустима, пока вы не измените значение поля snum заказчиков Hoffman и Clemens для другого назначенного продавца. С другой стороны, вы можете изменить значение поля snum для Peel на 1009, и Hoffman и Clemens будут также автоматически изменены.

Третий эффект - Пустые (NULL) изменения. Бывает, что, когда продавцы оставляют компанию, их текущие заказы не передаются другому продавцу. С другой стороны, вы хотите отменить все заказы автоматически для заказчиков, чьи счета вы удалите. Изменив номера продавца или заказчика, можно просто передать их ему. Пример ниже показывает, как вы можете создать таблицу Заказов с использованием этих эффектов.

CREATE TABLE Orders (onum integer NOT NULL PRIMARY KEY, amt decimal, odate date NOT NULL cnum integer NOT NULL REFERENCES Customers snum integer REFERENCES Salespeople, UPDATE OF Customers CASCADES, DELETE OF Customers CASCADES, UPDATE OF Salespeople CASCADES, DELETE OF Salespeople NULLS);

Конечно, в команде DELETE с эффектом Пустого изменения в таблице Продавцов, ограничение NOT NULL должно быть удалено из поля snum.


DELETE (УДАЛИТЬ)


Синтаксис

DELETE FROM <table name>

{ [WHERE <predicate>]; }

| WHERE CURRENT OF <cursorname><SQL term>

Если предложение WHERE отсутствует, ВСЕ строки таблицы удаляются. Если предложение WHERE использует предикат <predicate>, строки, которые удовлетворяют условию этого предиката <predicate>, удаляются. Если предложение WHERE имеет аргумент CURRENT OF (ТЕКУЩИЙ) в имени курсора <cursor name>, строка из таблицы <table name>, на которую в данный момент имеется ссылка с помощью имени курсора <cursor name>, будет удалена. Форма WHERE CURRENT может использоваться только во вложенном SQL и только с модифицируемыми курсорами.



DISTINCT С ПОДЗАПРОСАМИ


В некоторых случаях вы можете использовать DISTINCT чтобы вынудить подзапрос генерировать одиночное значение. Предположим что мы хотим найти все порядки кредитования для тех продавцов, которые обслуживают Hoffman'а (cnum = 2001).

Вот способ сделать это (вывод показан на Рисунке 10.2):

SELECT * FROM Orders WHERE snum = (SELECT DISTINCT snum FROM Orders WHERE cnum = 2001);

=============== SQL Execution Log ============== | | | SELECT * | | FROM Orders | | WHERE snum = | | (SELECT DISTINCT snum | | FROM Orders | | Where cnum = 2001); | | =============================================== | | onum amt odate cnum snum | | ----- --------- --------- ------ ------- | | 3003 767.19 10/03/1990 2001 1001 | | 3008 4723.00 10/05/1990 2006 1001 | | 3011 9891.88 10/06/1990 2006 1001 | ================================================

Рисунок 10.2 Использование DISTINCT для получения одного значения из подзапроса

Подзапрос установил, что значение поля snum совпало с Hoffman - 1001, а затем основной запрос выделил все заказы с этим значением snum из таблицы Заказов (не разбирая, относятся они к Hoffman или нет). Так как каждый заказчик назначен продавцу, мы знаем, что каждая строка в таблице Заказов с данным значением cnum должна иметь такое же значение snum. Однако, поскольку там может быть любое число таких строк, подзапрос мог бы вывести много (хотя и идентичных) значений snum для данного поля cnum. Аргумент DISTINCT предотвращает это. Если наш подзапрос возвратит более одного значения, это будет указывать на ошибку в наших данных - хорошая вещь для знающих об этом.

Должен быть и альтернативный подход, чтобы ссылаться к таблице Заказчиков, а не к таблице Заказов в подзапросе. Так как поле cnum это первичный ключ таблицы Заказчиков, запрос, выбирающий его, должен выдать только одно значение. Это рационально, только если вы как пользователь имеете доступ к таблице Заказов, но не к таблице Заказчиков. В этом случае вы можете использовать решение, которое мы показали выше. (SQL имеет механизмы, которые определяют, кто имеет привилегии на выполнение действий в определённой таблице. Это будет объясняться в Главе 22.)

Пожалуйста, учтите, что методика, используемая в предшествующем примере, применима, только когда вы знаете, что два различных поля в таблице должны всегда совпадать, как в нашем случае. Эта ситуация не является типичной в реляционных базах данных (РБД), она является исключением из правил.



ДРУГИЕ ФУНКЦИИ


Эта функция может быть применена к любому типу данных.

ИмяТелефонАдрес

ФУНКЦИЯЗНАЧЕНИЕ

ДРУГИЕ СПОСОБЫ БЛОКИРОВКИ ДАННЫХ


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

Страница это блок накопления памяти, обычно равный 1024 байт. Страница может состоять из одной или более строк таблицы, возможно, сопровождаемых индексами и другой сопутствующей информацией, а может состоять даже из нескольких строк другой таблицы. Если вы блокируете страницы вместо строк, все данные в этих страницах будут блокированы точно так же, как и в индивидуальных строках, согласно уровням изоляции, описанным выше.

Основным преимуществом такого подхода является эффективность. Когда SQL не следит за блокированностью и разблокированностью строк индивидуально, он работает быстрее. С другой стороны, язык SQL был разработан так, чтобы максимизировать свои возможности, и произвольно блокирует строки, которые не обязательно было блокировать. Похожая возможность доступна в некоторых системах - это блокировка областей DBS. Области базы данных имеют тенденцию быть больше, чем страница, так что этот подход удовлетворяет и достоинству увеличения производительности и недостатку блокирования страниц. Вообще-то лучше отключать блокировку низкого уровня, если вам кажется, что появились значительные проблемы с эффективностью.



ДРУГИЕ ТИПЫ ПРИВИЛЕГИЙ


Вы, разумеется, хотите знать, кто же имеет право первым создать таблицу. Эта область привилегий не относится к ANSI, но не может игнорироваться. Все стандартные привилегии ANSI вытекают из этой привилегии - привилегии создателей таблиц, которые могут передавать привилегии объекта. Если все ваши пользователи будут создавать в системе базовые таблицы с разными размерами, это приведет к избыточности в них и к неэффективности системы.

Возникают и другие вопросы:

Кто имеет право изменять, удалять или ограничивать таблицы?

Должны ли права создания базовых таблиц отличаться от прав создания представлений?

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

Пока ANSI не принимает в этом участия, а SQL используется в различных средах, мы не можем дать окончательный ответ на эти вопросы. Мы предлагаем рассмотреть здесь часть наиболее общих выводов.

Привилегии, которые не определяются в терминах специальных объектов данных, называются привилегиями системы или правами базы данных. На базисном уровне они будут, вероятно, включать в себя право создавать объекты данных, возможно, отличающиеся от базовых таблиц (обычно создаваемых несколькими пользователями) и представлений (обычно создаваемых большинством пользователей).

Привилегии системы для создания представлений должны дополнять, а не заменять привилегии объекта, которые ANSI требует от создателей представлений (описанных ранее в этой главе). Кроме того, в системе любого размера всегда имеются некоторые типы суперпользователей - пользователей, которые автоматически имеют большинство или все привилегии и которые могут передать свой статус суперпользователя кому-нибудь с помощью привилегии или группы привилегий. Администратор Базы Данных (DBA) является термином наиболее часто используемым для такого суперпользователя и для привилегий, которыми он обладает.



ДРУГОЕ ИСПОЛЬЗОВАНИЕ КАТАЛОГА


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

SELECT a.tname, a.cname, iname, cposition FROM SYSTEMCOLUMNS a, SYSTEMINDEXES b WHERE a.tabowner = b. tabowner AND a.tname = b.tname AND a.cnumber = b.cnumber ORDER BY 3 DESC, 2;

Она показывает два индекса: один - для таблицы Заказчиков и один - для таблицы Продавцов. Последний из них это одностолбцовый индекс с именем salesno в поле snum; он был помещён первым из-за сортировки по убыванию (в обратном алфавитном порядке) в столбце iname. Другой индекс, custsale, используется продавцами, чтобы отыскивать своих заказчиков. Он основывается на комбинации полей snum и cnum внутри таблицы Заказчиков с полем snum, приходящим в индексе первым, как это и показано с помощью поля cposition.

=============== SQL Execution Log ================ | | | SELECT a.tname, a.cname, iname, cposition | | FROM SYSTEMCOLUMNS a, SYSTEMINDEXES b | | WHERE a.tabowner = b.tabowner | | AND a.tname = b.tname | | AND a.cnumber = b.cnumber | | ORDER BY 3 DESC, 2; | | | | ================================================= | | tname cname iname cposition | | ----------- ------- -------- ------------ | | Salespeople sname salesno 1 | | Customers cnum custsale 2 | | Customers snum custsale 1 | | | ===================================================

Рисунок 24.9 Столбцы и их индексы

Подзапросы также могут быть использованы. Имеется способ увидеть данные столбца только для столбцов из таблиц каталога:

SELECT * FROM SYSTEMCOLUMNS WHERE tname IN (SELECT tname FROM SYSTEMCATALOG);

Для упрощения мы не будем показывать вывод этой команды, которая состоит из одного входа для каждого столбца каждой таблицы каталога. Вы могли бы поместить этот запрос в представление, назвав его, например, SYSTEMTABCOLS, для представления SYSTEMTABLES.



ДРУГОЕ ИСПОЛЬЗОВАНИЕ ПЕРЕМЕННОЙ INDICATOR


Переменная indicator также может использоваться для просвоения NULL-значения. Просто добавьте её к имени главной переменной в команде UPDATE или INSERT тем же способом, что и в команде SELECT. Если переменная indicator имеет отрицательное значение, значение NULL будет помещено в поле.

Например, следующая команда помещает значения NULL в поля city и comm таблицы Продавцов всякий раз, когда переменные indicator i_a или i_b будут отрицательными; в противном случае она помещает туда значения главных переменных:

EXEC SQL INSERT INTO Salespeople VALUES (:Id_num, :salesperson, :loc:i_a, :comm:i_b);

Переменная indicator также используется, чтобы показывать отбрасываемую строку. Это произойдет, если вы вставляете значения символов SQL в главную переменную, которая недостаточно длинна, чтобы вместить все символы. Это особая проблема с нестандартным типами данных VARCHAR и LONG (смотри Приложение C). В этом случае переменная будет заполнена первыми символами строки, а последние символы будут потеряны. Если используется переменная indicator, в неё будет установлено положительное значение, указывающее на длину отбрасываемой части строки, позволяя таким образом узнать, сколько символов было потеряно. В этом случае вы можете проверить с помощью просмотра значение переменной indicator > 0 или < 0.



EXEC SQL (ВЫПОЛНИТЬ SQL)


Синтаксис

EXEC SQL <embedded SQL command> <SQL term>

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



EXISTS И АГРЕГАТЫ


Одна вещь которую EXISTS не может сделать - использовать функцию агрегата в подзапросе. Это имеет значение. Если функция агрегата находит любые строки для операций с ними, EXISTS верен, невзирая на то, что это значение функции; если же агрегатная функция не находит никаких строк, EXISTS неправилен.

=============== SQL Execution Log ============ | | | SELECT DISTINCT snum | | FROM Salespeople outer | | WHERE NOT EXISTS | | (SELECT * | | FROM Customers inner | | WHERE inner.snum = outer.snum | | AND inner.cnum < > outer.cnum); | | ============================================= | | cnum | | ----- | | 1003 | | 1004 | | 1007 | =============================================

Рисунок 12.4 Использование EXISTS с NOT

Попытка использовать агрегаты с EXISTS таким способом, вероятно, покажет, что проблема неверно решалась от начала до конца. Конечно, подзапрос в предикате EXISTS может также использовать один или более из его собственных подзапросов. Они могут иметь любой из различных типов, с которыми мы уже знакомы (или познакомимся далее). Такие подзапросы и любые другие в них позволяют использовать агрегаты, если нет другой причины, по которой они не могут быть использованы. Следующий раздел приводит этому пример. В любом случае вы можете получить тот же самый результат более легко, выбрав поле, которое вы использовали в агрегатной функции, вместо использования самой этой функции. Другими словами, предикат

EXISTS (SELECT COUNT (DISTINCT sname) FROM Salespeople)

будет эквивалентен

EXISTS (SELECT sname FROM Salespeople)

который был показан выше.



FETCH (ВЫБОРКА/ИЗВЛЕЧЕНИЕ)


Синтаксис

EXEC SQL FETCH <cursorname>

INTO <host-varlable llst><SQL term>

FETCH принимает вывод из текущей строки запроса <query>, вставляет её в список главных переменных <host-variable list>, и перемещает курсор на следующую строку. Список <host-variable list> может включать переменную indicator в качестве целевой переменной (См. Главу 25).



ФОРТРАН


NVL(<column>,<value>) NVL (NULL-значение) будет менять на <value> каждое NULL значение, найденное в столбце <column>. Если полученное значение <column> не = NULL, NVL ничего не делает.
SQL ТИПЭКВИВАЛЕНТ ФОРТРАНА
CHARCHAR
INTEGERINTEGER

REALREALDOUBLE PRECISIONDOUBLE PRECISION

ФУНКЦИИ


Для SQL в стандарте ANSI вы можете применять агрегатные функции для столбцов или использовать их значения в скалярных выражениях, таких, например, как comm * 100. Имеется много других полезных функций, которые вы, вероятно, встречали на практике.

Имеется список некоторых общих функций SQL, отличающихся от стандартных агрегатов. Они могут использоваться в предложениях SELECT-запросов точно так же, как агрегатные функции, но эти функции выполняются для одиночных значений, а не для групповых. В следующем списке они классифицированы согласно типам данных, с которыми они работают. Если нет примечаний, то переменные в этом списке стандартизированы для любого выражения значений соответствующего типа, которые могут быть использованы в предложении SELECT.



ФУНКЦИИ ДАТЫ И ВРЕМЕНИ


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

ФУНКЦИЯЗНАЧЕНИЕ

ФУНКЦИОНАЛЬНЫЕ ЭЛЕМЕНТЫ


Следующая таблица показывает функциональные элементы команд SQL и их определения:

ЭЛЕМЕНТ ОПРЕДЕЛЕНИЕ

<query> Предложение SELECT

<subquery> Заключённое в круглые скобки предложение SELECT внутри другого условия, которое фактически оценивается отдельно для каждой строки-кандидата другого предложения.

<value expression> <primary> | <primary> <operator> <primary> | <primary> <operator> <value expression>

<operator> любое из следующих: + - / *

<primary> <column name> | <literal> | <aggregate function> | <built-in constant> | <nonstandard function>

<literal> <string> | <mathematical expressio>

ЭЛЕМЕНТ ОПРЕДЕЛЕНИЕ

<built-in constant> USER | <implementation-defined constant>

<table name> <identifier>

<column spec> [<table name> | <alias>.]<column name>

<grouping column> <column spec> | <integer>

<ordering column> <column spec> | <integer>

<colconstraint> NOT NULL | UNIQUE | CHECK (<predicate>) | PRIMARY KEY | REFERENCES <table name>[(<column name>)]

<tabconstraint> UNIQUE (<column list>) | CHECK (<predicate>) | PRIMARY KEY (<column list>) | FOREIGN KEY (<column list>) | REFERENCES <table name>[(<column list>)]

<defvalue> ЗНАЧЕНИЕ ПО УМОЛЧАНИЮ = <value expression>

<data type> Допустимый тип данных (См. в Приложении B

описание типов, обеспечиваемых ANSI, или в Приложении C - другие общие типы.)

<size> Значение зависит от <data type>(См. Приложение B.)

<cursor name> <identifier>

<index name> <identifier>

<synonym> <identifier>(*нестандартный*)

<owner> <Authorization ID>

<column list> <column spec> .,..

<value list> <value expression> .,..

<table reference> { <table name> [<alias>] } .,..



ГДЕ ПРИМЕНЯЮТСЯ ЗАПРОСЫ?


Запросы обычно рассматриваются как часть языка DML. Однако, так как запрос не меняет информацию в таблицах, а просто показывает её пользователю, мы будем рассматривать запросы как самостоятельную категорию среди команд DML, которые производят действия, а не просто показывают содержание базы данных (БД).

Любой запрос SQL имеет в своём составе одну команду. Структура этой команды обманчиво проста, потому что вы можете расширять её так, чтобы выполнить сложные оценки и обработку данных. Эта команда называется SELECT (ВЫБРАТЬ).



SQL. ОБЗОР.


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

Здесь дан лишь краткий обзор; многие подробности даны, чтобы впоследствии обращаться к ним по мере овладения языком. Мы поместили всё это в начало книги, чтобы ориентировать вас на мир SQL без упрощенного подхода к его проблемам и, в тоже время, дать вам повторяющиеся в дальнейшем места для ссылки на них, когда у вас появятся вопросы. Этот материал может стать более понятным, когда мы перейдём к описанию конкретных команд SQL в Главе 3.



ИСПОЛЬЗОВАНИЕ SQL ДЛЯ ИЗВЛЕЧЕНИЯ ИНФОРМАЦИИ ИЗ ТАБЛИЦ


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



вы узнали, что предикаты


В Главе 3 вы узнали, что предикаты могут оценивать равенство в операции как true/верное или false/неверное. Они могут также оценивать другие виды связей, помимо равенств.
Эта глава будет исследовать другие реляционные операции, используемые в SQL. Вы также узнаете, как использовать булевы операции, чтобы изменять и объединять значения предиката. С помощью булевых операций (или, проще говоря, логических операций) одиночный предикат может содержать любое число условий. Это позволяет создавать очень сложные предикаты. Использование круглых скобок в структуре этих сложных предикатов будет также разъясняться.

ИСПОЛЬЗОВАНИЕ СПЕЦИАЛЬНЫХ ОПЕРАТОРОВ В УСЛОВИЯХ


В дополнение к реляционным и булевым операциям, обсуждённым в Главе 4, SQL использует специальные операторы: IN, BETWEEN, LIKE и IS NULL.

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

Вы также узнаете о вариантах использования оператора, NOT применяющегося с этими операторами.



ОБОБЩЕНИЕ ДАННЫХ С ПОМОЩЬЮ АГРЕГАТНЫХ ФУНКЦИЙ


В этой главе вы перейдёте о простого использования запросов к извлечению значений из базы данных (БД) и определите, как можно использовать эти значения, чтобы получить из них информацию. Это делается с помощью агрегатных (обобщающих) функций, которые берут группы значений из поля и сводят их до одиночного значения.

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

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



ФОРМИРОВАНИЕ ВЫВОДА ЗАПРОСОВ


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



ЗАПРАШИВАНИЕ НЕСКОЛЬКИХ ТАБЛИЦ ТАК ЖЕ, КАК ОДНОЙ


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



ОБЪЕДИНЕНИЕ ТАБЛИЦЫ С СОБОЙ


В Главе 8 мы рассмотрели, как объединить две или более таблиц. Интересно, что та же самая методика может использоваться для объединения двух копий одной таблицы. В этой главе мы будем исследовать этот процесс. Как вы увидите, объединение таблицы с самой собой - далеко не простая вещь и может быть очень полезна для определения некоторых видов связей между данными в конкретной таблице.



ВСТАВКА ОДНОГО ЗАПРОСА ВНУТРЬ ДРУГОГО


В конце Главы 9 мы говорили, что запросы могут управлять другими запросами. В этой главе вы узнаете, как это делается (большей частью) путём помещения запроса внутрь предиката другого запроса и использования вывода внутреннего запроса в верном или неверном условии предиката.

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

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



СООТНЕСЁННЫЕ ПОДЗАПРОСЫ


В этой главе мы рассмотрим тип подзапроса, о котором мы не говорили в Главе 10, - соотнесённый подзапрос. Вы узнаете, как использовать соотнесённые подзапросы в предложениях WHERE и HAVING. Сходства и различия между соотнесёнными подзапросами и объединениями будут обсуждаться далее, и вы сможете расширить ваше знание о псевдонимах и префиксах имени таблицы - когда они необходимы и как их использовать.



Использование оператора EXISTS


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

Оператор EXISTS используется, чтобы указать предикату, производить ли подзапросу вывод или нет. В этой главе вы узнаете, как использовать этот оператор со стандартными и (обычно) соотнесёнными подзапросами. Мы будем также обсуждать специальные вопросы, которые перейдут в игру, когда вы будете использовать этот оператор как относительный агрегат, как пустой указатель NULL и как булев оператор. Кроме того, вы сможете повысить ваш профессиональный уровень относительно подзапросов, исследуя их в более сложных прикладных программах, чем те, которые мы видели до сих пор.









DAY()
Извлекает день месяца из даты. Подобные же функции существуют для MONTH (МЕСЯЦ), YEAR (ГОД), HOUR (ЧАС), SECOND (СЕКУНДА) и так далее.
WEEKDAY()Извлекает день недели из даты.