Представление VIEW_TABLE_USAGE
Это представление идентифицирует таблицы, от которых зависят представляемые таблицы, определенные в данном каталоге и принадлежащие данному пользователю. Определение представления:
CREATE VIEW VIEW_TABLE_USAGE AS SELECT VIEW_CATALOG, VIEW_SCHEMA, VIEW_NAME, TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME FROM DEFINITION_SCHEMA.VIEW_TABLE_USAGE JOIN DEFINITION_SCHEMA.SCHEMATA S ON ((TABLE_CATALOG, TABLE_SCHEMA) = (S.CATALOG_NAME, S.SCHEMA_NAME)) WHERE SCHEMA_OWNER = CURRENT_USER AND VIEW_CATALOG = (SELECT CATALOG_NAME FROM INFORMATION_SCHEMA_CATALOG_NAME)
Представление VIEWS
Представление идентифицирует представляемые таблицы, определенные в данном каталоге и доступные данному пользователю. Определение представления:
CREATE VIEW VIEWS AS SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, CASE WHEN (TABLE_CATALOG, TABLE_SCHEMA, CURRENT_USER) IN (SELECT CATALOG_NAME, SCHEMA_NAME, SCHEMA_OWNER FROM DEFINITION_SCHEMA.SCHEMATA) THEN VIEW_DEFINITION ELSE NULL END AS VIEW_DEFINITION, CHECK_OPTION, IS_UPDATABLE FROM DEFINITION_SCHEMA.VIEWS WHERE (TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME) IN (SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME FROM TABLES) AND TABLE_CATALOG = (SELECT CATALOG_NAMEFROM INFORMATION_SCHEMA_CATALOG_NAME)
Практические занятия курса "Введение в стандарты языка баз данных SQL"
На практических занятиях слушатели освоят основные приемы использования стандартного языка SQL в интерактивном режиме. Мы сознательно ограничиваемся этим режимом по следующим соображениям. Во-первых, цель этого курса состоит не в том, чтобы научить разрабатывать информационные приложения, а в том, чтобы показать возможности языка SQL. В этом смысле более важно понять принципы взаимодействия с базами данных. Используя интерактивный режим, такого понимания можно добиться существенно быстрее. Во-вторых, использование интерактивного режима, в частности, демонстрирует один из примеров приложения, которое само разработано на основе динамического SQL. Тем самым, слушатели могут на практике убедиться в том, что язык SQL дает возможность создавать разнообразные приложения, ориентированные на непосредственное общение с пользователем.
В качестве основного инструмента практических занятий будет использоваться MicrosoftSQLServer 6.5. Этот выбор не связан с тем, что данный сервер обладает какими-либо исключительными характеристиками. На самом деле, для наших целей подошла бы любая реляционная СУБД, в достаточной степени поддерживающая стандарт SQL. В частности, можно было бы использовать свободно распространяемую СУБД PostgreSQL или созданный в России сервер GSQL. Но MSSQLServer является исключительно популярным продуктом и работает на распространенных платформах серии Windows. Сервер входит в шестерку наиболее известных и мощных продуктов управления базами данных (остальные пять СУБД включают Informix, Oracle, Sybase, CA-OpenIngres и DB2 компании IBM). Не факт, что MSSQLServer идеально подходит в качестве основы корпоративных информационных приложений, но его возможностей вполне достаточно для демонстрации возможностей стандарта SQL.
Как и все другие производители реляционных СУБД, компания Microsoft внесла ряд расширений в свой вариант SQL. Тем не менее, продукт соответствует стандарту SQL/89 и вводному уровню SQL/92. Естественно, на занятиях мы будем пользоваться только стандартным подмножеством языка.
На практике будет использоваться стандартная демонстрационная база данных pubs, поставляемая вместе с SQL-сервером. В этой базе данных имеются некоторые объекты, выходящие за рамки стандарта SQL. Эти объекты использоваться не будут. Каждый из слушателей получит привилегии доступа по чтению ко всем таблицам, существующим в pubs, и, кроме того, привилегию для создания собственной таблицы. Тем самым, все слушатели будут работать с общей базой данных в режиме мультидоступа.
Привилегии
Поскольку все слушатели работают под одним идентификатором, реально проверить возможности передачи привилегий мы не сможем. Тем не менее, каждый пользователь должен передать право на чтение всех столбцов созданной им таблицы пользователю с идентификатором public.
Привилегия авторизует данную категорию действий по отношению к указанным базовой таблице, представлению, столбцу, домену и т.д. на основе специфицированного идентификатора авторизации. Отображение идентификаторов авторизации на пользователей операционной системы является зависимым от реализации. Могут быть специфицированы следующие действия:
INSERT INSERT (<columnnamelist>) UPDATE UPDATE (<columnnamelist>) DELETE SELECT REFERENCES REFERENCES (<columnnamelist>) USAGE
Идентификатор авторизации определяется для каждого определения схемы и модуля, а также для каждой SQL-сессии. Схема, которая связана с данным идентификатором привилегий может содержать дескрипторы привилегий, описывающие привилегии, которые переданы другим идентификаторам авторизации (получателям привилегий). Переданные привилегии применяются к объектам, определенным в текущей схеме. Раздел WITHGRANTOPTION оператора GRANT указывает, что получатель привилегии может передать ее дальше.
Текущий идентификатор авторизации определяет привилегии для выполнения каждого оператора SQL. При прямом использовании SQL идентификатор авторизации SQL-сессии всегда является текущим идентификатором авторизации.
Описатель привилегии с действием INSERT, UPDATE, DELETE, SELECT и REFERENCES называется описателем привилегий уровня таблицы и идентифицирует существование привилегии к таблице, идентифицируемой описателем привилегии.
Описатель привилегии с действием SELECT (<columnnamelist>), INSERT (<columnnamelist>), UPDATE (<columnnamelist>), и REFERENCES (<columnnamelist>) называется описателем привилегии уровня столбца и идентифицирует существование привилегии к столбцу таблицы, идентифицируемой описателем привилегии.
Прямой вызов операторов SQL
Как мы уже упоминали, в стандарте SQL/92 специфицирован набор операторов, которые могут вызываться напрямую не будучи встроены в модуль или программу на языке программирования. Обычно прямой вызов производится с помощью некоторой утилиты СУБД, обеспечивающей возможности интерактивного ввода и редактирования SQL-операторов и отображение результатов на экран терминала. Наиболее естественным способом написания такой утилиты является использование динамического SQL.
Набор прямо вызываемых операторов определяется следующими синтаксическими правилами:
<direct SQL statement> ::= <directly executable statement> <semicolon> <directly executable statement> ::= <direct SQL data statement> | <SQL schema statement> | <SQL transaction statement> | <SQL connection statement> | <SQL session statement> | <direct implementation-defined statement> <direct SQL data statement> ::= <delete statement: searched> | <direct select statement: multiple rows> | <insert statement> | <update statement: searched> | <temporary table declaration> <direct implementation-defined statement> ::= См. пояснения ниже
Пояснения:
Прямые операторы манипулирования данными (directSQLdatastatement) не должны содержать спецификацию параметров, спецификацию динамических параметров и спецификацию переменных. Спецификация значения, представляющего неопределенное значение, определяется в реализации. Синтаксические правила для прямых операторов, определяемых в реализации, (directimplementation-definedstatement) определяются в реализации. Инициирующими транзакцию являются следующие прямые операторы SQL:
(a) операторы, являющиеся инициирующими транзакцию операторами, которые могут входить в SQL-процедуру;
(b) прямой оператор выборки, возвращающий несколько строк (directselectstatement: multiplerows);
(c) инициирующий транзакцию прямой оператор, определяемый в реализации.
После последнего вызова оператора SQLSQL-агентом в SQL-сессии происходит следующее:
(a) выполняется оператор ROLLBACK или оператор COMMIT; если возникает невосстанавливаемая ошибка или если прямой вызов SQL завершается непредусмотренным образом (это определяется в реализации), или если не удовлетворяется некоторое ограничение, то выполняется оператор ROLLBACK; в противном случае выбор между выполнением операторов ROLLBACK и COMMIT определяется в реализации;
(b) пусть D - имя дескриптора в некоторой области дескрипторов, который выделен в пределах текущей сессии; тогда выполняется следующий оператор: DEALLOCATEDESCRIPTORD;
(c) все SQL-сессии, связанные с данным SQL-агентом, завершаются.
Пусть S обозначает прямой оператор SQL. Текущим идентификатором авторизации для выполнения S является идентификатор авторизации SQL-сессии. При вызове SSQL-агентом происходит следующее:
(a) если S - это оператор подключения, то
(i) очищается область диагностики;
(ii) S выполняется;
(iii) если оператор S успешно инициировал или возобновил SQL-сессию, то последующие вызовы операторов прямого SQL данным SQL-агентом связываются с этой сессией, пока SQL-агент не завершит ее или не сделает потенциальной;
(b) в противном случае:
(i) если для SQL-агента не существует текущая SQL-сессия, то:
(*) если SQL-агент не выполнял оператора подключения и с ним не связана SQL-сессия по умолчанию, то выполняется следующий оператор подключения: CONNECTTODEFAULT;
(**) если SQL-агент не выполнял оператора подключения и с ним связана SQL-сессия по умолчанию, то выполняется следующий оператор установки подключения: SETCONNECTIONDEFAULT;
(***) в противном случае возникает исключительное условие;
(ii) если для данного SQL-агента существует активная транзакция, то S связывается с этой транзакцией SQL-transaction; если S - прямой оператор SQL, определяемый в реализации, то в реализации же определяется, может ли S ассоциироваться с текущей транзакцией, если не может, то возбуждается исключительное условие;
(iii) если для данного SQL-агента не существует активной транзакции, то
(*) если S является инициирующим транзакцию оператором, то инициируется SQL-транзакция;
(**) если S является прямым оператором, определяемым в реализации, то в реализации же определяется, инициирует ли S транзакцию; если инициирует, то инициируется SQL-транзакция.
(***) если оператор S инициировал транзакцию, то пусть T обозначает эту транзакцию; тогда:
(****) T ассоциируется с данным вызовом и со всеми последующими вызовами прямых операторов SQL и процедур, производимых данным SQL-агентом, до тех пор, пока этот агент не завершит T;
(*****) если после завершения последней транзакции в данной SQL-сессии был выполнен оператор установки параметров транзакции, то режим доступа, режим проверки ограничений и уровень изоляции T устанавливаются в соответствии с заданными параметрами;
(******) в противном случае для T устанавливается режим доступа "чтение-запись", режим проверки ограничений "немедленный" и уровень изоляции;
(*******) T ассоциируется с текущей SQL-сессией;
(iv) область диагностики очищается;
(v) S выполняется.
Если в одной транзакции происходит вызов прямого оператора манипулирования данными и оператора манипулирования схемой и это не допускается реализацией, возбуждается исключительное условие. Если выполнение S завершилось успешно, то вырабатывается условие завершения "успешное выполнение", либо "предупреждение", либо "нет данных". Если выполнение S завершилось неуспешно, то все изменения, произведенные S над данными или над схемой, ликвидируются, и возбуждается исключительное условие. Диагностическая информация по поводу выполнения S помещается в область диагностики; способ доступа к диагностической информации определяется в реализации, но в любом случае содержимое области диагностики не меняется.
Как видно из синтаксических правил, определяющих набор прямых операторов SQL, в состав этого набора входит специальный оператор выборки, не употребляемый в других контекстах и потому не рассмотренный нами ранее. Синтаксис этого оператора следующий:
<direct select statement: multiple rows> ::= <query expression> [ <order by clause> ]
Пояснения:
Как видно, синтаксис этого оператора очень напоминает синтаксис спецификации курсора: отсутствует только раздел изменяемости (updatabilityclause). Однако, поскольку это прямой оператор, то в его выражении запроса и разделе сортировки не должны содержаться спецификации значений, отличные от литералов, CURRENT_USER, SESSION_USER и SYSTEM_USER. Пусть Q обозначает результат вычисления выражения запроса. Если Q пусто, то вырабатывается условие завершения оператора "нет данных". Если оператор не содержит раздела сортировки, то порядок строк в Q зависит от реализации; иначе порядок строк устанавливается в соответствии с параметрами раздела сортировки. Если Q непусто, то возвращается оператором, причем используемый способ возврата определяется в реализации.
Проверочное ограничение
Проверочное ограничение специфицирует условие, которому должна удовлетворять в отдельности каждая строка таблицы T. Это условие не должно содержать подзапросов, спецификаций агрегатных функций, а также ссылок на внешние переменные или параметров. В него могут входить только имена столбцов данной таблицы и литеральные константы.
Таблица удовлетворяет проверочному ограничению целостности в том и только в том случае, когда вычисление условия для каждой строки таблицы дает true.
Замечание: В некоторых реализациях допускаются расширенные механизмы ограничений по ссылкам и проверочных ограничений. Следует быть внимательным, если не желать выходить за пределы возможностей стандарта.
Раздел FROM
Раздел FROM имеет следующий синтаксис:
<from clause> ::= FROM <table reference> ({,<table reference>}...] <table reference> ::= <table name> [<correlation name>]
Результатом выполнения раздела FROM является расширенное декартово произведение таблиц, заданных списком таблиц раздела FROM. Расширенное декартово произведение (расширенное, потому что в качестве операндов и результата допускаются мультимножества) в стандарте определяется следующим образом:
"Расширенное произведение R есть мультимножество всех строк r таких, что r является конкатенацией строк из всех идентифицированных таблиц в том порядке, в котором они идентифицированы. Мощность R есть произведение мощностей идентифицированных таблиц. Порядковый номер столбца в R есть n+s, где n - порядковый номер порождающего столбца в именованной таблице T, а s - сумма степеней всех таблиц, идентифицированных до T в разделе FROM".
Как видно из синтаксиса, рядом с именем таблицы можно указывать еще одно имя "correlationname". Фактически, это некоторый синоним имени таблицы, который можно использовать в других разделах табличного выражения для ссылки на строки именно этого вхождения таблицы.
Если табличное выражение содержит только раздел FROM (это единственный обязательный раздел табличного выражения), то результат табличного выражения совпадает с результатом раздела FROM.
Формально синтаксис остался таким же, как и в SQL/89:
<from clause> ::= FROM <table reference> [ { <comma> <table reference> }... ]
Но вспомним, что такое ссылка на таблицу в SQL/92 (см. выше). Реально можно весь запрос сосредоточить в разделе FROM.
Раздел GROUPBY
Если в табличном выражении присутствует раздел GROUPBY, то следующим выполняется он. Синтаксис раздела GROUPBY следующий:
<group by clause> ::= GROUP BY <column specification> [{,<column specification>}...]
Если обозначить через R таблицу, являющуюся результатом предыдущего раздела (FROM или WHERE), то результатом раздела GROUPBY является разбиение R на множество групп строк, состоящего из минимального числа групп таких, что для каждого столбца из списка столбцов раздела GROUPBY во всех строках каждой группы, включающей более одной строки, значения этого столбца равны. Для обозначения результата раздела GROUPBY в стандарте используется термин "сгруппированная таблица".
Раздел HAVING
Наконец, последним при вычислении табличного выражения используется раздел HAVING (если он присутствует). Синтаксис этого раздела следующий:
<having clause> ::= HAVING <search condition>
Раздел HAVING может осмысленно появиться в табличном выражении только в том случае, когда в нем присутствует раздел GROUPBY. Условие поиска этого раздела задает условие на группу строк сгруппированной таблицы. Формально раздел HAVING может присутствовать и в табличном выражении, не содержащем GROUPBY. В этом случае полагается, что результат вычисления предыдущих разделов представляет собой сгруппированную таблицу, состоящую из одной группы без выделенных столбцов группирования.
Условие поиска раздела HAVING строится по тем же синтаксическим правилам, что и условие поиска раздела WHERE, и может включать те же самые предикаты. Однако имеются специальные синтаксические ограничения по части использования в условии поиска спецификаций столбцов таблиц из раздела FROM данного табличного выражения. Эти ограничения следуют из того, что условие поиска раздела HAVING задает условие на целую группу, а не на индивидуальные строки.
Поэтому в арифметических выражениях предикатов, входящих в условие выборки раздела HAVING, прямо можно использовать только спецификации столбцов, указанных в качестве столбцов группирования в разделе GROUPBY. Остальные столбцы можно специфицировать только внутри спецификаций агрегатных функций COUNT, SUM, AVG, MIN и MAX, вычисляющих в данном случае некоторое агрегатное значение для всей группы строк. Аналогично обстоит дело с подзапросами, входящими в предикаты условия выборки раздела HAVING: если в подзапросе используется характеристика текущей группы, то она может задаваться только путем ссылки на столбцы группирования.
Результатом выполнения раздела HAVING является сгруппированная таблица, содержащая только те группы строк, для которых результат вычисления условия поиска есть true. В частности, если раздел HAVING присутствует в табличном выражении, не содержащем GRОUPBY, то результатом его выполнения будет либо пустая таблица, либо результат выполнения предыдущих разделов табличного выражения, рассматриваемый как одна группа без столбцов группирования.
Раздел ORDERBY
Наконец, раздел ORDERBY позволяет установить желаемый порядок просмотра результата выражения запросов. Синтаксис ORDERBY следующий:
<order by clause> ::= ORDER BY <sort specification> [{,<sort specification>}...] <sort specification> ::= {<unsigned integer> <column specification>} [ASC DESC]
Как видно из этих синтаксических правил, фактически задается список столбцов результата выражения запросов, и для каждого столбца указывается порядок просмотра строк результата в зависимости от значений этого столбца (ASC - по возрастанию, этот режим используется по умолчанию, DESC - по убыванию). Столбцы можно задавать их именами в том и только в том случае, когда (1) выражение запросов не содержит операций UNION или UNIONALL и (2) в списке выборки спецификации запроса этому столбцу соответствует арифметическое выражение, состоящее только из имени столбца. Во всех остальных случаях в разделе ORDERBY должен указываться порядковый номер столбца в таблице-результате выражения запросов.
Раздел WHERE
Если в табличном выражении присутствует раздел WHERE, то следующим вычисляется он. Синтаксис раздела WHERE следующий:
<where clause> ::= WHERE <search condition> <search condition> ::= <boolean term> <search condition> OR <boolean term> <Boolean term> ::= <boolean factor> <boolean term> AND <boolean factor> <boolean factor> ::= [NOT] <boolean primary> <boolean primary> ::= <predicate> (<search condition>)
Вычисление раздела WHERE производится по следующим правилам: Пусть R - результат вычисления раздела FROM. Тогда условие поиска применяется ко всем строкам R, и результатом раздела WHERE является таблица, состоящая из тех строк R, для которого результатом вычисления условия поиска является true. Если условие выборки включает подзапросы, то каждый подзапрос вычисляется для каждого кортежа таблицы R (в стандарте используется термин "effectively" в том смысле, что результат должен быть таким, как если бы каждый подзапрос действительно вычислялся заново для каждого кортежа R). Заметим, что поскольку SQL/89 допускает наличие в базе данных неопределенных значений, то вычисление условия поиска производится не в булевой, а в трехзначной логике со значениями true, false и unknown (неизвестно). Для любого предиката известно, в каких ситуациях он может порождать значение unknown. Булевские операции AND, OR и NOT работают в трехзначной логике следующим образом:
trueANDunknown = unknown unknownANDtrue = unknown unknownANDunknown = unknown trueORunknown = true unknownORtrue = true unknownORunknown = unknown NOTunknown = unknown
Среди предикатов условия поиска в соответствии с SQL/89 могут находиться следующие предикаты: предикат сравнения, предикат between, предикат in, предикат like, предикат null, предикат с квантором и предикат exists. Сразу заметим, что во всех реализациях SQL на эффективность выполнения запроса существенно влияет наличие в условии поиска простых предикатов сравнения (предикатов, задающих сравнение столбца таблицы с константой). Наличие таких предикатов позволяет СУБД использовать индексы при выполнении запроса, т.е. избегать полного просмотра таблицы. Хотя в принципе язык SQL позволяет пользователям не заботиться о конкретном наборе предикатов в условии выборки (лишь бы они были синтаксически и семантически правильны), при реальном использовании SQL-ориентированных СУБД такие технические детали стоит иметь в виду.
Снова синтаксис формально не изменился:
<where clause> ::= WHERE <search condition>
Но существенно расширен набор допустимых предикатов (см. следующий раздел).
Разделы GROUPBY и HAVING остались такими же, как в SQL/89, если не считать расширения набора предикатов, которые можно использовать в условии HAVING.
Минимальный осмысленный контекст использования табличных выражений составляет спецификация запроса - один из основных строительных блоков для построения выражения запросов. Синтаксис спецификации запросов следующий:
<query specification> ::= SELECT [ <set quantifier> ] <select list> <table expression> <select list> ::= <asterisk> |<select sublist> [ { <comma> <select sublist> }... ] <select sublist> ::= <derived column> |<qualifier> <period> <asterisk> <derived column> ::= <value expression> [ <as clause> ] <as clause> ::= [ AS ] <column name>
Опять же на вид это очень похоже на соответствующую конструкцию SQL/89, но нужно иметь в виду, что, во-первых, в основе спецификации запроса SQL/92 лежит существенно расширенная конструкция табличного выражения, а во-вторых, в спецификации присутствует необязательный раздел AS, позволяющий присвоить имена таблице, которая генерируется при выполнении запроса. Эта возможность кажется на первый взгляд мелочью, но именно она позволяет использовать порождаемые таблицы в разделе FROM и отказаться от использования номеров столбцов порождаемой таблицы в разделе ORDERBY выражения запросов (см. ниже).
Результаты запросов
Агрегатные функции можно разумно использовать в спецификации курсора, операторе выборки и подзапросе после ключевого слова SELECT (будем называть в этом подразделе все такие конструкции списком выборки, не забывая о том, что в случае подзапроса этот список состоит только из одного элемента), и в условии выборки раздела HAVING. Стандарт допускает более экзотические использования агрегатных функций в подзапросах (агрегатная функция на группе кортежей внешнего запроса), но на практике они встречаются очень редко.
Рассмотрим различные случаи применения агрегатных функций в списке выборки в зависимости от вида табличного выражения.
Если результат табличного выражения R не является сгруппированной таблицей, то появление хотя бы одной агрегатной функции от множества строк R в списке выборки приводит к тому, что R неявно рассматривается как сгруппированная таблица, состоящая из одной (или нуля) групп с отсутствующими столбцами группирования. Поэтому в этом случае в списке выборки не допускается прямое использование спецификаций столбцов R: все они должны находиться внутри спецификаций агрегатных функций. Результатом запроса является таблица, состоящая не более чем из одной строки, полученной путем применения агрегатных функций к R.
Аналогично обстоит дело в том случае, когда R представляет собой сгруппированную таблицу, но табличное выражение не содержит раздела GROUPBY (и, следовательно, содержит раздел HAVING). Если в случае предыдущего абзаца имелись два варианта формирования списка выборки: только с прямым указанием столбцов R или только с указанием их внутри спецификаций агрегатных функций, то в данном случае возможен только второй вариант. Результат табличного выражения явно объявлен сгруппированной таблицей, состоящей из одной группы, и результат запроса можно формировать только путем применения агрегатных функций к этой группе строк. Опять результатом запроса является таблица, состоящая не более чем из одной строки, полученной путем применения агрегатных функций к R.
Наконец, рассмотрим случай, когда R представляет собой "настоящую" сгруппированную таблицу, т.е. табличное выражение содержит раздел GROUPBY и, следовательно, определен по крайней мере один столбец группирования. В этом случае правила формирования списка выборки полностью соответствуют правилам формирования условия выборки раздела HAVING: допускается прямое использование спецификации столбцов группирования, а спецификации остальных столбцов R могут появляться только внутри спецификаций агрегатных функций. Результатом запроса является таблица, число строк в которой равно числу групп в R, и каждая строка формируется на основе значений столбцов группирования и агрегатных функций для данной группы.
Семантика агрегатных функций
Агрегатные функции предназначены для того, чтобы вычислять некоторое значение для заданного множества строк. Таким множеством строк может быть группа строк, если агрегатная функция применяется к сгруппированной таблице, или вся таблица. Для всех агрегатных функций, кроме COUNT(*), фактический (т.е. требуемый семантикой) порядок вычислений следующий: на основании параметров агрегатной функции из заданного множества строк производится список значений. Затем по этому списку значений производится вычисление функции. Если список оказался пустым, то значение функции COUNT для него есть 0, а значение всех остальных функций - null.
Пусть T обозначает тип значений из этого списка. Тогда результат вычисления функции COUNT - точное число с масштабом и точностью, определяемыми в реализации. Тип результата значений функций MAX и MIN совпадает с T. При вычислении функций SUM и AVG тип T не должен быть типом символьных строк, а тип результата функции - это тип точных чисел с определяемыми в реализации масштабом и точностью, если T - тип точных чисел, и тип приблизительных чисел с определяемой в реализации точностью, если T - тип приблизительных чисел.
Вычисление функции COUNT(*) производится путем подсчета числа строк в заданном множестве. Все строки считаются различными, даже если они состоят из одного столбца со значением null во всех строках.
Если агрегатная функция специфицирована с ключевым словом DISTINCT, то список значений строится из значений указанного столбца. (Подчеркнем, что в этом случае не допускается вычисление арифметических выражений!) Далее из этого списка удаляются неопределенные значения, и в нем устраняются значения-дубликаты. Затем вычисляется указанная функция.
Если агрегатная функция специфицирована без ключевого слова DISTINCT (или с ключевым словом ALL), то список значений формируется из значений арифметического выражения, вычисляемого для каждой строки заданного множества. Далее из списка удаляются неопределенные значения, и производится вычисление агрегатной функции. Обратите внимание, что в этом случае не допускается применение функции COUNT!
Замечание: оба ограничения, указанные в двух предыдущих абзацах, являются более техническими, чем принципиальными, и могут отсутствовать в конкретных реализациях. Тем не менее, это ограничения стандарта SQL/89, и их нужно придерживаться при мобильном программировании.
Символьные строки
Тип данных символьных строк может содержать строки постоянной (CHARACTER) или переменной (CHARACTERVARYING) длины. Для конкретного типа CHARACTER указывается длина строк этого типа; в случае CHARACTERVARYING - максимальная длина.
Определен ряд операций, которые можно выполнять над символьными строками. Перечислим некоторые из них.
К операторам, операнды которых являются символьными строками и которые возвращают символьные строки, относятся следующие:
Оператор конкатенации (обозначается в виде ) возвращает символьную строку, произведенную путем соединения строк-операндов в том порядке как они заданы. Функция выделения подстроки (SUBSTRING) принимает три параметра - строку, номер начальной позиции и длину и возвращает строку, выделенную из строки-параметра в соответствии со значениями двух последних параметров. Функция UPPER возвращает строку, в которой все малые буквы строки-параметра заменяются на прописные. Функция LOWER, наоборот, заменяет в заданной строке все прописные буквы на малые. Выражение длины возвращает длину заданной символьной строки в символах, октетах или битах (в зависимости от вида вычисляющей функции) виде целого числа. Выражение позиции определяет первую позицию в строке S, с которой в нее входит заданная строка S1 (если не входит, то возвращается нуль).
Заметим, что мы опускаем в этом курсе громоздкий и редко самостоятельно применяемый механизм, позволяющий работать с символьными строками в национальной кодировке. Обычно такую настройку производят поставщики СУБД.
Скалярные выражения
Скалярное выражение - это выражение, вырабатывающее результат некоторого типа, специфицированного в стандарте. Скалярные выражения являются основой языка SQL/92, поскольку, хотя это реляционный язык, все условия, элементы списков выборки и т.д. базируются именно на скалярных выражениях. Заметим, что в SQL/89 не требовалось вводить такое отдельное понятие, поскольку единственным допустимым скалярным выражением было арифметическое (т.е. вырабатывающее число). В связи с расширением ассортимента типов и операций над их значениями, в SQL/92 появилось три разных вида скалярных выражения - численные, над строками и над временем и датами (и интервалами). Мы не будем слишком глубоко вникать в тонкости, но тем не менее, приведем некоторые базовые спецификации и пояснения.
Прежде, чем перейти к конкретным видам скалярных выражений, рассмотрим некоторые более общие языковые конструкции, на которых эти выражения базируются. (Мы опускаем обсуждение типов данных, считая, что материала, приведенного в предыдущем разделе, достаточно для понимания.)
Спецификация значения и спецификация цели
Эти конструкции служат для спецификации значений, не выбираемых из таблиц базы данных, а заданных пользователями. Общий синтаксис выглядит следующим образом:
<value specification> ::= <literal> |<general value specification> <unsigned value specification> ::= <unsigned literal> |<general value specification> <general value specification> ::= <parameter specification> |<dynamic parameter specification> |<variable specification> |USER |CURRENT_USER |SESSION_USER |SYSTEM_USER VALUE <simple value specification> ::= <parameter name> |<embedded variable name |<literal> <target specification> ::= <parameter specification> |<variable specification> <simple target specification> ::= <parameter name> <embedded variable name> <parameter specification> ::= & lt;parameter name> [ <indicator parameter> ] <indicator parameter> ::= [ INDICATOR ] <parameter name> <dynamic parameter specification> ::= <question mark> <variable specification> ::= <embedded variable name> [ <indicator variable> ] <indicator variable> ::= [ INDICATOR ] <embedded variable name>
Пояснения: Спецификация параметра идентифицирует параметр или параметр и индикаторный параметр в модуле (вернее, в процедуре модуля). Спецификация динамического параметра идентифицирует параметр динамически подготовленного оператора. Спецификация переменной идентифицирует переменную включающего языка или такую переменную и индикаторную переменную. Спецификация цели определяет параметр или переменную, которым может быть присвоено значение. Отрицательное значение индикаторных параметра или переменной в спецификации параметра или переменной соответственно означает, что параметр или переменная содержат неопределенное значение. Значение CURRENT_USER есть значение текущего идентификатора авторизации; SESSION_USER - значение идентификатора авторизации SQL-сессии; SYSTEM_USER - определяемая в реализации строка, представляющая пользователя операционной системы, который выполнил оператор SQL, в результате которого было вычислено значение SYSTEM_USER.
Спецификация явного преобразования типа или домена
В SQL/89 существуют только неявные преобразования типов (например, FLOAT к DOUBLE). Конечно, это не всегда удобно, недостаточно гибко и иногда чревато ошибками. В SQL/92 существует специальная конструкция CAST, с помощью которой можно явно преобразовывать типы в пределах допускаемых преобразований. Синтаксис конструкции следующий:
<cast specification> ::= CAST <left paren> <cast operand> AS <cast target> <right paren> <cast operand> ::= <value expression> |NULL <cast target> ::= <domain name> |<data type>
Пояснения. Примем следующие обозначения типов данных:
EN | - ExactNumeric; |
AN | - ApproximateNumeric; |
C | - Character (Fixed- orVariable-length); |
FC | - Fixed-lengthCharacter; |
VC | - Variable-lengthCharacter; |
B | - BitString (Fixed- orVariable-length); |
FB | - Fixed-lengthBitString; |
VB | - Variable-lengthBitString; |
D | - Date; |
T | - Time; |
TS | - Timestamp; |
YM | - Year-MonthInterval; |
DT | - Day-TimeInterval. |
SD | TD | ||||||||||
EN | AN | VC | FC | VB | FB | D | T | TS | YM | DT | |
EN | Да | Да | Да | Да | Нет | Нет | Нет | Нет | Нет | ? | ? |
AN | Да | Да | Да | Да | Нет | Нет | Нет | Нет | Нет | Нет | Нет |
C | Да | Да | ? | ? | Да | Да | Да | Да | Да | Да | Да |
B | Нет | Нет | Да | Да | Да | Да | Нет | Нет | Нет | Нет | Нет |
D | Нет | Нет | Да | Да | Нет | Нет | Да | Нет | Да | Нет | Нет |
T | Нет | Нет | Да | Да | Нет | Нет | Нет | Да | Да | Нет | Нет |
TS | Нет | Нет | Да | Да | Нет | Нет | Да | Да | Да | Нет | Нет |
YM | ? | Нет | Да | Да | Нет | Нет | Нет | Нет | Нет | Да | Нет |
DT | ? | Нет | Да | Да | Нет | Нет | Нет | Нет | Нет | Нет | Да |
Оговорки состоят в следующем:
Если TD - интервал, и SD - тип точных чисел, то TD должен содержать единственное поле даты-времени; Если TD - тип точных чисел, и SD - интервал, то SD должен содержать единственное поле даты-времени; Если SD - тип символьных строк, и TD - тип символьных строк постоянной или переменной длины, то репертуар символов SD и TD должен быть одним и тем же.
Результатом применения оператора CAST к неопределенному значению является неопределенное значение. Для значений, отличных от неопределенных, в стандарте приводятся подробные правила выполнения преобразований, которые интуитивно ясны.
Выражение, вырабатывающее значение
Это общая форма скалярного выражения, включающая все возможные типы результирующих значений. Синтаксис следующий:
<value expression> ::= <numeric value expression> |<string value expression> |<datetime value expression> |<interval value expression> <value expression primary> ::= <unsigned value specification> |<column reference> |<set function specification> |<scalar subquery> |<case expression> |<left paren> |<value expression> |<right paren> |<cast specification>
Пояснения: При вычислении выражения V для строки таблицы каждая ссылка на столбец этой таблицы, непосредственно содержащаяся в V, рассматривается как ссылка на значение данного столбца в данной строке. Если первичное выражение есть скалярный подзапрос (подзапрос, результатом которого является таблица, состоящая из одной строки и одного столбца), и результат подзапроса пуст, то результатом первичного выражения является неопределенное значение.
Соединенные таблицы
Конструкция соединенной таблицы - это альтернативный способ порождения новой таблицы на основе использования ранее определенных таблиц (базовых, представляемых или порожденных). Для этой конструкции аналоги в SQL/89 отсутствуют. Фактически соединенная таблица вносит алгебраический стиль в формулировки запросов на языке SQL. Формально соединенная таблица определяется следующими синтаксическими правилами:
<joined table> ::= <cross join> |<qualified join> |<left paren> <joined table> <right paren> <cross join> ::= <table reference> CROSS JOIN <table reference> <qualified join> ::= <table reference> [ NATURAL ] [ <join type> ] JOIN <table reference> [ <join specification> ] <join specification> ::= <join condition> |<named columns join> <join condition> ::= ON <search condition> <named columns join> ::= USING <left paren> <join column list> <right paren> <join type> ::= INNER |<outer join type> [ OUTER ] |UNION <outer join type> ::= LEFT |RIGHT |FULL <join column list> ::= <column name list>
Поскольку раньше мы не встречались с подобными конструкциями, приведем сравнительно подробные объяснения. Предположим, что соединяются таблицы T1 и T2. Пусть CP обозначает их расширенное Декартово произведения: CP = SELECT * FROMT1, T2.
Если специфицировано квалифицированное соединение (qualifiedjoin), то
(a) если указано NATURAL (естественное соединение), то спецификация соединения (joinspecification) должна отсутствовать;
(b) если указано UNION (объединение), то должны отсутствовать и спецификация соединения, и NATURAL;
(c) в противном случае спецификация соединения должна присутствовать.
Если специфицировано квалифицированное соединение, и не указан тип соединения (jointype), то неявно предполагается внутреннее (INNER) соединение. Если специфицировано квалифицированное соединение с условием соединения (joincondition), то
(a) каждая ссылка на столбец, встречающаяся в условии поиска, должна однозначно указывать на столбец таблицы T1 или T2, либо быть внешней ссылкой (ссылкой на столбец запроса более высокого уровня);
(b) если выражение со значением, непосредственно содержащееся в условии поиска, является спецификацией агрегатной функции, то соединенная таблица должна содержаться в разделе HAVING или списке выборки, и спецификация агрегатной функции должна содержать ссылку на внешний столбец.
Если не указано ни NATURAL, ни спецификация соединения, содержащая только имена столбцов соединения (namedcolumnsjoin), то описатели столбцов результата такие же, как описатели столбцов CP. Если указано NATURAL или если спецификация запроса содержит только имена столбцов соединения, то
(a) если указано NATURAL, то пусть именем общего столбца будет имя, являющееся именем столбца для в точности одного столбца T1 и именем столбца для в точности одного столбца T2. Столбцами соединения являются все столбцы T1 и T2 с общими именами;
(b) если указаны имена столбцов соединения, то каждое имя в этом списке имен должно быть именем столбца для в точности одного столбца T1 и именем столбца для в точности одного столбца T2. Пусть именем общего столбца является имя каждого такого столбца. Столбцами соединения являются столбцы T1 и T2, идентифицированные в списке столбцов соединения (joincolumnlist);
(c) пусть C1 и C2 пара соответствующих столбцов соединения из T1 и T2. Типы данных, на которых определены эти столбцы, должны быть совместимы;
(d) пусть SLCC - список выборки порожденных столбцов в форме COALESCE (TA.C, TB.C) ASC (см. п.3.2.4) для каждого столбца соединения в том порядке, в котором они появляются в T1;
(e) пусть SL1 - список выборки столбцов T1, не являющихся столбцами соединения, в том порядке, в котором они появляются в T1, а SL2 - аналогичный список для T2;
(f) описатели столбцов результата соединенной таблицы такие же, как описатели столбцов результата запроса SELECTSLCC, SLT1, SLT2 FROMTR1, TR2.
Каждый столбец CR результата соединенной таблицы, который не является столбцом соединения и соответствует столбцу C1 таблицы T1, потенциально может содержать неопределенные значения, если выполняется любое из следующих условий:
(a) специфицировано RIGHT, FULL или UNION;
(b) специфицировано INNER, LEFT или CROSSJOIN, и столбец С1 потенциально может содержать неопределенные значения.
Каждый столбец CR результата соединенной таблицы, который не является столбцом соединения и соответствует столбцу C2 таблицы T2, потенциально может содержать неопределенные значения, если выполняется любое из следующих условий:
(a) специфицировано LEFT, FULL или UNION;
(b) специфицировано INNER, RIGHT или CROSSJOIN, и столбец С2 потенциально может содержать неопределенные значения.
Каждый столбец CR результата соединенной таблицы, который является столбцом соединения и соответствует столбцам C1 таблицы T1 и C2 таблицы T2, потенциально может содержать неопределенные значения, если выполняется любое из следующих условий:
(a) специфицировано RIGHT, FULL или UNION и столбец C1 потенциально может содержать неопределенные значения;
(b) специфицировано LEFT, FULL или CROSSJOIN, и столбец С2 потенциально может содержать неопределенные значения.
Соединенная таблица является только читаемой. Определим T следующим образом:
(a) если тип соединения есть UNION, то пусть T будет пустым множеством;
(b) если специфицировано CROSSJOIN, то пусть T будет мультимножеством строк CP;
(c) если задано условие соединения, то пусть T будет мультимножеством строк CP, для которых заданное условие поиска вычисляется в true;
(d) если указаны NATURAL или имена столбцов соединения, то
(i) если имеются столбцы соединения, то пусть T будет мультимножеством строк CP, для которых соответствующие столбцы соединения имеют одинаковые значения;
(ii) в противном случае пусть T будет мультимножеством строк CP.
Пусть P1 - мультимножество строк из T1, для которых в T существует некоторая строка, являющаяся конкатенацией некоторой строки R1 из P1 и некоторой строки R2 из T2. Пусть P2 - мультимножество строк из T2, для которых в T существует некоторая строка, являющаяся конкатенацией некоторой строки R1 из T1 и некоторой строки R2 из P2. Пусть мультимножество U1 составляют те строки из T1, которые не входят в P1, а U2 - строки, которые не входят в P2. Пусть D1 и D2 - степени T1 и T2 соответственно. Пусть X1 получается из U1 путем расширения вправо на D2 столбцов, содержащих неопределенные значения, а X2 - из U2 путем расширения влево на D1 столбцов, содержащих неопределенные значения. Результат соединенной таблицы S получается следующим образом:
(a) если задано INNER или CROSSJOIN, то S - мультимножество строк из T.
(b) если указано LEFT, то S - это мультимножество строк, вырабатываемое в результате следующего запроса:
SELECT * FROMT UNIONALL SELECT * FROMX1
(c) если указано RIGHT, то S - это мультимножество строк, вырабатываемое в результате следующего запроса:
SELECT * FROMT UNIONALL SELECT * FROMX2
(d) если указано FULL, то S - это мультимножество строк, вырабатываемое в результате следующего запроса:
SELECT * FROMT UNIONALL SELECT * FROMX1 UNIONALL SELECT * FROMX2
(e) если указано UNION, то S - это мультимножество строк, вырабатываемое в результате следующего запроса:
SELECT * FROMX1 UNIONALL SELECT * FROMX2
Если указаны NATURAL или список имен столбцов соединения, то окончательный результат соединенной таблицы - это мультимножество строк из S, получаемое в результате выполнения следующего запроса: SELECTSLCC, SL1, SL2 FROMS. В противном случае окончательным результатом является S.
Создание таблицы
Каждый слушатель должен будет создать одну таблицу с именем my_libn (моя библиотека), где n - номер рабочей станции слушателя (номер своей рабочей станции можно найти на корпусе системного блока). Таблица должна включать следующие столбцы: book_no (порядковый номер книги в библиотеке), au_id (идентификатор автора), title_id (идентификатор издания), book_val (ваша оценка стоимости книги), pen_val (ваша оценка величины штрафа, который следует изъять с возможного похитителя книги), book_desc (краткая словесная характеристика книги).
Тип данных столбцов book_id, book_val, pen_val - целые числа, тип данных столбца pen_val - строки символов переменной длины с максимальной длиной 40 символов.
Первичным ключом таблицы должен быть объявлен столбец book_id. Столбец au_id должен быть объявлен внешним ключом, ссылающимся на первичный ключ таблицы authors, а столбец title_id - внешним ключом, ссылающимся на первичный ключ таблицы titles. Кроме того, должны быть объявлены два ограничения на столбцы: значения каждого из столбцов book_val и pen_val не должны превосходить 10.000. Единственным ограничением уровня таблицы должно быть следующее: сумма штрафа не превышает удвоенной стоимости книги.
Спецификация запроса
В спецификации запроса задается список выборки (список арифметических выражений над значениями столбцов результата табличного выражения и констант). В результате применения списка выборки к результату табличного выражения производится построение новой таблицы, содержащей то же число строк, но, вообще говоря, другое число столбцов, содержащих результаты вычисления соответствующих арифметических выражений из списка выборки. Кроме того, в спецификации запроса могут содержаться ключевые слова ALL или DISTINCT. При наличии ключевого слова DISTINCT из таблицы, полученной применением списка выборки к результату табличного выражения, удаляются строки-дубликаты; при указании ALL (или просто при отсутствии DISTINCT) удаление строк-дубликатов не производится.
SQL/ в сравнении с SQL/
В этой части курса содержится краткая сводка основных различий между языками SQL/89 и SQL/92.
SQLFlagger
Как упоминалось в начале этого раздела, от реализации, которая провозглашается соответствующей стандарту на любом уровне, требуется обеспечение SQLFlagger. Назначение SQLFlagger состоит в помечании любой специфичной в реализации конструкции SQL, т.е. конструкции, которая распознается и поддерживается реализацией, но не соответствует уровню стандарта, соответствие которому провозглашено. Целью является идентификация свойств SQL, которые могли бы породить разные результаты в разных средах, т.е. свойств, которые потребовали бы внимания, если бы приложения или запросы на SQL перемещались из одной среды в другую. Такие соображения уместны, например, если приложение разрабатывается на рабочей станции, а выполняется на mainframe.
Реализация, которая объявляется соответствующей полному SQL, должна обеспечивать SQLFlagger, который поддерживает следующие опции: - EntrySQLFlagging (т.е. опцию для помечания конструкций SQL, не соответствующих вводному SQL); - IntermediateSQLFlagging (т.е. опцию для помечания конструкций SQL, не соответствующих промежуточному SQL); - FullSQLFlagging (т.е. опцию для помечания конструкций SQL, не соответствующих полному SQL).
Должны также поддерживаться опции проверки "только синтаксиса" и "с привлечением каталога". Проверка "только синтаксиса" означает, что от реализации требуется выполнение только тех проверок, которые возможны без доступа к схеме определений (DefinitionSchema). Проверка "с привлечением каталога" означает, что от реализации дополнительно требуется выполнять те проверки (за исключением проверок привилегий), которые возможны, если схема определений доступна. В обоих случаях проверка замышляется только статической (т.е. "времени компиляции"); не требуется проверка элементов, которые невозможно определить до времени выполнения.
Реализация, объявленная соответствующей промежуточному SQL, должна обеспечивать SQLFlagging, который поддерживает вводный SQL и промежуточный SQL, и должна поддерживать как минимум проверку "только синтаксиса".
Реализация, объявленная соответствующей вводному SQL, должна обеспечивать SQLFlagging, который поддерживает как минимум проверку "только синтаксиса" вводного SQL.
Средства определения и манипулирования схемой
Как и в SQL/89, в SQL/92 существует оператор определения схемы, с помощью которого можно за одно обращение к СУБД создать все необходимые объекты, связанные с указанным идентификатором авторизации. Этот оператор имеет следующий синтаксис:
<schema definition> ::= CREATE SCHEMA <schema name clause> [ <schema character set specification> ] [ <schema element>... ] <schema name clause> ::= <schema name> |AUTHORIZATION <schema authorization identifier> <schema name> AUTHORIZATION <schema authorization identifier> <schema authorization identifier> ::= <authorization identifier> <schema character set specification> ::= DEFAULT CHARACTER SET <character set specification> <schema element> ::= <domain definition> |<table definition> |<view definition> |<grant statement> |<assertion definition> |<character set definition> |<collation definition> |<translation definition>
Пояснения:
Если имя схемы не специфицировано, но неявно в качестве имени схемы используется идентификатор авторизации схемы. Если в определении схемы отсутствует раздел AUTHORIZATION, то
(a) если определение схемы содержится в модуле, то в качестве идентификатора авторизации схемы используется идентификатор авторизации модуля;
(b) иначе, в качестве идентификатора авторизации схемы используется идентификатор авторизации SQL-сессии.
При выполнении оператора определения схемы создаются объекты, определяемые элементами схемы (базовые таблицы, представления, ограничения, домены, утверждения целостности, наборы символов, привилегии и т.д.), и их соответствующие описатели.
В отличие от SQL/89, (a) операторы, используемые для определения элементов схемы, можно использовать независимо, вне оператора определения схемы и (b) созданную ранее схему можно уничтожить. Для уничтожения схемы используется оператор DROPSCHEMA, определяемый следующим синтаксисом:
<drop schema statement> ::= DROP SCHEMA <schema name> <drop behavior> <drop behavior> ::= CASCADE RESTRICT
Пояснения:
Имя схемы должно идентифицировать существующую схему. Если специфицировано RESTRICT, то к моменту выполнения оператора DROPSCHEMA схема не должна содержать какие бы то ни было объекты (постоянные базовые таблицы, глобальные временные таблицы, создаваемые локальные временные таблицы, представления и т.д.); эти объекты должны быть ранее уничтожены соответствующими индивидуальными операторами (см. п. 3.5.6). Если специфицировано CASCADE, то такие объекты уничтожаются при выполнении оператора DROPSCHEMA путем неявного вызова соответствующих операторов. При выполнении оператора DROPSCHEMA указанная схема и ее описание уничтожаются.
Средства определения представлений
Представляемая таблица, или просто представление создается с помощью оператора CREATEVIEW, который похож на соответствующий оператор языка SQL/89, но обладает существенно расширенными возможностями. Для полноты мы опишем этот оператор достаточно подробно. Как обычно, начнем со сводки синтаксических правил:
<view definition> ::= CREATE VIEW <table name> [ <left paren> <view column list> <right paren> ] AS <query expression> [ WITH [ <levels clause> ] CHECK OPTION ] <levels clause> ::= CASCADED | LOCAL <view column list> ::= <column name list>
Пояснения:
Выражение запроса не должно содержать спецификацию цели или динамического параметра. Имя определяемого представления не должно содержаться в какой-либо ссылке на таблицу, содержащейся в выражении запроса (другими словами, не допускаются рекурсивные определения представлений). В выражении запросов не должны встречаться имена временных объявляемых таблиц. Если выражение запроса является обновляемым, то и определяемое представление является обновляемым. В противном случае представляемая таблица - только читаемая.
(a) выражение запроса является обновляемым в том и только в том случае, когда содержит только выражение запроса QE или спецификацию запроса QS и
(i) выражение запроса содержит QS или QS, не включающие выражение запроса без соединения с операторами UNION или EXCEPT;
(ii) выражение запроса содержит QE или QS, не включающие терм запроса без соединения с оператором INTERSECT;
(iii) QE или QS являются обновляемыми;
(b) спецификация запроса QS является обновляемой в том и только в том случае, когда
(i) в QS не специфицировано DISTINCT;
(ii) каждое выражение, содержащееся в списке выборки QS, состоит из ссылки на столбец, и ни одна ссылка на столбец не появляется более одного раза;
(iii) раздел FROM табличного выражения, непосредственно входящего в QS, содержит в точности одну ссылку на таблицу, указывающую на базовую таблицу или на обновляемую порождаемую таблицу;
(iv) таблица, на которую содержится ссылка в разделе FROM верхнего уровня, не должна использоваться в подзапросах, входящих в раздел FROM;
(v) табличное выражение, непосредственно содержащееся в QS, не должно включать разделы GROUPBY и HAVING;
(c) порождаемая таблица является обновляемой в том и только в том случае, когда обновляемым является выражение запроса, содержащееся в табличном подзапросе;
(d) соответствующие синтаксические правила и пояснения содержатся в разд. 3.3 (мы сознательно не говорили в этом разделе о правилах обновляемости, потому что они больше связаны с представлениями).
Число имен столбцов в списке столбцов представления должно совпадать со степенью таблицы, специфицированной выражением запроса. Если в определении представления содержится раздел WITHCHECKOPTION, то представление должно быть обновляемым. Если специфицировано WITHCHECKOPTION без задания раздела уровней (levelsclause), то по умолчанию полагается указание класса CASCADED. Если в определении представления специфицирован список столбцов представления, то i-тый столбец представления имеет i-тое имя из этого списка. В противном случае имена столбцов представления совпадают с именами столбцов таблицы, специфицируемой выражением запроса. Набор привилегий, которые получает создатель по отношению к определяемому представлению, определяется сравнительно громоздким набором правил и в конечном счете зависит от набора привилегий, которыми располагает создатель по отношению к базовым таблицам, лежащим в основе представления, и от того, является ли представление обновляемым. В соответствии с правилами обновляемости представления, для каждой строки обновляемого представления существует и только одна строка базовой таблицы, на которой в конечном счете основывается это представление. Занесение новой строки, удаление или модификация существующей строки приводит к выполнению соответствующей операции над строками этой базовой таблицы. Пусть V1 - представление. По определению V1 перекрывает (span) V1, и V1 перекрывает представление V2, если V2 используется в определении V1. Под операцией обновления понимаются операция INSERT и позиционная, поисковая, динамическая позиционная и подготавливаемая динамическая позиционная операции UPDATE. Если представление V1 перекрывает представление V2, в определении V2 содержался раздел WITHCHECKOPTION, и в результате выполнения операции обновления V1 возникает строка, невидимая в V2, то
(a) если в определении V1 было указано CASCADED, то вырабатывается исключительное условие;
(b) если в определении V1 было указано LOCAL и в результате выполнения операции обновления возникает строка, видимое в таблице, на которой непосредственно определено представление V2, то вырабатывается исключительное условие.
Проверка ограничения WITHCHECKOPTION выполняется в конце каждой операции обновления.
Средства определения схемы
Средства определения схемы БД в стандарте SQL/89 относятся к наиболее слабым и допускающим различную интерпретацию частям стандарта. Более того, мне неизвестна ни одна реализация, в которой поддерживался бы в точности такой набор средств определения схемы.
Поэтому, чтобы добиться мобильности прикладной системы в достаточно широком классе реализаций SQL/89, необходимо тщательно локализовать компоненты определения схемы БД. Думаю, что лучше всего сосредоточить всю работу со схемой БД в одном модуле и иметь в виду, что при переходе к другой СУБД очень вероятно потребуется переделка этого модуля.
Особо отметим, что в SQL/89 вообще отсутствуют какие-либо средства изменения схемы БД: нет возможности удалить схему таблицы, добавить к схеме таблицы новый столбец и т.д. Во всех реализациях такие средства поддерживаются, но они могут различаться и синтаксисом, и семантикой.
Несмотря на отсутствие особых надежд на то, что удастся встретить реализацию, поддерживающую язык определения схем SQL/89, мы коротко опишем этот язык (без синтаксических деталей), чтобы оценить на содержательном уровне возможности SQL/89 в этой части и получить хотя бы какие-то средства сравнения разных реализаций.
2.4.1. Оператор определения схемы
В соответствии с правилами SQL/89 каждая таблица данной БД имеет простое и квалифицированное имена. В качестве квалификатора имени выступает "идентификатор полномочий" таблицы, который обычно в реализациях совпадает с именем некоторого пользователя. Квалифицированное имя таблицы имеет вид:
<идентификатор полномочий>.<простое имя>
Подход к определению схемы в SQL/89 состоит в том, что все таблицы с одним идентификатором полномочий создаются (определяются) путем выполнения одного оператора определения схемы. При этом в стандарте не определяется способ выполнения оператора определения схемы: должен ли он выполняться только в интерактивном режиме или может быть встроен в программу, написанную на традиционном языке программирования.
В операторе определения схемы содержится идентификатор полномочий и список элементов схемы, каждый из которых может быть определением таблицы, определением представления (view) или определением привилегий. Каждое из этих определений представляется отдельным оператором SQL/89, но все они, как уже говорилось, должны быть встроены в оператор определения схемы.
Для этих операторов мы приведем синтаксис, поскольку это позволит более четко описать их особенности.
Средства уничтожения элементов схемы базы данных
Для каждого из упомянутых в этом разделе операторов создания элементов схемы базы данных имеются обратные операторы уничтожения этих элементов.
Созданная ранее таблица может быть уничтожена следующим оператором:
<drop table statement> ::= DROP TABLE <table name> <drop behavior>
Пояснения:
Пусть уничтожается таблица с именем T. T должна быть базовой таблицей. T не должна быть временной объявляемой таблицей. Если специфицировано RESTRICT, то ни в каком существующем представлении и ни в каком условии поиска существующего ограничения не должны содержаться ссылки на T. Пусть A обозначает текущий идентификатор авторизации. Тогда при выполнении оператора уничтожения таблицы неявно выполняется следующий оператор: REVOKEALLPRIVILEGESONTFROMACASCADE, что при наличии спецификации CASCADE в операторе уничтожения таблицы приводит к уничтожению всех объектов, в определении которых использовалась ссылка на T. Таблица T и ее дескриптор уничтожаются.
Созданное ранее представление может быть уничтожено с помощью следующего оператора:
<drop view statement> ::= DROP VIEW <table name> <drop behavior>
Пояснения:
Пусть V - имя уничтожаемого представления. V должно быть именем представляемой таблицы. Если специфицировано RESTRICT, то ни в одном существующем представлении или условии поиска существующего ограничения не должна содержаться ссылка на V. Пусть A обозначает текущий идентификатор авторизации. При выполнении оператора уничтожения представления неявно выполняется следующий оператор: REVOKEALLPRIVILEGESONTFROMACASCADE, что при наличии спецификации CASCADE в операторе уничтожения представления приводит к уничтожению всех объектов, в определении которых использовалась ссылка на V.
Оператор уничтожения домена имеет следующий синтаксис:
<drop domain statement> ::= DROP DOMAIN <domain name> <drop behavior>
Пояснения:
Пусть D - имя уничтожаемого домена. Если специфицировано RESTRICT, то ссылки на D должны отсутствовать в любом описателе столбца, в выражении запроса любого представления и в условии поиска любого ограничения. Пусть C обозначает описатель столбца, определенного на домене D; T - имя таблицы, описатель которой включает C. C модифицируется следующим образом:
(a) из C удаляется ссылка на D, и в C включается копия описателя типа данных D;
(b) если C не включает раздела значения по умолчанию, а описатель D включает такой раздел, то в C включается раздел умолчания D;
(c) для каждого описателя ограничения домена D выполняются следующие действия:
(i) пусть TCD обозначает табличное ограничение с определяемым в реализации именем, которое порождено из проверочного ограничения домена путем замены VALUE на имя столбца C с сохранением атрибутов ограничения;
(ii) если для идентификатора полномочий текущей SQL-сессии имеются необходимые привилегии, выполняется неявный оператор ALTERTABLETADDTCD;
Пусть A - текущий идентификатор полномочий. Выполняется следующий неявный оператор REVOKE: REVOKEUSAGEONDOMAINDNFROMACASCADE Описатель домена разрушается.
Утверждение целостности уничтожается с помощью следующего оператора:
<drop assertion statement> ::= DROP ASSERTION <constraint name>
Пояснение:
При выполнении оператора описатель идентифицируемого утверждения целостности разрушается.
Структура стандарта и его характеристика
В стандарте определяются два уровня языка и отдельное средство поддержания целостности. Уровень 2 - это полный язык баз данных SQL, не включающий средство поддержания целостности. Уровень 1 - это специфицированное подмножество уровня 2.
Средство поддержания целостности включает возможности определения:
требуемых ограничений на ссылки между таблицами; проверочных ограничений на строки таблицы; значений столбца по умолчанию при занесении строки в таблицу.
В приложениях к стандарту определяется синтаксис включения операторов манипулирования данными SQL в обычную во всех остальных отношениях прикладную программу. Такой синтаксис определяется как сокращенная нотация для стандартной прикладной программы, в которой встроенные операторы SQL заменены явными "вызовами" процедур базы данных, содержащими операторы SQL.
Синтаксические элементы стандарта определяются в следующих терминах:
Функция: короткое предложение о назначении элемента. Формат: БНФ-определение синтаксиса элемента. Синтаксические правила: дополнительные синтаксические ограничения, которым должен удовлетворять элемент, не выраженные в БНФ. Общие правила: последовательная спецификация эффекта выполнения элемента.
В синтаксических правилах термин "должен" определяет условия, которым должен удовлетворять любой вариант языка SQL, синтаксически соответствующий стандарту. Вариант языка SQL синтаксически соответствует стандарту, если соответствует и определениям синтаксиса, и синтаксическим правилам.
В общих правилах термин "должен" определяет условия, которые проверяются во время выполнения операторов SQL. Если все эти условия истинны, то оператор выполняется успешно, и в параметр SQLCODE устанавливается определенное неотрицательное число. Если какое-либо из условий ложно, оператор не выполняется успешно, не влияет на состояние базы данных, и в параметр SQLCODE устанавливается определяемое в реализации отрицательное число.
В соответствующей стандарту реализации не требуется выполнение точной последовательности действий, определенных в общих правилах, но должен достигаться тот же эффект, что и при выполнении этой последовательности. Термин "фактически" используется в общих правилах для того, чтобы выделить действия, результат которых может быть достигнут в реализации другим способом.
Термин "долговременно хранимый объект" используется для характеризования таких объектов, как <модуль> (<module>) и <схема> (<schema>), которые создаются и уничтожаются с помощью механизмов, определенных реализатором.
Структура запросов
Для того, чтобы можно было более или менее точно рассказать про структуру запросов в стандарте SQL/89, необходимо начать со сводки синтаксических правил:
<cursor specification> ::= <query expression> [<order by clause>] <query expression> ::= <query term> <query expression> UNION [ALL] <query term> <query term> ::= <query specification> | (<query expression>) <query specification> ::= (SELECT [ALL DISTINCT] <select list> <table expression>) <select statement> ::= SELECT [ALL DISTINCT] <select list> INTO <select target list> <table expression> <subquery> ::= (SELECT [ALL DISTINCT] <result specification> <table expression> <table expression> ::= <from clause> [<where clause>] [<group by clause>] [<having clause>]
Язык допускает три типа синтаксических конструкций, начинающихся с ключевого словаSELECT: спецификация курсора (cursorspecification), оператор выборки (selectstatement) и подзапрос (subquery). Основой всех них является синтаксическая конструкция "табличное выражение (tableexpression)". Семантика табличного выражения состоит в том, что на основе последовательного применения разделов from, where, groupby и having из заданных в разделе from таблиц строится некоторая новая результирующая таблица, порядок следования строк которой неопределен и среди строк которой могут находиться дубликаты (т.е. в общем случае таблица-результат табличного выражения является мультимножеством строк). На самом деле, именно структура табличного выражения наибольшим образом характеризует структуру запросов языка SQL/89. Мы рассмотрим ниже структуру и смысл разделов табличного выражения, но до этого немного подробнее обсудим три упомянутые конструкции, включающие табличные выражения.
2.3.1. Спецификация курсора
Наиболее общей является конструкция "спецификация курсора". Курсор - это понятие языка SQL, позволяющее с помощью набора специальных операторов получить построчный доступ к результату запроса к БД. К табличным выражениям, участвующим в спецификации курсора, не предъявляются какие-либо ограничения. Как видно из сводки синтаксических правил, при определении спецификации курсора используются три дополнительных конструкции: спецификация запроса, выражение запросов и раздел ORDERBY.
Сводка расширений SQL/ по отношению к SQL/
В этом разделе мы приводим сводку основных новых свойств, введенных в SQL/92.
Все, что относится к встроенному SQL. Встроенный SQL не являлся частью SQL/89 и был частично специфицирован только в приложениях. Кроме того, в этих приложениях не специфицировалась поддержка языков Си и Ада. Все, что относится к работе с каталогами и почти все, что касается работы со схемами. В SQL/89 имелся оператор CREATESCHEMA, но не было оператора DROPSCHEMA, и все операторы CREATETABLE, CREATEVIEW и GRANT должны были специфицироваться как "элементы схемы" внутри такого оператора CREATESCHEMA (т.е. не было понятия независимого выполнения таких операторов, как в SQL/92). Однако понятие схемы было по существу не определено. Заметим также, что CREATETABLE, CREATEVIEW и GRANT в SQL/89 были только операциями определения данных; не существовали DROPTABLE, ALTERTABLE и т.д. Возможность включать в модуль все виды операторов SQL. Как уже отмечалось, CREATETABLE, CREATEVIEW и GRANT в SQL/89 должны были выполняться как компоненты операции CREATESCHEMA; на самом деле, CREATESCHEMA, CREATETABLE, CREATEVIEW и GRANT вместе составляли отдельный "язык схемы", который отличался от "языка модулей". Нежелательное и не необходимое различие между языком схем и языком модулей почти полностью устранено в SQL/92. Возможность включать все виды операций SQL (в частности, возможность смешивать операции определения данных и манипулирования данными) в одну транзакцию. По причине разделения языков схем и модулей, отмеченного в предыдущем параграфе, SQL/89 не обладал этим свойством. Все, что относится к управлению подключениями и сессиями. Оператор SETTRANSACTION, включающий, в частности, возможность определения уровня изоляции (в SQL/89 поддерживался только уровень SERIALIZABLE, и только неявно). Все, что относится к работе с доменами, включая CREATE, ALTER и DROPDOMAIN. Операторы ALTER и DROPTABLE. Все, что связано с работой с временными таблицами. Варианты CASCADED и LOCAL опции проверки при CREATEVIEW. Оператор DROPVIEW. Почти все, что относится к работе с ограничениями целостности, за исключением случаев определения возможного и внешнего ключей и одного простого вида проверочного ограничения базовой таблицы. В SQL/89 имелись возможные и внешние ключи и проверочные ограничения для одной строки (т.е. ограничения, которые можно проверять для данной строки, рассматривая ее в изоляции). Однако отсутствовали общие (с несколькими строками) ограничения, не было разновидностей FULL и PARTIAL для соответствия внешних ключей и не было отложенных проверок (DEFERRABLE, INITIALLYDEFERRED, SETCONSTRAINTS и т.д.). Оператор REVOKE. Строки символов переменной длины. Битовые строки постоянной и переменной длины. Все, что относится к работе с датами и временем. Почти все, что касается работы с наборами символов, сравнениями, трансляциями и преобразованиями (включая поддержку национальных наборов символов и наборов символов для идентификаторов). В SQL/89 поддерживался тип данных строк постоянной длины вместе с соответствующим набором операторов присваивания и сравнения, но это все, что было (в частности, набор символов и правила их сравнения определялись по существу в реализации). Все скалярные операторы и функции (за исключением +, -, *, / и USER), включающие, в частности, операторы CASE и CAST для управления преобразованиями типов данных. Существенно улучшенная ортогональность в скалярных выражениях, включая, в частности, возможность использования скалярных выражений из базы данных как операндов внутри таких выражений. Спецификации FORUPDATE, SCROLL и INSENSITIVE в DECLARECURSOR. Существенно улучшенная ортогональность в табличных выражениях, включая
(а) возможность вводить имена столбцов результата и имена таблиц;
(b) набор правил вывода имени столбца;
(c) возможность вложенных табличных выражений.
Явная поддержка INTERSECT, EXCEPT и JOIN (включая естественные и внешние соединения). Конструкторы строк, включая, в частности, возможность использования таких конструкторов в условных выражениях наряду со скалярами. Новые условия MATCH и UNIQUE. Новые условия IS[NOT]TRUE, IS[NOT]FALSE и IS[NOT]UNKNOWN. Все, что касается динамического SQL. Информационная схема. SQLSTATE и все, что касается работы с областью диагностики. Более исчерпывающее обращение с прямым SQL (хотя многие конкретные вещи все еще остались определяемыми в реализации).
Табличное выражение
Стандарт SQL/89 рекомендует рассматривать вычисление табличного выражения как последовательное применение разделов FROM, WHERE, GROUPBY и HAVING к таблицам, заданным в списке FROM.
Табличные выражения
Как и в SQL/89, табличное выражение SQL/92 в качестве результата выдает обычную или сгруппированную таблицу:
<table expression> ::= <from clause> [ <where clause> ] [ <group by clause> ] [ <having clause> ]
Все отличия от SQL/89 сосредоточены в разделах табличного выражения.
Последний полный проект стандарта был
Последний полный проект стандарта был опубликован и предоставлен в свободный доступ в 1993 г. Этот документ имеет очень большой объем (более 3 Мб плоского текста) и носит очень предварительный характер. Видимо, осознавая практическую невозможность разработки и согласования стандарта такого объема, в том же 1983 г. комитеты ANSI и ISO приняли решение о расщеплении стандарта на несколько независимо разрабатываемых и отдельно согласовываемых частей. К настоящему времени таких частей семь:
Часть 1: Неформальное описание назначения и структуры документа; Часть 2: Основные свойства языка, включая базовые постоянно хранимых модулей (PSMPersistentStoredModules), новые типы данных; триггеры, подтаблицы, абстрактные типы данных, объектно-ориентированные возможности; Часть 3: Интерфейс уровня вызовов (CLICallLevelInterface); Часть 4: SQL/PSM, включая спецификации хранимых процедур с обеспечением их вычислительной полноты; Часть 5: Динамический и встроенный SQL (предполагается, что эта часть будет заимствована из SQL/92); Часть 6: Спецификация интерфейса XA, разработанного X/Open (это относится к управлению распределенными транзакциями); Часть 7: Темпоральные расширения языка SQL.
Разработка третьей части стандарта была завершена в 1995 г. SQL/CLI является аккуратной формализацией интерфейса ODBC, разработанного компанией Microsoft (кстати, это первый случай в истории стандартизации языка SQL, когда за основу международного стандарта принимается некоторый корпоративный стандарт). В том же году стандарт был принят ISO и получил официальное наименование ISO/IEC 9075-3:1995 Informationtechnology - Databaselanguages - SQL - Part 3: Call-LevelInterface (SQL/CLI).
В 1996 г. была закончена разработка четвертой части. Стандарт был принят ISO в конце 1996г. и получил официальное название ISO/IEC 9075-4:1996 Informationtechnology - Databaselanguages - SQL - Part 4: PersistentStoredModules (SQL/PSM).
Про время завершения остальных частей стандарта известно только то, что комитеты обещают закончить работу в 1999 г. Регулярно (хотя и не очень часто) обновляемую информацию о текущем состоянии дел в области стандартизации SQL/3 можно получить на Web-узле
В заключение заметим, что хотя стандарт SQL/3 все еще далек от завершения, практически все компании-производители СУБД утверждают по поводу своих новых продуктов, что они поддерживают базовые свойства SQL/3. В частности, это относится к IBMDB2, InformixUniversalServer и Oracle 8. Информацию относительно этих продуктов можно найти в Web-узлах компаний (www.ibm.com, www.informix.com, www.oracle.com). Обзоры статей, связанных с этой темой, публикуются на сервере www.citforum.ru, а также в журнале "СУБД" (электронная версия доступна по адресу www.osp.ru).
Типы данных
В языке SQL/89 поддерживаются следующие типы данных: CHARACTER, NUMERIC, DECIMAL, INTEGER, SMALLINT, FLOAT, REAL, DOUBLE PRECISION. Эти типы данных классифицируются на типы строк символов, точных чисел и приблизительных чисел.
К первому классу относится CHARACTER. Спецификатор типа имеет вид CHARACTER (length), где length задает длину строк данного типа. Заметим, что в SQL/89 нет типа строк переменного размера, хотя во многих реализациях они допускаются. Литеральные строки символов изображаются в виде 'последовательность-символов' (например, 'example').
Представителями второго класса типов являются NUMERIC, DECIMAL (или DEC), INTEGER (или INT) и SMALLINT. Спецификатор типа NUMERIC имеет вид NUMERIC [(precision [, scale]). Специфицируются точные числа, представляемые с точностью precision и масштабом scale. Здесь и далее, если опущен масштаб, то он полагается равным 0, а если опущена точность, то ее значение по умолчанию определяется в реализации.
Спецификатор типа DECIMAL (или DEC) имеет вид NUMERIC [(precision [, scale]). Специфицируются точные числа, представленные с масштабом scale и точностью, равной или большей значения precision.
INTEGER специфицирует тип данных точных чисел с масштабом 0 и определяемой в реализации точностью. SMALLINT специфицирует тип данных точных чисел с масштабом 0 и определяемой в реализации точностью, не большей, чем точность чисел типа INTEGER.
Литеральные значения точных чисел в общем случае представляются в форме
[+ -] <целое-без-знака> [.<целое-без-знака>].
Наконец, в классу типов данных приблизительных чисел относятся типы FLOAT, REAL и DOUBLE PRECISION. Спецификатор типа FLOAT имеет вид FLOAT [(precision)]. Специфицируются приблизительные числа с двоичной точностью, равной или большей значения precision.
REAL специфицирует тип данных приблизительных чисел с точностью, определенной в реализации. DOUBLE PRECISION специфицирует тип данных приблизительных чисел с точностью, определенной в реализации, большей, чем точность типа REAL.
Литеральные значения приблизительных чисел в общем случае представляются в виде
<литеральное-значение-точного-числа>E<целое-со-знаком>.
Заметим, что хотя с использованием языка SQL можно определить схему БД, содержащую данные любого из перечисленных типов, возможность использования этих данных в прикладных системах зависит от применяемого языка программирования. Весь набор типов данных можно использовать, только если программировать на ПЛ/1. Поэтому в некоторых реализациях SQL типы данных с масштабом и точностью вообще не поддерживаются.
Хотя правила встраивания SQL в программы на языке Си не определены в SQL/89, в большинстве реализаций, поддерживающих такое встраивание, имеется следующее соответствие между типами данных SQL и типами данных Си: CHARACTER соответствует строкам Си; INTEGER соответствует long; SMALLINT соответствует short; REAL соответствует float; DOUBLE PRECISION соответствует double (именно такое соответствие утверждено в стандарте SQL/92).
Заметим еще, что в большинстве реализаций SQL поддерживаются некоторые дополнительные типы данных, например, DATE, TIME, INTERVAL, MONEY. Некоторые из этих типов специфицированы в стандарте SQL/92, но в текущих реализациях синтаксические и семантические свойства таких типов могут различаться.
Типы дата-время и интервальные типы
Начнем с того, по какой причине в языке SQL появились эти типы данных (все вместе их можно было бы назвать темпоральными типами, т.е. типами, связанными со временем). В принципе, таблицы реляционных баз данных являются плоскими; каждая строка таблицы соответствует текущему состоянию моделируемого объекта предметной области. Однако на практике часто возникает потребность хранить в одной таблице информацию о состоянии объектов в разные моменты времени. До появления в языке темпоральных типов это можно было реализовать только одним способом: ввести в таблицу дополнительный столбец, в котором хранились бы временные метки создания соответствующих строк. Но если нет унифицированного представления таких временных меток, то вся логика их обработки уходит в прикладную программу, и другая прикладная программа не сможет работать с той же базой данных, если эта логика не будет в нее перенесена. Так что идея очень проста: унифицировать и сделать понятным системе смысл временных меток и временных интервалов.
Однако механизм, предлагаемый в стандарте SQL/92, очень громоздок по причине большого количества несущественных по смыслу деталей: с какой точностью сохранять временные метки и интервалы, как задать временную зону, в которой они возникают и т.д. Поэтому мы рассмотрим особенности этих типов очень коротко (соответствующие спецификации составляют значительную часть громадного документа).
Элемент типа дата-время составляется из смежного поднабора полей:
YEAR | Год от Рождества Христова |
MONTH | Месяц в пределах года |
DAY | День в пределах месяца |
HOUR | Час в пределах дня |
MINUTE | Минута в пределах часа |
SECOND | Секунда и, возможно, доли секунды в пределах минуты |
Реальный смежный поднабор полей, составляющих элемент типа дата-время определяется квалификатором дата-времени, называемым точностью элемента. Имеется подразумеваемая упорядоченность полей YEAR, MONTH, DAY, HOUR, MINUTE, SECOND. Значения каждого поля ограничиваются естественными правилами, регулирующими законные даты и время.
Элемент типа INTERVAL составляется из смежного поднабора полей:
YEAR | Года |
MONTH | Месяца |
или
DAY | Дни |
HOUR | Часы |
MINUTE | Минуты |
SECOND | Секунды и, возможно, доли секунд |
Внутри элемента типа интервал первое поле не ограничивается. Последующие поля ограничиваются следующим образом:
MONTH | Месяцы в пределах года (0-11) |
DAY | Не ограничивается |
HOUR | Часы в пределах дня (0-23) |
MINUTE | Минуты в пределах часа (0-59) |
SECOND | Секунды в пределах минуты (0-59.999...) |
Тип первого операнда | Оператор | Тип второго операнда | Тип результата |
Datetime | - | Datetime | Interval |
Datetime | + или - | Interval | Datetime |
Interval | + | Datetime | Datetime |
Interval | + или - | Interval | Interval |
Interval | * или / | Numeric | Interval |
Numeric | * | Interval | Interval |
Транзакции, подключения к базе данных, сессии
SQL-агентом называется зависимый от реализации объект, вызывающий выполнение операторов SQL. Под SQL-транзакцией (иногда называемой просто транзакцией) понимается последовательность выполнения операторов SQL, являющаяся атомарной по отношению к восстановлению. Эти операции выполняются одной или более единицами компиляции и модулями или путем прямого вызова SQL. От реализации зависит, могут ли в одной транзакции выполняться динамические и/или статические операторы выборки и манипулирования данными и динамические и/или статические операторы определения и манипулирования схемой. Если такие сочетания допускаются, то поведение открытого курсора, подготовленного динамического оператора, отложенного ограничения определяются в реализации.
Каждый модуль или прямой вызов SQL, инициирующие выполнение оператора, ассоциируются с транзакцией. SQL-транзакция начинается при выполнении процедуры из некоторого модуля или прямого вызова оператора SQL вне активной транзакции. Транзакция завершается при выполнении операторов COMMIT или ROLLBACK. Если SQL-транзакция завершается успешным выполнением оператора COMMIT, то все изменения, произведенные ею над данными и/или схемой становятся постоянно хранимыми и доступными всем параллельно выполняющимся или образуемым впоследствии транзакциям. Если транзакция завершается оператором ROLLBACK или если выполнение оператора COMMIT оказывается неуспешным, то все изменения, произведенные транзакцией над данными и/или схемой, ликвидируются. Если выполнение оператора COMMIT было начато, но при этом возникли определенные исключительные условия, то неизвестно, зафиксированы или уничтожены результаты этой транзакции.
У каждой SQL-транзакции имеется режим доступа - "только чтение" или "чтение и запись". Режим доступа может быть явно установлен оператором SETTRANSACTION; по умолчанию он устанавливается в "чтение-запись". Термин "только чтение" применяется только к постоянно хранимым базовым и представляемым таблицам.
SQL-транзакции приписывается ограничение размера области диагностики - положительное целое число, определяющее максимальное число условий, которые могут быть помещены в область диагностики при выполнении оператора SQL в этой транзакции.
Транзакции, инициированные разными SQL-агентами, которые обращаются к одним и тем же данным и/или схемам, являются конкурирующими (concurrent; по-русски обычно такие транзакции называют "параллельно" выполняющимися).
Каждой SQL-транзакции приписывается некоторый уровень изоляции: READUNCOMMITTED, READCOMMITTED, REPEATABLEREAD или SERIALIZABLE. Уровень изоляции транзакции определяет степень, в которой на операции этой транзакции влияют операции параллельно выполняющихся транзакций и в которой операции данной транзакции влияют на операции других транзакций. Уровень изоляции может быть явно установлен оператором SETTRANSACTION. По умолчанию устанавливается уровень изоляции SERIALIZABLE. При выполнении конкурирующих транзакций на этом уровне изоляции гарантируется их сериализуемость. Сериализованное выполнение - это такое выполнение операций конкурирующих транзакций, которое производит тот же самый окончательный эффект, что и некоторое последовательное выполнение этих транзакций (т.е. такое выполнение, при котором каждая транзакция полностью завершается до начала следующей). Уровень изоляции определяет вид явления, которое может произойти при параллельном выполнении транзакций. Возможны следующие виды явлений:
P1 ("Dirtyread" - "Грязное чтение"): Транзакция T1 модифицирует строку. Затем транзакция T2 читает эту строку до того, как T1 выполняет COMMIT. Если после этого T1 выполнит ROLLBACK, то окажется, что T2 прочитала строку, которая никогда не была зафиксирована; можно считать, что эта строка никогда не существовала. P2 ("Non-repeatableread" - "Неповторяющееся чтение"): Транзакция T1 читает строку. Затем транзакция T2 модифицирует или удаляет эту строку и выполняет COMMIT. Если после этого T1 попытается повторно прочитать эту строку, то либо получит ее измененное состояние, либо обнаружит, что строка удалена. P3 ("Phantom" - "Фантом"): Транзакция T1 читает набор строк N, которые удовлетворяют некоторому условию поиска. Затем транзакция T2 выполняет операторы SQL, которые генерируют одну или более строк, удовлетворяющих условию поиска, использованному T1. Если после этого транзакция T1 повторит чтение с тем же самым условием поиска, она получит другой набор строк.
Все четыре уровня изоляции гарантируют, что каждая SQL-транзакция либо выполнится полностью, либо не выполнится совсем и что ни одно изменение не будет потеряно. Уровни изоляции различаются по отношению к явлениям P1, P2 и P3. В приводимой ниже таблице показано, какие явления возможны, а какие невозможны на данном уровне изоляции.
Уровень изоляции | P1 | P2 | P3 |
READUNCOMMITTED | Возможно | Возможно | Возможно |
READCOMMITTED | Невозможно | Возможно | Возможно |
REPEATABLEREAD | Возможно | Невозможно | Возможно |
SERIALIZABLE | Невозможно | Невозможно | Невозможно |
Изменения данных и/или схем, произведенные транзакцией, не завершившей выполнение оператором COMMIT, могут быть восприняты этой транзакцией в той же самой SQL-сессии. Кроме того, изменения будут видны другим транзакциям и этой транзакции в других сессиях на уровне изоляции READUNCOMMITTED, но не будут видны другим транзакциям на уровне изоляции READCOMMITTED, REPEATABLEREAD, или SERIALIZABLE.
Если в реализации обнаруживается невозможность гарантировать сериализуемость двух или более параллельно выполняемых транзакций, то неявно может быть инициировано выполнение оператора ROLLBACK. Неявное выполнение ROLLBACK может быть также инициировано реализацией при распознавании невосстановимых ошибок. В этих случаях генерируется соответствующее исключительное условие.
С учетом того, что выполняемые внутри транзакции операторы изменения данных или схемы не оказывают влияния, если нарушают ограничения целостности, при сериализуемом выполнении транзакции все чтения являются повторяемыми за исключением следующих случаев:
изменения данных или схем произведены явно самой транзакцией; при повторном чтении процедуре передаются другие значения параметров; используются изменяемые во времени переменные, такие как CURRENT_DATEandCURRENT_USER.
SQL-подключение - это ассоциация между SQL-клиентом и SQL-сервером. Подключение устанавливается и именуется с помощью оператора CONNECT, в котором сервер идентифицируется именем. В реализации определяется, каким образом используется имя сервера, чтобы установить его местоположение и коммуникационный протокол, требуемый для доступа к серверу и создания SQL-сессий.
SQL-соединение активно, если какой-либо оператор SQL, инициировавший или востребоваший SQL-транзакцию, был выполнен на соответствующем сервере в течение текущей транзакции. Соединение может быть текущим или потенциальным. Если соединение, установленное самым последним по времени выполнения явным или неявным оператором CONNECT (или SETCONNECTION), не разорвано, то это соединение является текущим; в противном случае оно не текущее. Существующее соединение, не являющееся текущим, называется потенциальным.
Реализация может обнаружить потерю текущего соединения при выполнении любого оператора SQL. Когда это происходит, генерируется исключительное условие, смысл которого состоит в том, что результаты действий, выполненных сервером в связи с этим оператором, неизвестны SQL-агенту.
Аналогично, реализация может обнаружить потерю текущего соединения при выполнении оператора COMMIT. Исключительное условие, возбуждаемое в этом случае, обозначает, что реализация не может узнать, была ли соответствующая транзакция успешно зафиксирована, откачена или продолжает быть активной.
Пользователь может инициировать установление соединения между SQL-клиентом, связанным с SQL-агентом, и конкретным SQL-сервером путем выполнения оператора CONNECT. Иначе установление соединения между клиентом и сервером инициируется, когда вызывается процедура и отсутствует текущее соединение. Возможно определяемое в реализации соединение по умолчанию с некоторым выделенным SQL-сервером.
SQL-соединение уничтожается либо при выполнении оператора DISCONNECT, либо после последнего вызова процедуры в последнем активном модуле, либо после последнего выполнения прямого вызова оператора SQL. Механизм и правила, по которым среда SQL определяет, что вызов процедуры или прямой вызов оператора SQL являются последними, определяются в реализации.
Реализация должна поддерживать по крайней мере одно SQL-соединение и может требовать, чтобы SQL-сервер идентифицировался во время связывания, выбираемое реализацией. Если реализация допускает наличие более чем одного соединения, то SQL-агент может соединяться с более чем одним SQL-сервером и выбирать SQL-сервер путем выполнения оператора SETCONNECTION.
SQL-сессия накрывает выполнение последовательности операторов SQL, вызываемых одним пользователем через единственного SQL-агента или с помощью механизма прямого вызова. Сессия ассоциируется с соединением. SQL-сессия, ассоциированная с соединением по умолчанию, называется сессией по умолчанию. Сессия может быть текущей или потенциальной. Текущая сессия - это сессия, ассоциированная с текущим соединением (соответствующим образом определяется потенциальная сессия).
SQL-сессии соответствует модуль сессии, который отличается от любого другого модуля, одновременно существующего в среде SQL. Модуль сессии содержит глобальные подготовленные операторы SQL, относящиеся к этой сессии.
Управление сессиями
Операторы этого набора служат для установки разнообразных умолчаний, действующих в пределах текущей SQL-сессии. Как и операторы управления подключениями, операторы управления сессиями, на наш взгляд, недостаточно тщательно проработаны в стандарте SQL/92.
3.9.1. Оператор установки имени каталога по умолчанию
Оператор позволяет установить имя каталога по умолчанию для расширения неквалифицированных имен схем, используемых в динамических операторах, подготавливаемых с помощью оператора немедленного выполнения, оператора подготовки, или в прямых операторах SQL. Оператор определяется следующим синтаксическим правилом:
<set catalog statement> ::= SET CATALOG <value specification>
Пояснения:
Спецификация значения должна иметь тип символьных строк. Имя каталога по умолчанию устанавливается в соответствии с заданной строкой.
Управление транзакциями
На неформальном уровне мы кратко обсудили возможности управления транзакциями, поддерживаемые в стандарте SQL/92, в п.3.1.4. В этом разделе будут приведены синтаксические определения операторов управления транзакциями и соответствующие пояснения.
3.7.1. Оператор установки параметров транзакции
Оператор SETTRANSACTION служит для задания параметров следующей транзакции для данного SQL-агента. Оператор определяется следующими синтаксическими правилами:
<set transaction statement> ::= SET TRANSACTION <transaction mode> [ { <comma> <transaction mode> }... ] <transaction mode> ::= <isolation level> | <transaction access mode> | <diagnostics size> <isolation level> ::= ISOLATION LEVEL <level of isolation> <level of isolation> ::= READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE <transaction access mode> ::= READ ONLY | READ WRITE <diagnostics size> ::= DIAGNOSTICS SIZE <number of conditions> <number of conditions> ::= <simple value specification>
Пояснения:
Если уровень изоляции не специфицирован, то неявно полагается заданным уровень изоляции SERIALIZABLE. Если специфицирован режим доступа READWRITE, то уровень изоляции не должен быть READUNCOMMITTED. Если неспецифицирован режим доступа транзакции и указан уровень изоляции READUNCOMMITTED, то неявно полагается заданным режим доступа READONLY; в противном случае неявно полагается заданным режим доступа READWRITE. Попытка выполнения оператора SETTRANSACTION в активной транзакции приводит к возбуждению исключительной ситуации. Пусть TXN обозначает следующую транзакцию данного SQL-агента. Режим доступа TXN устанавливается в соответствии со спецификациями, заданными в операторе SETTRANSACTION. Уровень изоляции TXN устанавливается в зависимости от реализации, но таким образом, чтобы не проявлялись эффекты, которые не должны проявляться на уровне изоляции, явно или неявно задаваемом оператором SETTRANSACTION. Размер области диагностики TXN устанавливается в соответствии с параметром <numberofconditions>, если он задан; в противном случае размер области диагностики зависит от реализации, но должен быть не меньше того, который был бы выделен при явном задании числа условий равного единице.
Уровни языка
В стандарте SQL/92 специфицированы три уровня соответствия стандарту. Вводный уровень включает операторы определения схемы, язык манипулирования данными, ссылочную целостность, проверочные ограничения и раздел умолчания из SQL/89. Кроме того, вводный уровень содержит спецификации языка модулей и встроенного SQL для использования в семи различных языках программирования, а также определения подмножества SQL, предназначенного для прямого использования. Фактически, вводный уровень SQL/92 представляет собой более аккуратный вариант SQL/89.
Промежуточный уровень SQL/92 включает важные новые возможности, такие как операторы изменения схемы, динамический SQL и уровни изоляции SQL-транзакций. В промежуточном SQL содержатся также спецификации каскадного удаления при выполнении ссылочных действий, соединения объединением, операций со строками символов, операций пересечения и вычитания таблиц, простых доменов, выражения с переключателем, явного преобразования типов, средств управления диагностикой, интервальных типов данных и упрощенного варианта типа дата-время, строк переменной длины. К промежуточному уровню относится и требование наличия средства, контролирующего соответствие вводимых операторов стандарту.
Полный SQL включает возможности отложенной проверки ограничений целостности и определения именованных ограничений. Дополнительные свойства: возможность определять типы дата-время на уровне пользователя, модификации и удаления строк с возможностью ссылаться в условии на ту же таблицу, каскадные модификации при ссылочных действиях, подзапросы в проверочных ограничениях, тип данных битовых строк, временные таблицы, утверждения целостности.
На этом мы заканчиваем обсуждать понятия языка SQL/92 и переходим к более глубокому изучению его наиболее важных свойств (хотя, конечно, не всех и не так подробно, как это делается в самом стандарте).
Уровни языка SQL/
В официальном стандарте SQL/92 определяются три уровня языка: полный SQL, промежуточный SQL и вводный SQL. Основная идея состоит в том, что полный SQL является полным стандартом, промежуточный SQL - cтрогое подмножество полного SQL, а вводный SQL - строгое подмножество промежуточного SQL. Разработчики стандарта стремились позволить поэтапную реализацию с продвижением от поддержки вводного SQL через поддержку промежуточного SQL к поддержке полного SQL (как мы отмечали выше, до сих пор ни одна компания-производитель реляционных СУБД не объявила, что в ее продукте целиком поддерживается полный SQL). В п. 3.14.1 перечисляются основные свойства полного SQL, которые отсутствуют в промежуточном SQL, а в п. 3.14.2 указываются основные черты, которые в дополнение к этому отсутствуют во вводном SQL.
Язык SQL, определенный стандартом, называется "соответствующим языком SQL". Реализация называется "соответствующей реализацией SQL", если в ней обрабатывается соответствующий язык SQL в соответствии со спецификациями стандарта. Таким образом, соответствующая реализация SQL должна поддерживать соответствующий язык SQL по крайней мере на вводном уровне. Такая реализация должна также поддерживать по крайней мере один "стиль связывания" (модуль, встроенный SQL или прямой SQL), и в случае модуля или встроенного SQL, по крайней мере один из официальных основных языков (Ada, Си, COBOL, FORTRAN, MUMPS, Pascal или PL/1). Более того, в такой реализации должны быть также документированы определения для всех свойств соответствующего языка SQL, которые установлены стандартом как определяемые в реализации.
Заметим, однако, что в соответствующей реализации явно допускается:
обеспечение поддержки дополнительных свойств или опций, не специфицированных в стандарте; обеспечение опций для обработки соответствующего языка SQL несоответствующим образом; обеспечение опций для обработки не соответствующего языка SQL.
С другой стороны, от реализации, которая провозглашается соответствующей стандарту на любом уровне (за исключением, возможно, вводного уровня), требуется поддержка опции SQLFlagger для помечания элементов, которые не соответствуют указанному уровню (см.п.3.14.3).
В стандарте SQL/92 многие аспекты явно установлены как "зависимые от реализации", т.е. неопределенные; на самом деле, некоторые аспекты кажутся (возможно, неумышленно) неопределенными неявно. Даже если две реализации могут законно быть провозглашены соответствующими стандарту, это не дает абсолютной гарантии переносимости приложений.
В стандарте специально не определяется метод компиляции прикладных программ со встроенным SQL или иной способ их обработки.
3.14.1. Промежуточный SQL
В этом разделе приводятся некоторые основные различия между полным SQL и промежуточным SQL. Заметим, что мы не претендуем на полноту этого списка; цель состоит только в том, чтобы предоставить общую идею этих различий. Для абсолютно точной информации следует обращаться к самому стандарту (соответствующая информация разбросана по всему документу).
Сначала мы приведем список конструкций полного SQL, которые целиком отсутствуют в промежуточном SQL:
идентификаторы, в которых последний символ есть подчеркивание; явные имена каталогов; операторы SETCATALOG, SETSCHEMA, SETNAMES; операторы CONNECT, SETCONNECTION, DISCONNECT; все конструкции, связанные с битовыми строками; все, что служит для трансляции, преобразования и (явного) сравнения; явная спецификация точности для данных типа TIME и TIMESTAMP; значения SECOND для данных типа DATETIME или INTERVAL с более чем микросекундной точностью; функции POSITION, UPPER, LOWER; UNIONJOIN; возможность указания CORRESPONDING для операторов UNION, EXCEPT и INTERSECT; предикаты IS[NOT]TRUE, IS[NOT]FALSE, IS[NOT]UNKNOWN; условия MATCH в определениях внешнего ключа; утверждения целостности общего вида (операторы CREATE и DROPASSERTION); проверочные ограничения базовой таблицы, которые ссылаются на другие таблицы; определения действий ONUPDATE в определениях внешнего ключа; откладываемые ограничения и оператор SETCONSTRAINTS; "глобальные" и "объявляемые локальные" временные таблицы; привилегии INSERT уровня столбцов; LOCAL или CASCADED в опциях проверки (хотя CASCADED должно поддерживаться неявно); оператор ALTERDOMAIN; INSENSITIVE курсоры; спецификация "TABLE таблица" внутри табличного выражения; параметры или переменные основной программы как имена области дескрипторов SQL; все, что служит для работы с генерируемыми пользователями именами операторов; все, что служит для работы с генерируемыми пользователями именами курсоров; операторы DEALLOCATEPREPARE, DESCRIBEINPUT и возможность наличия раздела INTO в операторе EXECUTE.
Вот список дополнительных ограничений:
ссылка на таблицу не может быть табличным выражением в круглых скобках; оператор DISTINCT допускается внутри табличного выражения не более одного раза на каждом уровне вложенности; список сравниваемых значений в правой части условия IN не должен включать более сложные элементы, чем литерал, ссылка на столбец или встроенная функция без параметров; если при ссылке на агрегатную функцию указывается DISTINCT, аргумент должен представлять простую ссылку на столбец; привилегия REFERENCES не требуется для столбцов, используемых в проверочном ограничении (это на самом деле противоположность ограничению; из этого следует, что промежуточный SQL не является вполне строгим подмножеством полного SQL); наличие в определении курсора ORDERBY влечет неявно свойство FORREADONLY; операторы INSERT, UPDATE и DELETE не могут включать раздел WHERE (ни прямо в случае поисковой операции, ни через определение курсора в случае позиционной операции), ссылающийся на таблицу, которая является целью этого оператора; на некоторые таблицы информационной схемы (например, TRANSLATIONS) нельзя ссылаться.
Условие поиска
Условие поиска принимает значения true, false или unknown в зависимости от результата применения булевских операторов к составляющим его простым условиям. Синтаксис и семантика условия поиска в SQL/92 практически такие же, как в SQL/89, но в стандарте SQL/92 более четко специфицирована трехзначная логика, в которой происходит вычисление условия поиска. Синтаксис определяется следующими правилами:
<search condition> ::= <boolean term> |<search condition> OR <boolean term> <boolean term> ::= <boolean factor> |<boolean term> AND <boolean factor> <boolean factor> ::= [ NOT ] <boolean test> <boolean test> ::= <boolean primary> [ IS [ NOT ] <truth value> ] <truth value> ::= TRUE |FALSE |UNKNOWN <boolean primary> ::= <predicate> | <left paren> <search condition> <right paren>
Пояснения:
Если условие поиска не содержит булевских операторов, то результат его вычисления совпадает с результатом составляющего его простого условия, задаваемого одним из перечисленных выше предикатов. NOT(true) есть false, NOT(false) есть true и NOT(unknown) есть unknown. Правила применения других булевских операторов задаются следующими таблицами истинности:
Таблица истинности для оператора AND
true | false | unknown | |
true | true | false | unknown |
false | false | false | false |
unknown | unknown | false | unknown |
Таблица истинности для оператора OR
true | false | unknown | |
true | true | true | true |
false | true | false | unknown |
unknown | true | unknown | unknown |
Таблица истинности для оператора IS
true | false | unknown | |
true | true | true | false |
false | false | true | false |
unknown | false | false | unknown |
Важность применения стандартов SQL при разработке прикладных систем
Помимо прочего, в курсе содержатся некоторые рекомендации, направленные на то, чтобы облегчить создание мобильных прикладных информационных систем, опирающихся на использование реляционных СУБД, которые поддерживают международный стандарт языка баз данных SQL. Чтобы больше прояснить назначение и возможности предлагаемых материалов, необходимо сделать несколько предварительных замечаний.
Прежде всего под мобильностью прикладной системы здесь понимается не только возможность ее сравнительно легкого переноса на другую аппаратную платформу, но и возможность сравнительно ее легкого приспособления к использованию другой СУБД. Мы не рассматриваем здесь проблемы переносимости, связанные с особенностями операционных систем. Заметим, что в общем случае проблемы переноса будут существенно проще, если в качестве целевых аппаратных средств используются UNIX-компьютеры, причем в качестве операционной системы используются современные версии ОС UNIX, соответствующие международным стандартам (например, системы семейств SystemVRelease 4.x или BSD 4.3), а в качестве языка программирования используется хорошо стандартизованный язык (далее мы предполагаем использование языка ANSI Си). Конечно, при некоторых дополнительных ограничениях на программирование (если это позволяет специфика прикладной системы) иногда можно добиться возможности несложного переноса прикладной системы и в среду другой операционной системы.
Когда мы говорим о возможности приспособления прикладной системы к использованию различных СУБД, то, конечно, имеем в виду не произвольные СУБД, а системы, поддерживающие международный стандарт языка SQL. Другими словами, мы предполагаем прямое использование языка SQL при разработке прикладной системы, а также то, что все взаимодействия с системой БД производятся только с использованием этого языка. На самом деле, это существенно ограничивает возможный набор СУБД. Например, если в некоторой СУБД поддерживается доступ к БД на основе некоторого подмножества SQL, из этого не следует автоматически, что прикладная система может быть легко приспособлена к использованию этой СУБД. Реализация стандарта SQL вообще говоря означает, что для работы с БД не требуется привлечение никакого другого языка.
К сожалению, на практике дела обстоят не совсем так, и в разных СУБД, производители которых объявляют их соответствующими стандарту SQL, достаточно часто реализуются немного разные языки. Частично это объясняется недостатками самого стандарта, частично - историческими и конъюнктурными обстоятельствами. К сожалению, такова текущая реальность, и к ней нужно приспосабливаться.
Дополнительной трудностью при подготовке курса было то, что в настоящее время происходит переход от одного стандарта языка SQL к другому. Как уже отмечалось, первый международный стандарт языка SQL был принят в 1989 г., и подавляющее большинство доступных на рынке СУБД поддерживают именно этот стандарт. Все было бы в порядке, если бы этот стандарт был достаточно полным. Но к сожалению, он обладает по крайней мере двумя недостатками.
Во-первых, очень многие важные свойства языка стандарт устанавливает как определяемые в реализации или зависимые от реализации. Это дало большой простор к расхождениям между различными реализациями SQL. Во-вторых, некоторые практически важные аспекты языка вообще не упоминаются в стандарте SQL/89. К ним прежде всего относятся правила встраивания языка SQL в язык программирования Си и так называемый динамический SQL. Естественно, во всех коммерческих СУБД реализованы какие-то варианты этих возможностей. Как правило, они очень близки, но отсутствие стандарта не гарантирует их идентичность.
Принятый в 1992 г. новый международный стандарт языка SQL тоже не лишен недостатков, но в то же время является существенно более точным и полным, чем SQL/89. SQL/92 не только восполняет недостатки SQL/89, но содержит также много новых свойств. Но даже если ориентироваться на использование СУБД, поддерживающей только стандарт SQL/89, необходимо некоторое знакомство со стандартом SQL/92, поскольку этот стандарт во многом базировался на расширениях языка, имеющихся в различных реализациях. При создании прикладных систем обойтись без использования этих расширений иногда невозможно, а единственным способом анализа совместимости разных расширений SQL/89 является SQL/92.
Естественно, данный курс не может служить заменой текстов стандартов языка SQL и фирменной документации какой-либо конкретной СУБД. Его цель состоит в том, чтобы по возможности облегчить работу по освоению этих основных документов, отметить некоторые тонкие места, связанные с мобильностью. В некоторых случаях, когда вероятность расхождения между разными реализациями может быть особенно велика, будут предлагаться возможные решения локализации проблем.
Встроенный SQL
Поскольку в стандарте SQL/89 не специфицированы (даже в приложениях) правила встраивания SQL в язык Си, мы приведем только общие синтаксические правила встраивания, используемые для любого языка. Это поможет оценить "степень стандартности" конкретной реализации.
<embedded SQL statement> ::= <SQL prefix> { <declare cursor> |<embedded exception declaration> |<SQL statement>} [<SQL terminator>] <SQL prefix> ::= EXEC SQL <SQL terminator> ::= END EXEC ; <embedded SQL declare section> ::= <embedded SQL begin declare> (<host variable definition>...] <embedded SQL end declare> <embedded SQL begin declare> ::= <SQL prefix> BEGIN DECLARE SECTION [<SQL terminator>] <embedded SQL end declare> ::= <SQL prefix> END DECLARE SECTION [<SQL terminator>] <embedded variable name> ::= :<host identifier> <embedded exception declaration> ::= WHENEVER <condition> <exception action> <condition> ::= SQLERROR NOT FOUND <exception action> ::= CONTINUE <go to> <go to> ::= { GOTO GO TO } <target> <target> ::= :<host identifier> <unsigned integer>
Встраиваемые операторы SQL, включая объявления курсора, а также разделы объявления исключительных ситуаций и переменных основной программы, должны быть окружены скобками EXECSQL и ENDEXEC. Объявление курсора должно встречаться текстуально раньше любого оператора, ссылающегося на этот курсор. Все переменные основной программы, используемые во встроенных операторах SQL, должны быть объявлены в текстуально предшествующем этому оператору разделе объявления переменных основной программы. При этом синтаксис объявления переменной соответствует синтаксису основного языка программирования, но имени переменной предшествует двоеточие.
Механизм обработки исключительных ситуаций в SQL/89 исключительно прост (можно сказать, примитивен). Можно задавать реакцию на возникновение двух видов условий: SQLERROR - это условие появления в переменной SQLCODE после выполнения встроенного оператора отрицательного значения; NOTFOUND - условие появления в SQLCODE значения +100 (этот код означает исчерпание курсора). Реакция может состоять в выполнении безусловного перехода на метку основной программы (действие GOTO), или отсутствовать (действие CONTINUE). Срабатывает тот оператор определения реакции на исключительную ситуацию, который текстуально ближе от начала программы к данному оператору SQL.
Заметим, что во многих реализациях поддерживается два вида кодов ответа при выполнении операторов SQL (встроенных или взятых из модуля): через переменную SQLCODE с кодами ответа, представляемыми целыми числами, и через переменную SQLSTATE с кодами ответа, кодируемыми десятичными числами, представленными в текстовой форме. Имеется тенденция к переходу на использование только механизма SQLSTATE, но в стандартных реализациях должен поддерживаться механизм SQLCODE.
Пояснения:
Программа на языке Си со встроенным SQL - это единица компиляции, состоящая из текстов на языках Си и SQL. Си-текст должен соответствовать стандарту ISO/IEC 9899. SQL-текст должен состоять из одного или более встроенных операторов SQL и, возможно, из одной или более секций объявления SQL. Встроенный оператор SQL может содержаться в любом месте программы, в котором может содержаться Си-оператор внутри блока функции. Если перед Си-оператором в этом месте может присутствовать метка, то она может быть поставлена и перед встроенным оператором SQL. В Си-программе со встроенным SQL Си-идентификатор (Chostidentifier) - это любой допустимый в языке Си идентификатор переменной. Определение Си-переменной (Cvariabledefinition) определяет одну или более переменных языка Си и модифицируется следующим образом:
(a) любая необязательная спецификация CHARACTERSET удаляется из определения <CVARCHARvariable> или <Ccharactervariable>;
(b) в любом объявлении символьной переменной "VARCHAR" заменяется на "char";
(c) в любом объявлении битовой переменной "BIT" заменятся на "char";
(d) длина (length), указанная в спецификации массива при объявлении битовой переменной, заменяется на значение, равное наименьшему целому, ближайшему к L/B (см. ниже);
(e) длина, указанная в спецификации массива при объявлении символьной переменной (постоянной или переменной длины), содержащего спецификацию CHARACTERSET, заменяется на длину в октетах соответствующего Си-идентификатора.
Последовательность представления символа (characterrepresentation), содержащаяся в начальном Си-значении, присваиваемом Си-переменной, должна быть допустимой Си-спецификацией начального значения. За исключением случаев спецификации массива для символьных и битовых строк, объявление Си-переменной должно ссылаться на скалярный тип. При объявлении Си-переменной в ключевых словах "VARCHAR", "CHARACTER", "SET", "IS", "BIT" и "VARYING" может использоваться произвольная комбинация малых и заглавных букв. Каждый Си-идентификатор, указанный в определении символьной Си-переменной постоянной длины, описывает символьную строку постоянной длины; эта длина задается значением <length> в соответствующей спецификации массива; значение переменной заканчивается пустым символом, позиция которого включается в заданную длину; эквивалентный тип данных SQL есть CHARACTER с длиной на единицу меньше <length> и со значением, не включающим пустой символ; значение <length> должно быть больше единицы 1. Каждый Си-идентификатор, указанный в определении строчной Си-переменной переменной длины, описывает символьную строку переменной длины; максимальная длина задается значением <length> в соответствующей спецификации массива; значение переменной заканчивается пустым символом, позиция которого включается в заданную максимальную длину; эквивалентный тип данных SQL есть CHARACTERVARYING с длиной на единицу меньше <length> и со значением, не включающим пустой символ; значение <length> должно быть больше единицы 1. Каждый Си-идентификатор, указанный в определении битовой Си-переменной, описывает битовую строку постоянной длины; пусть B - длина в битах значения типа языка Си "char", а L - значение <length> в соответствующей спецификации массива, тогда длина эквивалентной символьной Си-переменной есть наименьшее целое, не меньшее значения L/B; эквивалентный тип SQL есть BIT с длиной L. Тип данных "long" Си-переменной эквивалентен типу INTEGER языка SQL. Тип данных "short" Си-переменной эквивалентен типу SMALLINT языка SQL. Тип данных "float" Си-переменной эквивалентен типу REAL языка SQL. Тип данных "double" Си-переменной эквивалентен типу DOUBLEPRECISION языка SQL. Если Си-программа со встроенным SQL не содержит определения Си-переменной SQLSTATE в виде символьной переменной постоянного размера с указанием длины массива, равной 6, или в виде переменной типа "long", то предполагается наличие такой переменной с типом "long".
Одним из основных преимуществ реляционного
Одним из основных преимуществ реляционного подхода к организации баз данных (БД) является то, что пользователи реляционных БД получают возможность эффективной работы в терминах простых и наглядных понятий таблиц, их строк и столбцов без потребности знания реальной организации данных во внешней памяти. Реляционная модель данных, содержащая набор четких предписаний к базовой организации любой реляционной системы управления базами данных (СУБД), позволяет пользователям работать в ненавигационной манере, т.е. для выборки информации из БД человек должен всего лишь указать список интересующих его таблиц и те условия, которым должны удовлетворять выбираемые данные. СУБД скрывает от пользователя выполняемые ей последовательные просмотры таблиц, выполняя их наиболее эффективным образом. Основная особенность реляционных систем состоит в том, что результатом выполнения любого запроса к таблицам БД является также таблица, которую можно сохранить в БД и/или по отношению к которой можно выполнять новые запросы.
Очень важным требованием к реляционным СУБД является наличие мощного и в тоже время простого языка, позволяющего выполнять все необходимые пользователям операции. В последние годы таким повсеместно принятым языком стал язык реляционных БД SQL (StructuredQueryLanguage), введению в который посвящен этот курс.
До появления SQL в СУБД (независимо от того, на какой модели они основывались) приходилось поддерживать по крайней мере три языка, которые обычно имели мало общего: язык определения данных (ЯОД), служащий для спецификации структур БД (обычно общую структуру БД называют схемой БД); язык манипулирования данными (ЯМД), позволяющий создавать прикладные программы, взаимодействующие с БД; и язык администрирования БД (ЯАБД), с помощью которого можно было выполнять служебные действия (например, изменять структуру БД или производить ее настройку с целью повышения эффективности). Кроме того, если требовалось предоставить пользователям СУБД интерактивный доступ к БД, приходилось вводить еще один язык, операторы которого выполняются в диалоговом режиме. Язык SQL позволяет решать все эти задачи.
Следует отметить, что к достоинствам языка SQL относится наличие международных стандартов. Первый международный стандарт был принят в 1989 г., и соответствующая версия языка называется SQL-89. Этот стандарт поддерживается практически во всех современных коммерческих реляционных СУБД (например, в Informix, Sybase, Ingres и т.д.). Второй международный стандарт был принят в 1992 г. - SQL-92. Этот вариант языка существенно шире, чем SQL-89. К настоящему времени основные компании-производители СУБД только частично поддерживают этот стандарт. Тем не менее, он является исключительно важным документом как для реально практикующих разработчиков программного обеспечения, так и для специалистов, связанных с подбором аппаратно-программных средств.
Вводный SQL
В этом разделе мы перечисляем некоторые дополнительные свойства полного SQL, которые отсутствуют во вводном SQL в дополнение к тем, которых нет в промежуточном SQL:
идентификаторы длиннее, чем из 18 символов; малые буквы в идентификаторах; оператор SETSESSIONAUTHORIZATION; символьные строки переменного размера; определяемые в реализации наборы символов, включая строки национальных символов; все конструкции, связанные с datetime и interval; все, что связано с доменами; явные именованные ограничения; константы CURRENT_USER, SESSION_USER, SYSTEM_USER (однако USER поддерживается); CHARACTER_LENGHT, OCTET_LENGHT; функции SUBSTRING, TRIM, EXTRACT; операция конкатенации символьных строк; выражения с переключателем; оператор явного преобразования типов (CAST); раздел DEFAULT в операторах INSERT и UPDATE; явный оператор JOIN; операции EXCEPT и INTERSECT; элементы выборки в форме "R.*"; условие UNIQUE; оператор DROPSCHEMA; оператор DROPTABLE; задание действия ONDELETE в определениях внешнего ключа; оператор ALTERTABLE; оператор DROPVIEW; оператор REVOKE; оператор SETTRANSACTION; динамический SQL; прокручиваемые курсоры; раздел FORUPDATE в определении курсора; преобразования между точными и приблизительными численными значениями при присваивании; информационная схема; оператор GETDIAGNOSTICS.
Вот список дополнительных ограничений:
конструктор строки должен включать в точности один компонент, за исключением специального случая, когда конструктор строки является компонентом конструктора таблицы (в этом случае он должен быть единственным таким компонентом), и случая, когда конструктор строки используется для определения источника в операторе INSERT; табличное выражение в круглых скобках не может включать UNION; если в разделе FROM выражения выборки присутствует ссылка на представление, определение которого включает разделы GROUPBY или HAVING, то
(а) в этом разделе FROM не должны упоминаться другие таблицы;
(b) это выражение выборки не должно включать разделы WHERE, GROUPBY и HAVING;
(c) раздел SELECT этого выражения выборки не должен включать ссылок на какие-либо агрегатные функции;
одиночный оператор SELECT не может включать разделы GROUPBY и ORDERBY и не может ссылаться на представление, в определении которого использованы разделы GROUPBY и ORDERBY; если какое-либо значение в условии сравнения представляет собой выражение выборки в круглых скобках, это выражение выборки не может содержать разделы GROUPBY и HAVING и не должно ссылаться на представление, в определении которого использованы разделы GROUPBY и ORDERBY; для UNION типы данных соответствующих столбцов должны быть в точности одними и теми же (и NOTNULL должно прилагаться ко всем или ни к кому); в условии LIKE первый операнд должен быть ссылкой на столбец, и "pattern" и "escape" должны быть литералами, параметрами или переменными основной программы; в проверке на неопределенное значение операнд должен быть ссылкой на столбец; оператор CREATESCHEMA должен включать раздел AUTHIRIZATION и не должен включать имени схемы; определение модуля должно включать раздел AUTHIRIZATION и не должен включать раздела SCHEMA; каждый столбец, упомянутый в определении возможного ключа, должен быть явно определен как NOTNULL; ключевое слово TABLE не должно появляться в операторе GRANT; операторы COMMIT и ROLLBACK должны включать паразитное слово WORK.
Выражение запросов
Выражение запросов - это выражение, строящееся по указанным синтаксическим правилам на основе спецификаций запросов. Единственной операцией, которую разрешается использовать в выражениях запросов, является операция UNION (объединение таблиц) с возможной разновидностью UNIONALL. К таблицам-операндам выражения запросов предъявляется то требование, что все они должны содержать одно и то же число столбцов, и соответствующие столбцы всех операндов должны быть одного и того же типа. Выражение запросов вычисляется слева направо с учетом скобок. При выполнении операции UNION производится обычное теоретико-множественное объединение операндов, т.е. из результирующей таблицы удаляются дубликаты. При выполнении операции UNIONALL образуется результирующая таблица, в которой могут содержаться строки-дубликаты.
Выражения над строками
Выражения над строками - это выражения, значениями которых являются символьные или битовые строки. Соответствующие конструкции определяются следующим синтаксисом:
<string value expression> ::= <character value expression> <bit value expression> <character value expression> ::= <concatenation> <character factor> <concatenation> ::= <character value expression> |<concatenation operator> <character factor> <character factor> ::= <character primary> [ <collate clause> ] <character primary> ::= <value expression primary> <string value function> <bit value expression> ::= <bit concatenation> <bit factor> <bit concatenation> ::= <bit value expression> <concatenation operator> <bit factor> <bit factor> ::= <bit primary> <bit primary> ::= <value expression primary> <string value function>
Если не вдаваться в тонкости, смысл выражений над строками понятен из описания синтаксиса: единственная применимая для построения выражений операция - конкатенация, производящая "склейку" строк-операндов. Более важно то, что первичной составляющей выражения над строками может быть как первичное выражение, вычисляющее значение (см. выше), так и вызов функций, возвращающих строчные значения. Репертуар и синтаксис вызова таких функций определяются следующим синтаксисом:
<string value function> ::= <character value function> <bit value function> <character value function> ::= <character substring function> <fold> <form-of-use conversion> <character translation> <trim function> <character substring function> ::= SUBSTRING <left paren> <character value expression> FROM <start position> [ FOR <string length> ] <right paren> <fold> ::= { UPPER LOWER } <left paren> <character value expression> <right paren> <form-of-use conversion> ::= CONVERT <left paren> <character value expression> USING <form-of-use conversion name> <right paren> <character translation> ::= TRANSLATE <left paren> <character value expression> USING <translation name> <right paren> <trim function> ::= TRIM <left paren> <trim operands> <right paren> <trim operands> ::= [ [ <trim specification> ] [ <trim character> ] FROM ] <trim source> <trim source> ::= <character value expression> <trim specification> ::= LEADING TRAILING BOTH <trim character> ::= <character value expression> <bit value function> ::= <bit substring function> <bit substring function> ::= SUBSTRING <left paren> <bit value expression> FROM <start position> [ FOR <string length> ] <right paren> <start position> ::= <numeric value expression> <string length> ::= <numeric value expression>
Пояснения: Основные полезные функции - выделение подстроки (SUBSTRING) и замена малых букв на заглавные и наоборот (UPPER и LOWER) - мы упоминали при рассмотрении строчных типов. Как видно из описания синтаксиса функций, возвращающих строчные значения, для символьных строк имеются еще три функции: CONVERT, TRANSLATE и TRIM. По смыслу они все очень просты. Функция CONVERT меняет кодировку символов в заданной строке, причем репертуар символов не меняется. Способ задания правил перекодировки определяется в реализации. Функция TRANSLATE, наоборот, в соответствии с правилами трансляции "переводит" текстовую строку на другой язык (используя набор символов целевого алфавита). Кодировка не меняется. Функция TRIM "отсекает" последовательности указанного символа в начале, в конце или в конце и начале заданной строки.
Выражения над временем и датами
К выражениям над временем и датой мы относим выражения, вырабатывающие значения типа дата-время и интервал. Выражения дата-время определяются следующими синтаксическими правилами: >
<datetime value expression> ::= <datetime term> |<interval value expression> <plus sign> <datetime term> |<datetime value expression> <plus sign> <interval term> <datetime value expression> <minus sign> <interval term> <datetime term> ::= <datetime factor> <datetime factor> ::= <datetime primary> [ <time zone> ] <datetime primary> ::= <value expression primary> |<datetime value function> <time zone> ::= AT <time zone specifier> <time zone specifier> ::= LOCAL TIME ZONE <interval value expression>
Пояснения: Как видно из описания синтаксиса, сами выражения строятся очень просто - на основе обычных арифметических операций. Снова более интересны первичные составляющие- вызовы функций, возвращающих значение дата-время. Эти вызовы определяются следующим синтаксисом:
<datetime value function> ::= <current date value function> |<current time value function> |<current timestamp value function> <current date value function> ::= CURRENT_DATE <current time value function> ::= CURRENT_TIME [ <left paren> <time precision> <right paren> ] <current timestamp value function> ::= CURRENT_TIMESTAMP [ <left paren> <timestamp precision> <right paren> ]
Видимо, приведенные синтаксические правила не нуждаются в комментариях: можно получить текущую дату, а также текущее время с желаемой точностью.
Синтаксис выражений со значениями типа интервал определяется следующими правилами:
<interval value expression> ::= <interval term> |<interval value expression 1> <plus sign> <interval term 1> |<interval value expression 1> <minus sign> <interval term 1> |<left paren> <datetime value expression> <minus sign> |<datetime term> <right paren> <interval qualifier> <interval term> ::= & lt;interval factor> |<interval term 2> <asterisk> <factor> |<interval term 2> <solidus> <factor> |<term> <asterisk> <interval factor> <interval factor> ::= [ <sign> ] <interval primary> <interval primary> ::= <value expression primary> [ <interval qualifier> ] <interval value expression 1> ::= <interval value expression> <interval term 1> ::= <interval term> <interval term 2> ::= <interval term>
Как видно из приведенных правил, выражения со значениями типа интервал устроены очень просто; почти вся содержательная информация была приведена при обсуждении соответствующего типа данных. Стоит только заметить, что квалификатор интервала указывается для того, чтобы явно специфицировать единицу измерения интервала.
Выражения с переключателем
Выражения с переключателем в некотором смысле ортогональны рассмотренным выше видам выражений, поскольку разные выражения с переключателем могут вырабатывать значения разных типов. Поскольку мы еще вообще не рассматривали этот вид выражений, обсудим их более подробно. Как обычно, начнем с синтаксиса:
<case expression> ::= <case abbreviation> |<case specification> <case abbreviation> ::= NULLIF <left paren> <value expression> <comma> <value expression> <right paren> |COALESCE <left paren> <value expression> |<comma> <value expression> }... <right paren> <case specification> ::= <simple case> <searched case> <simple case> ::= CASE <case operand> imple when clause>... <else clause> ] END <searched case> ::= CASE earched when clause>... <else clause> ] END <simple when clause> ::= WHEN <when operand> THEN <result> <searched when clause> ::= WHEN <search condition> THEN <result> <else clause> ::= ELSE <result> <case operand> ::= <value expression> <when operand> ::= <value expression> <result> ::= <result expression> NULL <result expression> ::= <value expression>
Пояснения:
NULLIF (V1, V2) эквивалентно следующей спецификации выражения с переключателем: CASEWHENV1=V2 THENNULLELSEV1 END. COALESCE (V1, V2) эквивалентно следующему: CASEWHENV1 ISNOTNULLTHENV1 ELSEV2 END. COALESCE (V1, V2, . . . ,n) для n >= 3 эквивалентно CASEWHENV1 ISNOTNULLTHENV1 ELSECOALESCE (V2, . . . ,n) END. Если используется простая спецификация выражения (simplecase), то тип данных операнда переключателя (CO - CaseOperand) должен быть совместим с типов данных операнда каждого варианта (WO - WhenOperand); спецификация эквивалентна спецификации поискового переключателя (searchedcase), в котором каждое условие поиска имеет вид "CO=WO". По крайней мере в одном из вариантов должно быть специфицировано результирующее выражение. Если отсутствует раздел ELSE, то по умолчанию полагается ELSENULL. Тип данных результата определяется как минимальный накрывающий тип для всех возможных результатов. Например, если все результирующие значения имеют тип данных строк переменной длины с максимальными длинами m1, m2, ..., mn, то типом данных результата будет тип данных строк переменной длины с максимальной длиной, равной max (m1, m2, ..., mn)).
Выражения запросов
Хотя на вид (на примерах) выражения запросов SQL/92 очень напоминают соответствующие конструкции SQL/89, на самом деле они гораздо мощнее. Для того, чтобы можно было лучше понять существо выражений запросов SQL/92, мы начнем с рассмотрения вспомогательных конструкций. Заметим, что синтаксические определения часто носят рекурсивный характер, но это "хорошая" рекурсия, потому что в конечном счете любой запрос опирается на именованные базовые или представляемые таблицы.
Итак, сначала введем некоторые начальные понятия, связанные с запросами. Наверное, наиболее важным из таких понятий в SQL/92 является ссылка на таблицу (tablereference), которая может встречаться во всех конструкциях, адресуемых к таблицам. Ссылка на таблицу определяется следующими синтаксическими правилами:
<table reference> ::= <table name> [ [ AS ] <correlation name> [ <left paren> <derived column list> <right paren> ] ] |<derived table> [ AS ] <correlation name> [ <left paren> <derived column list> <right paren> ] |<joined table> <derived table> ::= <table subquery> <derived column list> ::= <column name list> <column name list> ::= <column name> [ { <comma> <column name> }... ]
Пояснения: Как видно, в отличие от SQL/89, где ссылка на таблицу всегда задается ее именем, в SQL/92 возможны еще два варианта: задать таблицу запросом в традиционной форме или выражением с использованием операторов соединения. Как выглядят эти два варианта, мы увидим в следующих подразделах.
Еще два понятия, более мелких, но необходимых, - конструктор значения-строки и конструктор значения-таблицы. Конструктор значения строки строит из скалярных значений упорядоченный набор, представляющий строку (возможно и использование подзапроса):
<row value constructor> ::= <row value constructor element> |<left paren> <row value constructor list> <right paren> |<row subquery> <row value constructor list> ::= <row value constructor element> [ { <comma> <row value constructor element> }... ] <row value constructor element> ::= <value expression> |<null specification> |<default specification> <null specification> ::= NULL <default specification> ::= DEFAULT
Заметим, что значение элемента по умолчанию можно использовать только в том случае, когда конструктор значения-строки используется в операторе INSERT (тогда этим значением будет значение по умолчанию соответствующего столбца).
Конструктор значения-таблицы производит таблицу на основе заданного набора конструкторов значений-строк:
<table value constructor> ::= VALUES <table value constructor list> <table value constructor list> ::= <row value constructor> [ { <comma> <row value constructor> }... ]
Пояснение: Конечно, для того, чтобы корректно построить таблицу, требуется, чтобы строки, производимые всеми конструкторами строк, были одной и той же степени и чтобы типы (или домены) соответствующих столбцов совпадали.
В заключение курса приведем краткую
В заключение курса приведем краткую сводку новых возможностей, ожидаемых в новом стандарте SQL/3, работа над которым все еще продолжается.
В стандарте SQL/92 по сравнению со стандартом SQL/89 язык был расширен главным образом количественно, хотя даже этих количественных расширений оказалось достаточно для того, чтобы стандарт SQL/92 не удалось полностью реализовать до сих пор в большинстве коммерческих СУБД. Поскольку SQL/92 не удовлетворял значительной части претензий, исторически предъявляемых к языку SQL, был сформирован новый комитет, который должен выработать стандарт языка с качественными расширениями. Язык SQL/3 пока не сформирован полностью, многие аспекты продолжают обсуждаться. Поэтому к приводимой здесь сводке возможностей нужно относиться как к сугубо предварительной.
Дополнительные возможности операторов выборки
7.1.Выдать список фамилий и идентификаторов заданий служащих, выполняющий задания со значениями идентификаторов 10 и 11. Список упорядочить по возрастанию значений идентификаторов, а для каждого идентификатора - по убыванию значений фамилий в лексикографическом порядке (из таблицы employee).
7.2.Выдать список названий калифорнийских магазинов и их общего объема продаж, упорядоченный по значению общего объема продаж (из таблицы sales).
7.3.Выдать аббревиатуру штатов, в которых проживают авторы, а также тех, в которых находятся книжные магазины (использовать таблицы authors и stores).
7.4.Для заданий со значениями идентификатора 9 и 10 выдать значения уровни оплаты сотрудников, выполняющих такие задания, а также минимальный и максимальный уровни оплаты; результат упорядочить по значению уровня оплаты (использовать таблицы employee и jobs).
7.5.Выдать аббревиатуру штатов, в которых проживают авторы книги категории 'popular_comp', а также тех штатов, в которых находятся книжные магазины, продавшие эти книги (использовать таблицы authors, titleauthor, sales и stores).
Изменение таблицы базы данных
8.1.Для целей этого занятия каждый слушатель должен создать новую таблицу с именем new_libn, где n - номер рабочей станции. Таблицы должна содержать следующие поля: title_id (тип tid), title (тип varchar(80), и pub_id (тип char(4)). Первичным ключом объявите столбец title_id. Внешний ключ - столбец pub_id ссылается на первичный ключ pub_id таблицы publishers; кроме того, столбец title_id также является внешним ключом, ссылающимся на первичный ключ title_id таблицы titles.
8.2.Вставьте в таблицу соответствующие данные из первых двух строк таблицы titles, проверьте правильность выполнения операций.
8.3.Теперь пополним свои библиотеки популярной компьютерной литературой: добавьте к таблице new_libn строки из таблицы titles, для которых значением столбца type является 'popular_comp'. Проверьте, что операция выполнилась правильно.
8.4.Прежде чем мы начнем ломать содержимое ваших таблиц, давайте воспользуемся их текущим содержимым: выдать имена и фамилии авторов и названия книг вашей библиотеки.
8.5.Удалить из таблицы строку со значением поля title_id равным 'BU1111'; проверить, что удалилась нужная строка.
8.6.Удалить из таблицы new_libn описания книг, относящихся к категории 'business'. Проверить, что удалилась единственная строка со значением столбца title_id равным 'BU1032'.
8.7.Изменить название книги, написанной автором по фамилии Carson, на 'ThisisthebookbyMrCarson'; проверить, что нужная строка изменилась.
8.8.Проверить, что не будут выполняться следующие операции: для строки таблицы со значением столбца title_id равным 'PC8888' поменять значение этого столбца на 'PC1035'; для строки таблицы со значением столбца title_id равным 'PC8888' поменять значение этого столбца на 'ZZ8888'; для строки таблицы со значением столбца title_id равным 'PC8888' поменять значение поля pub_id на '1888'. Почему эти операции не выполняются?
|
Операторы выборки из одной таблицы со вложенными подзапросами
4.1.Выдать имена и фамилии авторов таких, что имеются служащие с такими же именами (из таблицы authors с использованием таблицы employee).
4.2.Выдать имена и фамилии авторов, проживающих в том же штате, что и автор с фамилией White, и имеющих идентификаторы автора, которые начинаются с символа '2' (из таблицы authors).
4.3.Выдать фамилии служащих, выполняющих задания со значениями идентификаторов от 1 до 5, таких, что существуют другие служащие, выполняющие то же задание (из таблицы employee).
4.4.Выдать аббревиатуру названий штатов, в которых проживает только по одному автору (из таблицы authors).
4.5.Выдать фамилии служащих, выполняющих задания с нижним уровнем оплаты большим 175 и таким, что существуют задания с таким же верхнем уровнем оплаты (из таблицы employee с использованием таблицы jobs).
4.6.Выдать общий объем продаж, произведенных магазинами, находящимися в штатах, в которых проживает хотя бы один автор (из таблицы sales с использованием таблиц stores и authors).
4.7.Выдать названия магазинов с общим объемом продаж большим, чем объем продаж магазинов, расположенных в штате Oregon (OR) (из таблицы stores с использованием таблиц sales и stores).
Простые операторы выборки из базы данных
3.1.Получить имена и номера телефонов авторов по фамилии Ringer (из таблицы authors)
3.2.Получить идентификаторы заданий, описание которых начинается со слова 'Chief' (из таблицы jobs)
3.3.Получить идентификаторы служащих, имя которых начинается на букву 'P', выполняющих задания со значением идентификатора, большим 12 (из таблицы employee).
3.4.Получить фамилии и имена авторов, не проживающих в Калифорнии, zip-код которых начинается на '4', а также тех, идентификатор автора которых начинается на '998' (из таблицы authors).
3.5.Получить описание заданий, нижний уровень оплаты которых равен верхнему уровню оплаты (из таблицы jobs).
3.6.Получить число различных заданий, минимальное значение минимального уровня оплаты, максимальное значение максимального уровня оплаты и среднее значение суммы минимального и максимального уровне оплаты для заданий с идентификаторами в диапазоне от 8 до 13 (из таблицы jobs).
3.7.Выдать список штатов, в которых проживают авторы; аббревиатура каждого штата должна участвовать в списке только один раз (из таблицы authors).
Работа с MicrosoftSQLServer с использованием языка SQL в интерактивном режиме
Мы начнем с описания базы данных pubs, которая будет использоваться на практических занятиях. Эта база данных имитирует информационное хранилище издательской компании и состоит из 11 таблиц: authors (авторы), discounts (скидки), employee (служащие), jobs (задания), pub_info (информация об издательствах), publishers (издательства), roysched (авторские гонорары), sales (продажи), stores (магазины), titleauthor (название-автор), titles (названия).
Таблицы определены следующим образом:
Таблица authors
Имя столбца | Тип данных | Возможность содержать NULL | Значение по умолчанию |
au_id | id | нет | нет |
au_lname | varchar(40) | нет | нет |
au_fname | varchar(20) | нет | нет |
phone | char(12) | нет | 'UNKNOWN' |
address | varchar(40) | да | нет |
city | varchar(20) | да | нет |
state | char(2) | да | нет |
zip | char(5) | да | нет |
contract | bit | нет | нет |
Первичным ключом объявлен столбец au_id. Определены два ограничения целостности на столбцах au_id (au_idLIKE '[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]') и zip (zipLIKE '[0?9][0-9][0-9][0-9][0-9]').
К типу данных id нужно относиться как к типу символьных строк (CHAR(9)). Тип varchar - аналог CHARACTERVARYINGSQL/92. Тип bit - нестандартный, и мы не будем использовать столбец contract в наших примерах.
Таблица discounts
Имя столбца | Тип данных | Возможность содержать NULL | Значение по умолчанию |
discounttype | varchar(40) | нет | нет |
stor_id | char(4) | да | нет |
lowqty | smallint | да | нет |
highqty | smallint | да | нет |
discount | float | нет | нет |
Эта таблица представляет интерес тем, что в ней отсутствует первичный ключ (если внимательно посмотреть на требования стандарта SQL, то можно увидеть, что такая ситуация допускается, хотя на практике встречается очень редко). Для таблицы определено ссылочное ограничение: столбец stor_id ссылается на первичный ключ stor_id таблицы stores.
Таблица employee
Имя столбца | Тип данных | Возможность содержать NULL | Значение по умолчанию |
emp_id | empid | нет | нет |
fname | varchar(20) | нет | нет |
minit | char(1) | да | нет |
lname | varchar(30) | нет | нет |
job_id | smallint | нет | 1 |
job_lvl | tinyint | нет | 10 |
pub_id | char(4) | нет | '9952' |
hire_date | datetime | нет | GETDATE() |
Первичным ключом объявлен столбец emp_id. Имеются два ссылочных ограничения: столбец job_id ссылается на первичный ключ job_id таблицы jobs, столбец pub_id ссылается на первичный ключ pub_id таблицы publishers. Определено ограничение для столбца emp_id: (emp_idLIKE '[A-Z][A-Z][A-Z][1-9][0-9][0-9][0-9][0-9][FM]' ORemp_idLIKE '[A-Z]-[A-Z][1-9][0-9][0-9][0-9][0-9][FM]'). Тем самым, видно, что тип emp_id на самом деле есть varchar(9). Тип данных tinyint является нестандартным, и мы не будем использовать столбец job_lvl. Функция GETDATE() является аналогом стандартной функции CURRENT_DATE, т.е. значением по умолчанию столбца hire_date является текущая дата.
Таблица jobs
Имя столбца | Тип данных | Возможность содержать NULL | Значение по умолчанию |
job_id | smallint | нет | IDENTITY(1,1) |
job_desc | varchar(50) | нет | 'NewPosition - titlenotformalizedyet' |
min_lvl | tinyint | нет | нет |
max_lvl | tinyint | нет | нет |
Первичный ключ - job_id. Значение по умолчанию этого столбца вырабатывается нестандартной функцией IDENTITY, генерирующей уникальные целые значения.
Таблица pub_info
Имя столбца | Тип данных | Возможность содержать NULL | Значение по умолчанию |
pub_id | char(4) | нет | нет |
logo | image | да | нет |
pr_info | text | да | нет |
Первичный ключ таблицы - pub_id. Этот же столбец является и внешним ключом и ссылается на первичный ключ pub_id таблицы publishers. Типы данных image и text являются нестандартными, и мы не будем использовать столбцы logo и pr_info.
Таблица publishers
Имя столбца | Тип данных | Возможность содержать NULL | Значение по умолчанию |
pub_id | char(4) | нет | нет |
pub_name | archar(40) | да | нет |
city | varchar(20) | да | нет |
state | char(2) | да | нет |
country | varchar(30) | да | 'USA' |
Первичный ключ - pub_id. Для этого столбца, кроме того, определено следующее ограничение: (pub_id = '1622' ORpub_id = '0877' ORpub_id = '0736' ORpub_id = '1389' ORpub_idLIKE '99[0-9][0-0]').
Таблица roysched
Имя столбца | Тип данных | Возможность содержать NULL | Значение по умолчанию |
title_id | tid | нет | нет |
lorange | int | да | нет |
hirange | int | да | нет |
royalty | int | да | нет |
В этой таблице отсутствует первичный ключ. Объявлено одно ссылочное ограничение: столбец title_id ссылается на первичный ключ title_id таблицы titles. Тип tid - синоним char(6), тип int - синоним стандартного типа INTEGER.
Таблица sales
Имя столбца | Тип данных | Возможность содержать NULL | Значение по умолчанию |
stor_id | char(4) | нет | нет |
ord_num | varchar(20) | нет | нет |
ord_date | datetime | нет | нет |
qty | smallint | нет | нет |
payterms | varchar(12) | нет | нет |
title_id | tid | нет | нет |
Первичный ключ таблицы образует комбинация полей stor_id, ord_num, title_id. Определены два внешних ключа: столбец stor_id ссылается на первичный ключ stor_id таблицы stores, а столбец title_id - на первичный ключ title_id таблицы titles.
Таблица stores
Имя столбца | Тип данных | Возможность содержать NULL | Значение по умолчанию |
stor_id | char(4) | нет | нет |
stor_name | varchar(40) | да | нет |
stor_address | varchar(40) | да | нет |
city | varchar(20) | да | нет |
state | char(2) | да | нет |
zip | char(5) | да | нет |
Первичным ключом является столбец stor_id.
Таблица titleauthor
Имя столбца | Тип данных | Возможность содержать NULL | Значение по умолчанию |
au_id | id | нет | нет |
title_id | tid | нет | нет |
au_ord | tinyint | да | нет |
royaltyper | int | да | нет |
Первичный ключ составляет комбинация столбцов au_id, title_id.
Таблица titles
Имя столбца | Тип данных | Возможность содержать NULL | Значение по умолчанию |
title_id | tid | нет | нет |
title | varchar(80) | нет | нет |
type | char(12) | нет | 'UNDECIDED' |
pub_id | char(4) | да | нет |
price | money | да | нет |
advance | money | да | нет |
royalty | int | да | нет |
ytd_sales | int | да | нет |
notes | varchar(200) | да | нет |
pubdate | datetime | нет | GETDATE() |
Первичный ключ - title_id. Внешний ключ pub_id ссылается на первичный ключ pub_id таблицы publishers. Тип money - нестандартный, и мы не будем использовать столбцы price и advance.
Содержимое базы данных можно посмотреть в приложении B руководства по TransactSQL, входящего в оперативно доступную документацию по MicrosoftSQLServer, а также в прилагаемом тексте.
Слушатели будут работать с базой данных pubs с рабочих станций. Для каждого слушателя будет использоваться одно и то же входное имя (admin) и один и тот же пароль (adminnt). Следует учитывать, что пользователь admin обладает привилегиями администратора WindowsNT. Поэтому, чтобы не разрушить систему, слушателям не следует выполнять какие-либо действия, не предусмотренные программой занятий, без согласования с преподавателями.
Для доступа к базе данных будет использоваться программа MicrosoftQuery, позволяющая, в частности, через средства ODBC работать с MSSQLServer. Правила вызова MSQuery с обеспечением общего доступа к базе данных pubs будут продемонстрированы преподавателем.
Запросы к одной таблице с использованием агрегатных функций и раздела GROUPBY
5.1.Выдать аббревиатуру названий штатов, в которых проживает хотя бы один автор (из таблицы authors).
5.2.Выдать идентификаторы магазинов, число их заказов и общий объем продаж (из таблицы sales).
5.3.Для каждого задания со значением идентификатора, большим 5, выдать значение идентификатора задания и число служащих, выполняющих это задание (из таблицы employee).
5.4.Для магазинов, выполнивших заказ в объеме, большем 20, выдать объем заказа, число магазинов, выполняших заказ одного и того же объема, и число заказов одного и того же объема (из таблицы sales).
5.5.Выдать идентификаторы магазинов и суммарный объем продаж для магазинов, выполнивших хотя бы один заказ объемом больше 25 (из таблицы sales).
5.6.Выдать аббревиатуру названий штатов и число магазинов в каждом штате для штатов, в которых живет хотя бы один автор и располагается хотя бы один магазин (из таблицы stores с использованием таблицы authors).
5.7.Для магазинов, находящихся в Калифорнии, выдать идентификатор магазина, число заказов и общий объем продаж магазина с наибольшим общим объемом продаж (из таблицы sales с использованием таблицы stores).
Запросы с соединениями
6.1.Выдать идентификаторы и названия магазинов, а также номера заказов для магазинов, находящихся в штате Oregon ('OR') (использовать таблицы sales и stores).
6.2.Выдать идентификаторы и названия магазинов, находящихся в штате California ('CA') (использовать таблицы sales и stores).
6.3.Выдать наименования заданий и число служащих, выполняющих каждое задание, для служащих, фамилии которых начинаются на букву от 'A' до 'M', и для заданий, значения идентификаторов которых содержатся в диапазоне от 5 до 11 (из таблиц employee и jobs).
6.4.Выдать названия и адреса магазинов с минимальным объемом заказа большим 10 и максимальным объемом заказа меньшим 50 (использовать таблицы sales и stores).
6.5.Выдать имена и фамилии авторов книг, отнесенных к категории 'business', а также идентификаторы книг (использовать таблицы authors, tittleauthor и titles).
6.6.Выдать имена и фамилии авторов книг, относящихся к категории 'business' и написанных в соавторстве, а также идентификаторы этих книг (использовать таблицы authors, tittleauthor и titles).
6.7.Выдать имена и фамилии авторов, прошивающих не в Калифорнии, книги которых заказываются в магазинах, расположенных не в том штате, где проживает автор, а также получить названия обоих штатов (использовать таблицы authors, stores, titleauthor).
Заполнение созданной таблицы
Занесите в таблицу две строки, не нарушая установленных ограничений целостности. Попробуйте занести строки, содержимое которых противоречит определенным ограничениям. Проверьте, что занесенные строки действительно содержатся в таблице.