Книга
Книга
Введение
Данная книга посвящена Структурированному языку запросов — SQL, который является стандартным языком реляционных систем управления базами данных (СУБД). Международная организация стандартизации (ISO) и Американский национальный институт стандартов (ANSI) уже более двадцати лет ведут работы по поддержанию стандарта этого языка, и практически все современные реляционные СУБД используют его в качестве языка интерфейса пользователей с базами данных.
Таким образом, знание SQL открывает путь к успешному освоению и использованию практически любой современной реляционной СУБД..
По SQL имеется множество различных изданий. В этой книге делается попытка наиболее полно и доходчиво осветить возможности языка с точки зрения прежде всего конечного пользователя. Язык излагается через его основные синтаксические конструкции и описание их семантики, но главное — это многочисленные примеры, которые базируются на сопровождающей книгу учебной базе данных и обеспечивают его практическое освоение.
В качестве основы при изложении языка был выбран стандарт ISO-ANSI 2003 г. Так как многие производители СУБД расширяют возможности стандарта, мы использовали некоторые из расширений языка, предоставляемые СУБД Oracle 10. В этой же СУБД проверены все приводимые в книге примеры.
Следует отметить, что детально проанализировать новый стандарт SQL в одной книге не представляется возможным — ведь он занимает более 4000 страниц. Однако мы постарались описать все основные, принципиальные аспекты языка. Условно книгу можно разбить на три части.
О Первая часть, уроки 1-10, предназначена для так называемых конечных пользователей, которые используют базу данных для получения необходимых им сведений. Здесь излагаются основы языка запросов SQL, начиная от самых простых конструкций с постепенным переходом ко все более, сложным.
О Вторая часть, уроки 11-15, в большей мере ориентирована на администраторов базы данных. В ней описываются такие возможности языка, как определение базы данных, ввод данных в базу, создание представлений, защита данных.
О Третья часть, уроки 16-20, ориентирована на программистов, задачей которых является разработка приложений баз данных. Здесь рассмотрены написание
процедур и функций, использование триггеров и транзакций, объектно-ориентированные возможности SQL, интеграция SQL с XML, работа с системным каталогом.
В приложениях приводится полное описание учебной базы данных, используемой в большинстве примеров, а также кратко описывается инструментальное средство SQL*Plus Oracle, которым можно воспользоваться для создания учебной базы данных (самостоятельного или с помощью доступного для загрузки скрипта) и выполнения приводимых в книге примеров.
От издательства
Файл скрипта для создания учебной базы данных можно найти по адресу: http://www.piter.com/download.
Свои замечания, предложения, вопросы отправляйте по адресу электронной почты comp@piter.com (издательство «Питер», компьютерная редакция). Мы будем рады узнать ваше мнение.
Информацию о книгах издательств «Питер» и «Издательская группа BHV» вы найдете на web-сайтах http://www.piter.com и http://www.bhv.kiev.ua.
| УРОК Введение в SQL
Этот урок представляет собой краткое введение в язык SQL. Мы познакомим вас с отдельными вехами в создании и развитии этого языка, становление которого тесно связано с системами управления базами данных (СУБД). Затем рассмотрим многолетнюю деятельность двух ведущих организаций в области стандартизации — Американского национального института стандартов и Международной организации стандартов — по созданию и развитию стандарта SQL. Перечислим основные возможности языка и познакомим вас с основными его понятиями (ключевые слова, предложения, типы данных, литералы, операторы, выражения и т. д.).
Краткая история развития SQL
SQL ведет свою историю с начала 1970-х годов, когда в исследовательской лаборатории компании IBM в штате Калифорния была разработана его первая версия. Первая публикация описания языка относится к 1974 году. В то время его назвали SEQUEL (Structured English Query Language — структурированный английский язык запросов). Сначала он был реализован в экспериментальной реляционной СУБД System/R, проект которой инициировала в середине 70-х годов компания IBM в исследовательской лаборатории в Сан-Хосе. При реализации последующей версии System/R язык был переименован в SQL. Исследовательский проект System/R был завершен в 1979 году. Он подтвердил возможность создания эффективных промышленных реляционных СУБД.
В 1977 году небольшая, только что организованная фирма Relational Software приступила к созданию промышленной реляционной СУБД на основе SQL. Поставки этой СУБД, получившей название Oracle, начались в 1979 году. Вскоре и сама фирма была переименована в Oracle. С тех пор она является крупнейшим поставщиком реляционных СУБД на базе SQL.
В середине 70-х годов в исследовательской лаборатории Калифорнийского университета в Беркли был открыт проект по созданию реляционной СУБД. В этой лаборатории, как и в компании IBM, создали экспериментальную СУБД, получившую название Ingress, на которой отрабатывались результаты научных исследований в области реляционных баз данных. В 1980 году часть сотрудников этой
лаборатории организовали фирму Relational Technology, которая в 1981 году выпустила промышленную СУБД Ingress. Первоначально эта СУБД использовала реляционный язык QUEL, однако в 1986 году была переведена на SQL.
В 1980 году компания IBM на основании опыта, полученного при разработке экспериментальной System/R, приступила к созданию собственной промышленной СУБД реляционного типа, которая начала поставляться в 1982 году под названием SQL/DS. Затем в компании был разработан более совершенный продукт - DB2, поставки которого начались в 1985 году. Эта СУБД стала стратегическим программным продуктом компании IBM.
К середине 80-х годов SQL уже общепризнан как язык реляционных СУБД, а его диалект, поддерживаемый СУБД DB2, фактически стал стандартом для управления реляционными базами данных. К этому времени реляционные базы данных господствовали среди СУБД других типов и считались основной технологией баз данных будущего. '
Деятельность по стандартизации SQL
К началу 80-х годов в связи с широким распространением реляционных СУБД появилась необходимость анализа возможной стандартизации языка для управления реляционными базами данных и разработки такого стандарта, если это будет признано целесообразным. В связи с этим в 1982 году Американский национальный институт стандартов (American National Standards Institute — ANSI) создал комитет X3H2, перед которым была поставлена эта задача. Комитет принял к рассмотрению различные реляционные языки, которые были описаны и реализованы к тому времени. Однако, учитывая широкую распространенность SQL в промышленных СУБД и тот факт, что он фактически уже стал стандартом к тому времени, комитет остановился на этом языке. Взяв за основу его диалект, реализованный в СУБД DB2, комитет постарался его обобщить, учитывая реализованные в других реляционных СУБД возможности. После четырех лет работы, в 1986 году предложенный комитетом вариант SQL был официально утвержден как стандарт ANSI, а в 1987 году он был принят в качестве стандарта Международной организацией стандартов (International Standards Organization — ISO). Затем стандарт ANSI/ISO приняло правительство США как федеральный стандарт в области обработки информации (Federal Information Processing Standard — FIPS). В 1989 году стандарт был незначительно изменен и получил название SQL-89 (или SQL1).
При разработке стандарта SQL-89 члены комитета ХЗН2 столкнулись с многообразием диалектов языка в реализованных на то время СУБД. В состав комитета входили представители ведущих фирм — производителей СУБД, и многие вопросы, касающиеся отличительных особенностей диалектов, не удалось согласовать. В связи с этим было принято компромиссное решение, согласно которому стандартизовано было ядро языка, а существующие различия отнесли к особенностям реализации. Это решение удовлетворило разработчиков СУБД, так как их варианты SQL оказались совместимыми со стандартом, но это же сделало стандарт SQL слабым.
Последующая деятельность этого комитета, который со временем получил название ANSI ТС NCITS Н2, была направлена на устранение недостатков стандарта. В 1992 году ANSI принял новый стандарт, который был назван SQL-92 (или SQL2). В этом стандарте комитет не пошел на поводу производителей СУБД и предусмотрел возможности, которые выходили за рамки имеющихся в промышленных СУБД, — были расширены способы ограничения целостности, введена поддержка различных языков программирования, предусмотрена обработка транзакций и многое другое. В связи с существенным расширением языка было введено три уровня совместимости стандартов. Нижний уровень (Entry Level) предполагает минимальные дополнения к стандарту SQL-89. Промежуточный уровень (Intermediate Level) существенно расширяет SQL-89, но не затрагивает сложных элементов языка. Третий уровень (Full Level) представляет полную спецификацию нового стандарта.
В 1992 году комитет приступил к решительным изменениям в SQL, которые отразились в стандарте SQL-99 (или SQL3). Первое принципиальное изменение заключается в том, что SQL стал поддерживать модель данных, выходящую за рамки реляционной. В соответствии с SQL3, ячейки таблиц могут быть многозначными, что позволяет представлять иерархическую и сетевую модели. Кроме того, язык расширен до возможности представления объектной модели данных и манипулирования ею. Во-вторых, он был структурирован — стал состоять из отдельных частей (parts), составляющих его основу (foundation), которая дополняется неза- 4 висимо определенными модулями (packages).
Наконец, в 2003 году был опубликован последний стандарт — SQL-2003. Ничего . революционного, как это было в SQL-99, в нем нет. Помимо последовательного расширения уже существующих возможностей, введена новая часть языка - SQL/XML, позволяющая интегрировать две популярные технологии структурирования данных.
Возможности SQL
В начале 70-х годов SQL являлся лишь языком запросов (ЯЗ). Он, по сути, содержал только предложение SELECT, которое позволяло формулировать запросы для выборки данных из базы. Затем язык был дополнен двумя другими компонентами, необходимыми для работы с базами данных. Первый из них — средства для определения структуры базы данных, которые в терминологии теории баз данных называются языком определения данных (ЯОД). Второй — средства, позволяющие заполнять базу данными, изменять их и удалять. Этот компонент в теории баз данных называется языком манипулирования данными (ЯМД). Также было принято решение, что весь интерфейс с базами данных должен обеспечиваться одним языком, вследствие чего SQL оброс множеством функций, необходимых для управления базами данных. Приведем некоторые из них:
О определение, переопределение и удаление таблиц базы данных и других ее объектов (доменов, представлений, индексов, триггеров, хранимых процедур, функций и т. д.);
О указание физической организации данных;
О поддержка ограничений целостности и непротиворечивости базы данных;
О защита данных от несанкционированного доступа посредством определения пользователей (с именами и паролями) и ролей, прав доступа к данным и прав на изменение состояния базы данных;
О манипулирование данными в таблицах базы, включая вставку, изменение и удаление значений;
О поиск данных в нескольких таблицах и упорядочение полученных результатов;
О организация резервного копирования и восстановления базы данных;
О поддержка целостности транзакций;
О поддержка пользовательских процедур и функций, расширяющих функциональные возможности SQL.
SQL существует в двух формах. В интерактивном SQL пользователь непосредственно вводит команды и получает результат. Команды встроенного SQL включаются в тексты программ на других языках. В этом случае обращение к базе данных, а также обработка результатов производится этими программами.
Основы SQL
В этом разделе приводятся сведения, которые имеют отношение к языку в целом. К ним, прежде всего, относятся основные синтаксические правила языка, его основные конструкции (слова, фразы, предложения), типы данных, с которыми язык имеет дело, способы представления значений (литералов, или констант) соответствующих типов, операторы, выражения, правила именования объектов.
Основные синтаксические правила
Хотя в SQL существуют правила, характерные для любого языка программирования, его синтаксис довольно гибкий. Первое и основное синтаксическое правило заключается в том, что язык является нечувствительным к регистру букв. Все его фразы и выражения могут быть написаны как прописными, так и строчными буквами. Например, в следующем примере используются прописные буквы:
SELECT DEAN, FUND
FROM FACULTY
WHERE NAME = 'INFORMATICS';
Однако этот же запрос можно записать следующим образом:
Select dean, fund from faculty where name = 'INFORMATICS';
Отметим, что слово INFORMATICS записано в обоих случаях прописными буквами. Это уже не элемент синтаксиса языка, а строковая константа, с которой сравниваются данные базы. Строки символов, ссылающиеся на данные, необходимо записывать в таком же виде, в каком они были введены в базу. Подробнее мы рассмотрим это в одном из следующих уроков.
Второе синтаксическое правило заключается в следующем — в любом месте, где согласно синтаксису языка должен стоять пробел, можно использовать любое
количество пробелов и табуляций, а также начинать новую строку. Например, предыдущий запрос может быть записан и так:
SELECT Dean, Fund FROM FACULTY WHERE Name = •INFORMATICS';
Третье правило касается признака окончания предложения SQL. Стандарт ANSI не определяет для этого какого-либо специального символа. Однако в некоторых реализациях SQL точка с запятой или прямая косая черта указывает интерпретатору, что достигнут конец предложения. Например, приложение SQL*PLUS фирмы Oracle не начнет выполнение запроса до тех пор, пока не будет введен один из указанных символов. В то же время другие приложения не требуют указания конца предложения. Например, в Microsoft Query обработка запроса начинается после щелчка на специальной кнопке. Обратите на это внимание при изучении конкретной СУБД. .
Учитывая, что приводимые примеры выполнялись в приложении SQL*PLUS, в конце каждого предложения SQL мы будем ставить точку с запятой.
Ключевые слова, фразы и предложения
При описании языка мы будем часто пользоваться такими понятиями, как ключевые слова, фразы и предложения.
О Ключевое слово — слово, которое в SQL зарезервировано для специального использования и является частью его синтаксиса. В приведенных выше примерах ключевыми словами являются SELECT, FROM, WHERE. В зависимости от предложения SQL ключевое слово может быть обязательным или факультативным.
О Фраза — часть предложения SQL, имеющая самостоятельный смысл, но не имеющая возможности независимой интерпретации. Любая фраза обязательно включает в себя ключевое слово, по которому она и называется, а также другие конструкции языка. Примером фразы может быть SELECT Dean, Fund. Она называется фразой SELECT. Другой пример — фраза WHERE Name = 'INFORMATICS', которая называется фразой WHERE.
О Предложение — конструкция SQL, которая имеет возможность самостоятельной интерпретации. Предложения SQL состоят из фраз, одна из которых считается базовой и по ее имени называется предложение. Примером предложения является SELECT Dean, Fund FROM FACULTY WHERE Name = 'INFORMATICS';. Оно состоит из трех фраз: SELECT, FROM и WHERE. Базовой в этом предложении является фраза SELECT, поэтому и предложение называется предложением SELECT.
^ПРИМЕЧАНИЕИногда мы будем называть предложение командой, подразумевая под
этим то, что оно может быть выполнено.
Правила описания синтаксиса
При описании языка будут использоваться синтаксические обозначения, представленные в табл. 1.1.
Таблица 1.1. Специальные синтаксические обозначения
Обозначение Описание
SELECT
Прописными буквами указаны ключевые слова, фразы и другие конструкции языка, которые должны присутствовать в тексте именно в том виде, в каком они приведены в описании синтаксиса
условие
1
Строчные буквы используются для обозначения метасимволов, то есть таких элементов синтаксиса, которые должны заменяться другой конструкцией
Конструкции, разделенные прямой вертикальной чертой, являются вариантами, из которых можно использовать только один. Например, в случае указания INSERT | DELETE | UPDATE нужно вводить либо INSERT, либо DELETE, либо UPDATE"
[]
Конструкция, заключенная в квадратные скобки, является необязательной. Например, указание [INSERT | DELETE | UPDATE] обозначает, что можно не вводить ни одного варианта
{}
Конструкция, заключенная в фигурные скобки, обязательна. Например, указание {INSERT | DELETE | UPDATE} обозначает, что один из вариантов должен быть введен обязательно
Многоточие указывает, что конструкцию перед ним можно повторить несколько раз. Например, указание [, имя_столбца]... обозначает, что содержание метасимвола имя_столбца вместе с предшествующей запятой можно опустить, а также ввести один или несколько раз
Если в имени метасимвола использовано слово список, это означает один или несколько разделенных запятой указанных элементов (если не оговорено ничто иное). Например, метасимвол список_имен_столбцов обозначает перечень имен столбцов, разделенных запятыми: имя столбца[, имя столбца]...
Поддержка наборов символов
Несколько забегая наперед, опишем общие правила стандарта SQL по оперированию наборами символов, так как без этого будут неясны многие вопросы. Набор символов включает три составляющих, описанных ниже.
О Совокупность символов, которая в соответствии со стандартом SQL должна быть подмножеством Универсального набора символов (UCS, Universal Character Set).
О Способ кодирования символов, которых для каждой совокупности символов может быть один или несколько. Способы кодирования могут соответствовать стандартам или определяться конкретной реализацией SQL. Если реализация поддерживает более одного способа, должна быть определена их упорядоченность. Например, для совокупности символов UCS определена следующая упорядоченность способов кодирования: UTF8 < UTF16 < UTF32.
О Способ сравнения символов, определяющий упорядоченность символов в совокупности (то есть, для любых двух символов совокупности устанавливающий отношение больше-меньше-равно). Способ сравнения символов может соответствовать стандарту или определяться конкретной реализацией SQL. В реализации может поддерживаться несколько способов сравнения для каждой совокупности символов, и один способ сравнения может применяться к различным совокупностям символов.
Стандарт SQL допускает использование наборов символов трех категорий: стандартных, определяемых реализацией и определяемых пользователями (или приложениями). К первой категории относятся национальные и международные стандарты. Они определяют совокупности символов, способы их кодирования и сравнения. К стандартным отнесен наборов символов SQLCHARACTER и некоторые другие (GRAPHICJRV, ASCII_GRAPHIC, ASCII_FULL, LATIN1, ISO8BIT, UTF32, UTF16, UTF8).
Определяемые реализацией наборы символов фиксируют свои собственные совокупности символов, способы их кодирования и сравнения. Согласно требованиям стандарта SQL, реализация должна включать следующие два набора символов: SQL_TEXT и SQLJDENTIFIER.
Кроме того, стандарт SQL предоставляет возможность пользователям самим определять способы сравнения и наборы символов как объекты схемы. В любой момент времени они могут быть удалены.
Определение способа сравнения символов производится командой CREATE COLLATION, которая имеет следующий синтаксис:
CREATE COLLATION способ_сравнения FOR набор_символов
FROM существующий_способ_сравнения [NO PAD | PAD SPACE]
Как видно из определения, создаваемые способы сравнения базируются на существующих. Фраза NO РАО указывает, что сравнение не предусматривает дополнения более короткой строки пробелами до более длинной, а фраза PAD SPACE указывает, что перед сравнением более короткая дополняется пробелами до размера более длинной строки.
Определение нового набора символов производится командой CREATE CHARACTER SET, которая имеет следующий синтаксис:
CREATE CHARACTER SET набор_символов [AS]
GET существующий_набор_символов
[COLLATE способ_сравнения]
Таким образом, определяемый набор символов базируется на существующем наборе и может иметь свой способ сравнения символов, используемый по умолчанию. Наконец, стандарт SQL предоставляет возможность определения преобразования (трансляции) строк текста одного набора символов в строки другого набора. Для этого используется команда CREATE TRANSLATION, имеющая следующий синтаксис:
CREATE TRANSLATION транслятора
FOR исходный_набор_символов
ТО целевой_набора_символов
FROM {существующий_транслятор | процедура_трансляции}
Транслятор преобразует строки исходного набора символов в строки целевого набора с использованием либо существующего транслятора, либо заданной процедуры трансляции. Сама процедура трансляции в стандарте не специфицируется. После определения транслятора он может использоваться в функции TRANSLATE, осуществляющей преобразование строки символов в соответствии с указанным транслятором:
TRANSLATE(строка USING транслятор)
Типы данных SQL
SQL поддерживает типы данных трех классов: предопределенные, конструируемые и определяемые пользователем. В табл. 1.2 представлены типы данных первого класса (некоторые опущены из-за их специфичности), а об остальных речь пойдет в следующих главах.
Таблица 1.2. Классификация предопределенных типов данных SQL
Категория
Описание
Тип в SQL
Тип в Oracle
Строковые
Строка символов
{CHARACTER | CHAR}
CHAR
типы
постоянной длины
(количество_символов)
(количество_символов)
Строка символов
{{CHARACTER | CHAR}
VARCHAR
переменной длины
VARYING | VARCHAR} (количество_символов)
(количество_символов)
Большая строка символов переменной длины
{{CHARACTER | CHAR) LARGE OBJECT | CLOB} (количество_символов)
CLOB
Большой двоичный объект переменной длины
{BINARY LARGE OBJECT | BLOB} (количество_байт)
BLOB
Числовые
Целое число
INTEGER | INT
NUMBER(38)
точные типы
Целое число.
Количество разрядов больше или равно INTEGER
BIGINT
NUMBER(38)
Целое число.
Количество разрядов меньше или равно INTEGER
SMALLINT"
NUMBER(38)
Число с фиксированной
NUMERIC(количество-
NUMBER(количество-
запятой (количество_разрядов — общее число знаков, масштаб — знаков после запятой)
разрядов, масштаб)
разрядов, масштаб)
То же
{DECIMAL | DEC}(количество- разрядов, масштаб)
NUMBER(количество- разрядов, масштаб)
Категория
ОписаниеТип в SQLТип в Oracle
Числовые неточные типы
Число с плавающейREALNUMBER
запятой
Число с плавающейDOUBLE PRECISIONNUMBER
запятой. Количество разрядов больше или
равно REAL
Число с плавающейFLOAT(кол имеет во_NUMBER
запятойразрядов)
Временные типы
Дата. Содержит год,DATEDATE
месяц и день
Временная отметка.TIMESTAMP(масштаб)TIMESTAMP(масштаб)
Содержит год, месяц,[{WITH | WITHOUT}
день, час, минутыTIME ZONE]
и секунды
Временные типы
Время. Содержит час, Т1МЕ(масштаб) [{WITH |DATE
минуты и секундыWITHOUT} TIME ZONE]
(масштаб — количество знаков в дробной части секунд). Возможно указание временной зоны
Временной промежуток.INTERVALINTERVAL {YEARТО
Точность можетвременная_единицаMONTH | DAY ТО
указываться[ТО временная_единица]SECOND}
единственной единицей измерения времени либо от большей к меньшей
Логический тип
Принимает'BOOLEAN
истинностные значения
XML
Данные XMLXMLXMLType
Литералы
Литералы (или константы) — это простейшие выражения, являющиеся значениями соответствующих типов. Каждый тип данных имеет способ представления литералов своего типа. В SQL имеются литералы символьных строк, двоичных строк, чисел, временные и логические.
Литералы символьных строк
Литерал символьной строки представляется заключением строки символов в оди- парные кавычки. Если строка содержит одинарную кавычку, то ее следует представить двумя кавычками. Примеры литералов символьных строк:
"Это символьная строка*
'Здесь внутри будут "одинарные" кавычки'
Литералы двоичных строк
Литерал двоичной строки для представления одного байта использует пару шестнадцатеричных цифр (это цифры 0-9 и латинские буквы A-F). В начале двоичной строки ставится символ X, а вся строка заключается в одинарные кавычки. Например:
X'1AFFD561'
Числовые литералы
Точный числовой литерал представляется с использованием десятичных цифр (0-9), точки (.) и знаков плюс (+) или минус (-) в начале. Нулевая целая часть может опускаться. Примеры:
27 -863 0.173.8582 -9572.5619
Неточный числовой литерал задается в виде:
мантисса Е экспонента
где мантисса — точный числовой литерал, экспонента — целое число. Символ Е обозначает, что мантисса умножается на 10 в степени экспоненты. Примеры:
11.54Е7.94Е194 93Е-12 -29.629Е27
Временные литералы
Литерал даты представляется в следующем формате:
DATE 'YYYY-MM-DD*
где YYYY — четыре цифры года, ММ — две цифры месяца, DD — две цифры дня. Разделителем между ними является символ минуса (-). Например:
DATE '2005-12-07' DATE '1941-07-22'
Литерал времени имеет следующий формат:
TIME 'HH:MI:SS'
где НН - две цифры часа, MI - две цифры минут и SS - две цифры секунд. Разделителем между ними является символ двоеточия (:). Например:
TIME '17:22:00' TIME '01:01:01'
Отметим, что во многих СУБД литералы даты и времени представляются иными способами. Так, например, в Oracle тип DATE включает в себя дату и время, поэтому существует единый литерал для их представления. Задается он в виде строкового литерала, формат которого либо определяется по умолчанию, либо устанавливается через переменную окружения Oracle. Однако наилучший способ указания литерала даты — воспользоваться функцией TO DATE, которая преобразует в дату строку, заданную в указанном формате:
TO_DATE (1дата_в_виде_строки', 'формат даты')
Рассмотрим примеры:
TO_DATE ('01-17-2003', 'MM-DD-YYYY')-- задание месяца, дня и года
TO_DATE('32:17', 'MI:SS')-- задание минут и секунд
TO_DATE ('13/07/1947 15:12:07', 'MM-DD-YYYY HH:MI:SS') -- задание дня, месяца, года, часа, минут, секунд
Литерал временной отметки содержит все составляющие даты и времени и имеет следующий формат:
TIMESTAMP 'YYYY-MM-DD HH:MI:SS'
Обозначение составляющих даты и времени в этом формате такое же, как и для литералов даты и времени. Пример:
TIMESTAMP '2005-12-07 19:45:11'
Литерал временного промежутка имеет следующий формат:
INTERVAL {'годмесяц' | 'день_время'} квалификатор
Метасимвол год_месяц обозначает следующие два варианта:
YYYYC-MM] | ММ
Метасимвол день время обозначает такие варианты:
DD[HH[:MI[:SS]]] | HH[:MI[:SS]] | MI[:SS] | SS
В конце литерала следует квалификатор, указывающий временную единицу. Приведем примеры временных промежутков:
INTERVAL '123-2' YEAR ТО MONTH- 123 года и 2 месяца
INTERVAL '4' YEAR .--4 года
INTERVAL '50' MONTH-- 50 месяцев
INTERVAL '4 5:12:10.222' DAY TO SECONDO) -- 4 дня, 5 часов. 12 минут, 10,222 секунды
Логические литералы
Существует три логических литерала: TRUE, FALSE, UNKNOWN.
Операторы и выражения
Операторы — это конструкции языка, указывающие операции над элементами данных и возвращающие в качестве результата новое значение. Элементы данных, используемые в операторах, называются операндами или аргументами. Операторы представляются в виде специальных символов или ключевых слов. Например, оператор умножения представляется звездочкой (*), а оператор проверки на неопределенное значение — ключевым словом IS NULL.
Есть два основных вида операторов. Унарные имеют только один операнд и обычно представляются в следующем формате:
операнд оператор
Бинарные оперируют двумя операндами и представляются таким образом:
операнд оператор операнд
Кроме того, существуют специальные операторы, использующие более двух операндов. Тип оператора определяется типом используемых аргументов и типом возвращаемого результата. Имеются операторы следующих типов:
О строковые;
О арифметические;
О логические;
О предикаты сравнения;
О специальные предикаты;
О операторы над множествами (таблицами).
Строковые операторы
Над строковыми значениями (символьными и двоичными) определен бинарный оператор конкатенации (11), который соединяет строки, являющиеся его операндами. Например, результатом выражения:
'Оператор конкатенации* || * соединяет две строки*
является строка:
'Оператор конкатенации соединяет две строки*
Тот же результат дает многократное применение оператора конкатенации:
'Оператор конкатенации* |] * соед* || *иняет две строки*
Арифметические операторы
Над числами определены обычные арифметические операторы: бинарные и унарные плюс (+) и минус (-), бинарные умножить (*) и делить (/). Для указания порядка вычисления операторов, отличающегося от принятого, применяются круглые скобки. Пример:
-37.75 + (1 - 26) * 55.7 / 67.88
Арифметические операторы применимы также к временным значениям — допустимые варианты указаны в табл. 1.3.
Таблица 1.3. Арифметические операторы над временными значениями
Тип левого операнда
Оператор
Тип правого операнда
Тип результата
Дата-время
-
Дата-время
Промежуток
Дата-время
+ или -
Промежуток
Дата-время
Промежуток
+
Дата-время
Дата-время
Промежуток
+ или -
Промежуток
Промежуток
Промежуток
* или /
Число
Промежуток
Число
*
Промежуток
Промежуток
Логические операторы
Логические операторы возвращают логическое значение на основании логических значений его операндов. Имеются следующие три логических оператора: AND, OR и NOT. Использование этих операторов описывается в уроке 3, который посвящен изучению фразы WHERE. В уроке 10 описывается логическое значение UNKNOWN и его использование в логических операторах.
Предикаты сравнения
Предикаты (операторы) сравнения используют в качестве аргументов строки, числа, временные значения и возвращают истинностное значение (TRUE, FALSE или UNKNOWN). В SQL имеется шесть операторов сравнения:
= равно;< меньше;> больше;
<> не равно;<= меньше или равно; >= больше или равно.
Не для всех типов данных можно использовать любые предикаты сравнения. Для больших строк символов определено только сравнение на равенство и неравенство, двоичные строки могут сравниваться только на равенство. Сравнение значений даты и времени производится согласно хронологическому порядку. Сравнивать можно также логические значения, при этом предполагается, что TRUE больше FALSE, а сравнение с UNKNOWN всегда дает UNKNOWN.
Другие случаи использования предикатов сравнения подробно рассматриваются в уроке 3 при изучении фразы WHERE.
Специальные предикаты
Предикаты этого класса указаны в табл. 1.4. Они расширяют возможности предикатов сравнения. Кроме операторов ALL, SOME, ANY, остальные проверяют значение операнда на соответствие определенному условию.
Таблица 1.4. Специальные предикаты
Предикат
Описание
ALL, SOME, ANY
Квантификация операторов сравнения
BETWEEN
Вхождение в заданный диапазон значений
DISTINCT FROM
. Являются ли разными две строки таблиц
EXISTS
Не является ли множество значений пустым
IN
Вхождение во множество значений
IS A SET
Является ли мультимножество множеством
IS NORMALIZED
Является ли символьная строка нормализованной строкой UCS (Universal Multi-Octet Coded Character Set)
IS NULL
Является ли значение неопределенным
IS OF
Принадлежность типу
LIKE
Соответствие строке шаблона
MATCH
Соответствие строки одной таблицы множеству строк другой таблицы
продолжение ^
Таблица 1.4 (продолжение)
Предикат
Описание
MEMBER
Является ли значение членом мультимножества
OVERLAPS
Пересекаются ли два временных диапазона (заданные парами значений дата-время)
SIMILAR ТО
Соответствие регулярному выражению
SUBMULTISET
Принадлежит ли под мультимножество другому мультимножеству
UNIQUE
Являются ли строки результата запроса уникальными
Большая часть из этих предикатов будет изучена на последующих уроках.
Операторы над множествами (таблицами)
В SQL определено несколько операторов над множествами строк (таблицами), возвращающими в качестве своих значений также множество строк (таблицу). К ним относятся следующие:
О UNION ALL, UNION DISTINCT;
О EXCEPT ALL, EXCEPT DISTINCT;
О INTERSECT ALL, INTERSECT DISTINCT.
Изучению этих операторов посвящен урок 9.
Выражения
Выражение — это конструкция языка, возвращающая значение. Типы выражений довольно разнообразны.
По сути, выражением является конструкция SELECT FROM, не говоря уже об имени столбца во фразе SELECT, которое возвращает значение столбца. Конструкция Post = ' профессор' также выражение, так как ее результатом является истинностное значение. В общем случае выражение представляет собой одно значение или комбинацию значений (столбцов, констант, функций и операторов). Возвращаемое выражением значение имеет определенный тип.
Простым примером выражения является 2 * 2, которое имеет тип INTEGER (тот же, что и члены выражения) и возвращает число 4. Следующее выражение является более сложным и использует функции, арифметический оператор + и строковый оператор |1. Это выражение добавляет семь дней к текущей дате, удаляет время из полученной даты, переводит ее в строку символов и добавляет к строковой константе (записано с использованием функций Oracle):
'Дата через 7 дней: ' || TO_CHAR(TRUNC(SYSDATE + 7))
Следует помнить, что выражения строятся над значениями одного или совместимых типов. Примером логического выражения может быть следующее:
Name = 'Иванов* OR Salary + Rise <= 1295.99 AND HireDate > DATE *2005-12-07'
В SQL определено понятие скалярного выражения — это выражение над столбцами таблицы с использованием строковых функций и констант.
При построении выражений следует помнить о старшинстве операторов. Старшинство операторов определяет порядок, в котором они вычисляются в выражении, то есть по убыванию старшинства. Операторы одного старшинства вычисляются слева направо. Если необходимо изменить этот порядок, следует воспользоваться круглыми скобками. В табл. 1.5 приводятся группы операторов в порядке убывания их старшинства.
Таблица 1.5. Старшинство операторов в SQL
Оператор
Операция
*, /
Унарные плюс и минус
Умножение и деление
+» - Л
Сложение, вычитание и конкатенация
=, <>, <, >, <=, >=, IS NULL, LIKE, SIMILAR, BETWEEN, IN, EXISTS, UNIQUE, MATCH, OVERLAPS, DISTINCT FROM
Сравнение
NOT
Логическое отрицание
AND
Логическая конъюнкция
OR
Логическая дизъюнкция
Операторы над множествами не используются в выражениях с другими операторами и имеют одинаковое старшинство.
Именование объектов
В соответствии со стандартом SQL, имена объектов базы данных могут состоять из прописных и строчных букв латинского алфавита, цифр и символа подчеркивания О, причем первым символом должна быть буква. Если нужно использовать имя, не отвечающее указанным правилам, его следует заключать в двойные кавычки.
Однако многие СУБД, в том числе Oracle, расширяют набор допустимых символов, включая в них, например, символы национальных алфавитов.
Комментарии
В текстах на языке SQL можно использовать комментарии, которые предоставляют возможность указывать авторство, приводить объяснения и любую другую полезную информацию. Комментарий может содержать любые печатаемые символы. На выполнение команд SQL комментарии не влияют и могут располагаться между ключевыми словами, параметрами и в любом другом месте, где в соответствии с правилами языка должен быть разделитель.
Имеются два типа комментариев:
О многострочный начинается с символов /*, за которыми следует одна или несколько строк комментария, и завершается символом *;
О однострочный располагается в конце строки и начинается с символов —, за которыми следует текст комментария.*
Предложение SQL может содержать комментарии обоих типов.
Подведение итогов
Усвоив материал этого урока, вы изучили:
0 краткую историю развития SQL;
0 деятельность ANSI и ISO по стандартизации SQL;
0 основные возможности SQL;
0 основные синтаксические правила SQL;
0 понятия ключевое слово, фраза и предложение;
0 типы данных SQL;
0 правила написания литералов;
0 операторы и выражения SQL;
0 правила именования объектов;
0 использование комментариев.
§ )УРОК Простейшие запросы
В этом уроке мы приступаем к изучению возможностей SQL по выборке данных из базы — так называемого языка запросов. Ему будет посвящено несколько уроков. В качестве языка запросов SQL используется наиболее интенсивно. Это означает, что подавляющее число пользователей используют его именно для организации поиска информации в базе данных, а не для чего-нибудь другого. Начиная с самых простых возможностей и последовательно переходя к все более сложным конструкциям, мы изучим практически все указанные в стандарте SQL средства поиска и выборки данных. Кроме того, будут представлены некоторые дополнительные возможности, реализованные в СУБД Oracle.
Запрос - это команда, которой вы сообщаете СУБД, что она должна найти и показать определенную информацию из базы данных. Эта информация обычно посылается непосредственно на экран компьютера, хотя в большинстве случаев ее можно также послать на принтер, сохранить в файле, представить как исходную информацию для другой команды или процесса или вернуть назад в программу, из которой было инициировано выполнение запроса.
Запросы иногда рассматриваются как часть ЯМД. Однако поскольку запрос не изменяет данные, а только предоставляет их пользователю, мы будем рассматривать запросы как действия самостоятельной категории.
О предложении SELECT
Все запросы в SQL состоят из единственной команды или, как принято говорить в SQL, предложения. Структура этого предложения проста, элегантна, однако оно обладает внушительными возможностями по выборке данных из базы. Это предложение называется SELECT. По отношению к нему мы также будем применять термин команда, подразумевая, что это предложение выполняет определенные действия.
Предложение SELECT может состоять из многих фраз и в упрощенном виде имеет следующий синтаксис:
SELECT {* | [DISTINCT | ALL] список_выражений_выбора)
[INTO список пеоеменных!
FROM список_спецификаций_таблиц
[WHERE условие]
[[START WITH условие_спецификации_корня]
CONNECT BY условие_рекурсивной_связи]
[GROUP BY список_выражений_группировки
[HAVING групповое_условие]]
[ORDER BY список_выражений_упорядочения];
В этом уроке мы изучим фразы SELECT и FROM, а в следующем уроке рассмотрим фразу WHERE. Фразы START WITH и CONNECT BY изучаются в уроке 10, a GROUP BY, HAVING и ORDER BY - в уроке 6.
В самой простой форме предложение SELECT инструктирует СУБД о необходимости извлечь информацию из таблицы базы данных. Например, можно вывести всю таблицу FACULTY, сформулировав следующий запрос:
SELECT FacPK. Name. Dean. Building, Fund
FROM FACULTY;
Этот запрос содержит следующие компоненты.
О SELECT — ключевое слово, сообщающее СУБД, что эта команда является запросом. Все запросы начинаются этим словом. Указанные за ним FacPK, Name, Dean, Building, Fund являются списком столбцов, которые выбираются запросом из таблицы. Любые ее столбцы, не перечисленные здесь, не будут включены в вывод команды. Это не значит, что сами столбцы или их данные будут удалены — запрос не воздействует на информацию в таблицах; он только выводит ее.
О FROM — ключевое слово, за которым следует указать имя таблицы, используемой в качестве источника. В данном случае это таблица FACULTY.
О ; — используется во всех интерактивных командах SQL, чтобы сообщить СУБД о конце предложения.
Запрос, указанный в примере, не будет упорядочивать выходные данные. Тот же запрос, но выполненный повторно, может вывести те же данные в другом порядке. Строки обычно отбираются в том порядке, в котором они найдены в таблице. Поскольку этот порядок произволен, последовательность выведенных строк необязательно будет соответствовать порядку их ввода. Упорядочивать вывод можно фразой ORDER BY предложения SELECT, и позже мы покажем, как это делать.
В общем случае результатом выполнения предложения SELECT является другая таблица. К этой новой (рабочей, временной или промежуточной) таблице может быть снова применена команда SELECT и т. д., то есть такие операции могут быть вложены друг в друга. Представляет интерес тот факт, что именно благодаря возможности включения одного предложения SELECT внутрь другого в названии SQL использовали слово «структурированный».
Желательно, чтобы текст запроса был наглядным, то есть легко воспринимался визуально. Наглядность является во многом индивидуальным свойством, однако существуют общие принципы, ей способствующие. Мы не будем их здесь рассматривать, просто обратите внимание, как сформатированы примеры в данной книге.
Основные фразы — SELECT и FROM
В данном разделе мы рассмотрим самые простые возможности языка запросов, обеспечивающие выборку данных из одной таблицы без условия отбора и упорядочения результатов. Для этого используются фразы SELECT и FROM, которые обязательны для всех запросов (все остальные фразы предложения SELECT — факультативные). Обратите внимание, что по отношению к ключевому слову SELECT мы употребляем термины и предложение, и фраза. Дело в том, что предложение, с помощью которого формулируется запрос, состоит из множества фраз, и первая из них — SELECT. В связи с этим и все предложение было названо SELECT.
Фраза FROM указывает, из какой таблицы следует выбрать данные, а фраза SELECT — какие именно столбцы из указанной таблицы должны быть выбраны. Следующий запрос приводит к выводу названий факультетов:
SELECT Name
FROM FACULTY;
Фраза FROM должна содержать имя хотя бы одной таблицы, а фраза SELECT — указание на вывод хотя бы одного ее столбца.
Фраза SELECT — указание выводимых данных
Рассмотрим, как можно воспользоваться фразой SELECT для организации выдачи данных. Эта фраза имеет две синтаксические формы:
SELECT *
SELECT [DISTINCT | ALL] выражение_выбора [[AS] алиас][, выражение_выбора [[AS] алиас]]...
Далее на примерах покажем все возможные варианты использования этой фразы.
Указание выводимых столбцов
Основное назначение фразы SELECT — указать, какие столбцы исходной таблицы должны быть выведены.
Вывод значений определенных столбцов
Можно вывести определенные столбцы таблицы, для чего следует перечислить во фразе SELECT их имена, разделяя запятой с возможным последующим пробелом. Столбцы выводятся в порядке их указания во фразе SELECT.
Запрос. Вывести из таблицы SGROUP столбцы номера группы, номера курса и количества студентов в группе.
SELECT Num, Year, Quantity
FROM SGROUP;
NUMYEAR QUANTITY
505527
504531
307333
408420124084201227352735
4084
2012
4084
2012
27
35
27
35
Вывод всех столбцов
Также можно вывести все столбцы таблицы. Для этого следует либо все их перечислить во фразе SELECT, либо, если вас устраивает порядок расположения столбцов в исходной таблице, воспользоваться символом *.
Запрос. Вывести все столбцы таблицы DEPARTMENT.
SELECT DepPK, FacFK, Name. Head. Building. Fund
FROM DEPARTMENT;-
SELECT *
FROM DEPARTMENT;
DEPPK FACFK NAMEHEAD BUILDING FUND
1
2
3
4
5
6
1 базы данныхСоколов626000
1 программирование Федоров612000
1 интернетСтрельцов310000
2 теория языковГлущенко310000
2 лингвистикаКоробов314100
2 базы данныхТараненко527000
В случае использования звездочки во фразе SELECT не могут быть указаны никакие имена столбцов.
Уточнение имен
Имена столбцов являются уникальными в пределах одной таблицы, поэтому при использовании в запросе только одной таблицы никаких коллизий имен столбцов быть не может. Однако при вычислении запроса может использоваться несколько таблиц, и если в них имеются столбцы с одинаковыми именами, при обращении к ним возникает неоднозначность. В связи с этим в SQL действует правило, согласно которому имя любого столбца в любом месте запроса может быть уточнено именем таблицы:
имя_таблицы.имя_столбца
Уточнять имена столбцов можно всегда, даже когда в этом нет необходимости. Так, например, рассмотренный выше запрос может иметь следующий вид:
SELECT SGROUP.Num, SGROUP.Year. SGROUP.Quantity
FROM SGROUP;
Исключение повторяющихся строк
Когда вы выводите все столбцы таблицы, то можете быть уверены, что выводимые строки будут уникальны — таблица не может содержать повторяющихся строк. Однако если выводятся не все столбцы, повторяющиеся строки могут образоваться. Например, нас интересует список должностей в вузе.
Запрос. Вывести значения столбца Post таблицы TEACHER.
SELECT Post
FROM TEACHER:
POST
профессор
доцент
преподаватель
ассистент
ассистент
преподаватель доцент
ассистент
доцент
ассистент
профессор
преподаватель
профессор
доцент
преподаватель
В результате будут выведены все строки таблицы. SQL сам по себе не исключает повторяющиеся строки при формировании результирующей таблицы. Для того чтобы указать необходимость такого исключения, следует воспользоваться ключевым словом DISTINCT.
Запрос. Вывести уникальные значения столбца Post таблицы TEACHER.
SELECT DISTINCT Post
FROM TEACHER:
POST
ассистент
доцент
преподаватель
профессор
Это удобный способ избежать избыточности результирующих данных, но важно, чтобы это делалось осознанно. Использовать ключевое слово DISTINCT нужно осторожно, если вы не хотите потерять информацию. При его применении какие-то проблемные или важные данные могут быть скрыты. Например, вы предполагаете, что названия всех кафедр в таблице DEPARTMENT различны. Однако если это не так, то с помощью запроса
SELECT DISTINCT Name
FROM DEPARTMENT:
вы не узнаете о повторяющихся названиях, станете использовать строку не той кафедры и даже не узнаете об этом.-
Указывать ключевое слово DISTINCT можно только один раз - оно применяется не к отдельным столбцам, перечисленным во фразе SELECT, а ко всей строке результирующей таблицы, формируемой предложением SELECT. Исключением является его использование в аргументе агрегатной функции (см. урок 5). Ключевое слово DISTINCT нельзя использовать вместе с символом *. Да это и бессмысленно, так как строки в таблице не повторяются.
Альтернативой DISTINCT является ключевое слово ALL. Оно имеет противоположный эффект — повторяющиеся строки в результирующей таблице сохранятся.
Так как по умолчанию выводятся все строки, включая и повторяющиеся, то ALL, по существу, пояснительное, а не действующее ключевое слово.
Использование вычисляемых выражений
Фраза SELECT может содержать не только перечень столбцов таблицы или символ *, но и выражения. Выражения базируются на именах столбцов и могут быть любыми допустимыми в языке выражениями соответствующих типов. Приведем пример. Запрос. Вывести фамилии преподавателей, их ставки, надбавки, сумму ставки с надбавкой и процент надбавки относительно ставки.
SELECT Name, Salary, FROM TEACHER;
Rise,
RISE S,
Salary + Rise, Rise * 100 / Salary
\LARY+RISE RISE*100/SALARY
NAME
SALARY 1
Сидоров
1070
470
1540
43.93
Рамишевский
830
370
1200
44.58
Хоренко
670
230
900
34.33
Вибровский
570
170
740
29.82
Воропаев
570
150
720
26.32
Кузинцев
630
270
900
42.86
Завратинский
770
341
1111
44.29
Козлутин
530
220
750
41.51
Лекарь
890
440
1330
49.44
Мартынов
530
220
750
41.51
Резван
1100
470
1570
42.73
Недеведеев
570
230
800
40.35
Ахромеев
1050
500
1550
47.62
Наумов
770
350
1120
45.45
Дараганов
570
250
820
43.86
В SQL действует правило, согласно которому, если в арифметическом выражении значение какого-либо операнда не определено (иначе говоря, операнд имеет специальное значение NULL), то и все выражение принимает значение NULL. Это относится и к выражениям во фразе SELECT. Будьте внимательны и всегда помните об этом.
Переопределение имен результирующих столбцов
Столбцы результирующей таблицы будут иметь те имена, которые указаны во фразе SELECT. Однако имена столбцов в таблицах базы данных могут быть сжатыми, а подчас представлять собой сокращение — в этом случае их использование в выводе может существенно понизить наглядность.
Имена столбцов, указанные во фразе SELECT, используются также для ссылки на них в других фразах (например, GROUP BY, HAVING, ORDER BY) и запросах. Если результирующий столбец является вычисляющим выражением (например, Rise * 100 / Salary), сослаться на него не получится.
В этом случае можно использовать возможность переопределения имени столбца в результирующей таблице, для чего необходимо после имени столбца исходной таблицы или выражения указать ключевое слово AS и затем новое имя столбца.
Запрос. Вывести данные о факультетах и их удвоенных фондах финансирования под новыми именами.
SELECT Name AS Faculty_Name, 2 * Fund AS Double_Fund
FROM FACULTY:
FACULTY_NAME DOUBLE_FUND
информатика50000
кибернетика54000
математика46000
Ключевое слово AS не является обязательным, существующее и новое имена можно записать просто через пробел. Переопределенное имя называется синонимом столбца (иногда говорят о псевдониме или алиасе столбца). Правила именования синонимов такие же, что и для имен столбцов, и могут зависеть от особенностей конкретной СУБД. В следующем запросе в синонимах используется пробел, поэтому они заключены в двойные кавычки.
Запрос. Вывести данные о кафедрах и их утроенных фондах финансирования под новыми именами.
SELECT Name "Название кафедры".
Fund * 3 "Утроенный фонд финансирования"
FROM DEPARTMENT:
Название кафедры Утроенный фонд финансирования
780003600030000300004230081000780003600030000300004230081000базы данных программирование интернет
78000
36000
30000
30000
42300
81000
78000
36000
30000
30000
42300
81000
теория языков лингвистика базы данных
Включение текста в результат запроса
Во фразе SELECT кроме имен столбцов и выражений с ними можно указывать константы (и константные выражения). Это приведет к тому, что в результирующей таблице будет создан столбец с одинаковыми значениями во всех строках. Такой константой может быть любой литерал, в том числе и символьный. Покажем это на примере.
Запрос. Вывести ставки преподавателей, оформив результат предложениями на русском языке.
SELECT 'Преподаватель*. Name, 'имеет ставку', Salary. '.'
FROM TEACHER:
ПРЕПОДАВАТЕЛЬ NAME ИМЕЕТСТАВКУ SALARY.
Преподаватель Сидоровимеетставку1070.
Преподаватель Рамишевскийимеетставку830.
Преподаватель Хоренкоимеетставку670.
Преподаватель Вибровский
имеет ставку
570
Преподаватель Воропаев
имеет
ставку
570
Преподаватель Кузинцев
имеет
ставку
630
Преподаватель Завратинский
имеет
ставку
770
Преподаватель Козлутин
имеет
ставку
530
Преподаватель Лекарь
имеет
ставку
890
Преподаватель Мартынов
имеет
ставку
530
Преподаватель Резван
имеет
ставку
1100
Преподаватель Недеведеев
имеет
ставку
570
Преподаватель Ахромеев
имеет
ставку
1050
Преподаватель Наумов
имеет
ставку
770
Преподаватель Дараганов
имеет
ставку
570
В результирующей таблице данные выводятся в пяти столбцах. Однако, используя выражения над столбцами и константами, можно те же данные вывести в виде одного столбца, как это показано в следующем примере.
Запрос. Вывести зарплату преподавателей, оформив результат предложениями на русском языке без лишних пробелов.
SELECT 'Преподаватель ' || Name ||
' имеет зарплату 1 || (Salary + Rise) 11 ' '
AS "Сведения о зарплате"
FROM TEACHER;
Сведения о зарплате
Преподаватель Сидоров имеет зарплату 1540.
Преподаватель Рамишевский имеет зарплату 1200.
Преподаватель Хоренко имеет зарплату 900.
Преподаватель Вибровский имеет зарплату 740.
Преподаватель Воропаев имеет зарплату 720.
Преподаватель Кузинцев имеет зарплату 900.
Преподаватель Завратинский имеет зарплату НИ.
Преподаватель Козлутин имеет зарплату 750.
Преподаватель Лекарь имеет зарплату 1330.
Преподаватель Мартынов имеет зарплату 750.
Преподаватель Резван имеет зарплату 1570.
Преподаватель Недеведеев имеет зарплату 800.
Преподаватель Ахромеев имеет зарплату 1550.
Преподаватель Наумов имеет зарплату 1120..
Преподаватель Дараганов имеет зарплату 820.
В некоторых случаях необходимо вставлять в строки результирующей таблицы разные тексты в зависимости от тех или иных условий. Прямых средств для этого в языке нет, однако можно использовать теоретико-множественный оператор UNION, позволяющий объединять результаты запросов (о нем пойдет речь в уроке 9).
Фраза SELECT обладает ограниченными возможностями форматирования результирующих данных. Обычно в таких случаях в дополнение к базовым средствам СУБД используются сервисные программы, в частности так называемые генераторы отчетов. Они, как правило, обладают широкими возможностями визуального представления результатов запросов.
Фраза FROM — указание используемых таблиц
Как мы уже отмечали, фраза FROM нужна для указания используемых в запросе таблиц. Синтаксис этой фразы следующий:
FROM {имя_таблицы | (подзапрос)} [алиас][, {имя_таблицы | (подзапрос)} [алиас]]...
В запросе могут использоваться несколько таблиц. В этом случае во фразе FROM приводятся их имена, перечисленные через запятую. Например:
FROM FACULTY, DEPARTMENT, SGROUP
Синонимы таблиц
Имена таблиц, как и столбцов, можно переопределить, например, чтобы для ссылок на таблицу использовать короткий (вплоть до одной буквы) синоним (его называют еще алиасом таблицы). Имя таблицы и ее синоним разделяются пробелом:
FROM FACULTY F, DEPARTMENT D, SGROUP G
В случае использования для имени таблицы синонима уточнять столбцы следует только указанным синонимом, например:
F.Name, F.Building. F.Fund, D.Head, D.Fund, G.Year. G.Quantity
В следующем примере слева приведен правильный запрос, а справа — нет:
SELECT f.Name,f.FundSELECT FACULTY.Name,f.Fund
FROM FACULTY f;FROM FACULTY f;
В случае, когда в списке FROM одна и та же таблица указана более одного раза, переопределение имени этой таблицы синонимом является обязательным, и синонимы должны различаться. Например:
FROM TEACHER Tl, TEACHER T2
Теперь к первой копии таблицы можно обращаться с помощью синонима Т1, а ко второй — синонима Т2. Правила именования синонима таблицы те же, что и для имени таблицы, принятые в той или иной СУБД.
Запрос в качестве имени таблицы
Стандарт ANSI и многие СУБД, в частности Oracle, допускают возможность использования запроса во фразе FROM в качестве имени таблицы. Ведь результатом запроса является промежуточная таблица, которая может быть исходной для другого запроса. Для этого нужно только вместо имени таблицы указать во фразе FROM подзапрос, заключив его в круглые скобки.
Таблица, получаемая в результате вычисления подзапроса, не имеет имени. Поэтому, если к ее столбцам необходимо будет обращаться из самого запроса, обязательно нужно приписать подзапросу синоним. Например, в следующем выражении указано, что результирующие таблицы подзапросов именуются как FD и DH:
FROM (SELECT Dean FROM FACULTY) FD, (SELECT Head FROM DEPARTMENT) DH
Мы вернемся к использованию запросов во фразе FROM в уроке 7.
Самостоятельная работа
Напишите запрос, который выводит содержимое всей таблицы ROOM.
Выведите всю таблицу DEPARTMENT, но расположите ее столбцы в обратном порядке.
Выведите фамилии и телефоны всех преподавателей.
Выведите номера групп и их рейтинги с уточнением имен столбцов именем таблицы.
Из таблицы ROOM выведите номера корпусов, исключив при этом повторения.
Выведите для всех преподавателей их фамилию, процент ставки по отношению к надбавке и процент ставки по отношению к зарплате (ставка + надбавка).
Из таблицы SGROUP выведите номера групп под именем Номер группы и курсов под именем Номер курса.
Выведите данные таблицы FACULTY в виде одного столбца следующего формата: «На факультете название_факультета деканом является фамилия_декана».
Запишите фразу FROM для любых трех таблиц учебной базы данных, используя для них синонимы.
Подведение итогов
Усвоив материал этого урока, вы научились:
0 указывать столбцы, отбирающиеся в результирующую таблицу;
0 уточнять имена столбцов;
0 исключать повторяющиеся строки в результирующей таблице;
0 использовать во фразе SELECT выражения;
0 переопределять имена результирующих столбцов;
0 помещать в результирующую таблицу константы;
0 указывать синонимы таблиц;
0 использовать во фразе FROM запросы в качестве источника данных.
^ ) УРОК Отбор строк по условию
Таблицы базы данных имеют тенденцию становиться очень большими, поскольку с течением времени в них добавляется все большее и большее количество строк. Поэтому выборка всех строк таблиц используется довольно редко, в основном при последовательном просмотре базы данных и для создания полных отчетов. Обычно пользователей интересуют только определенные строки таблиц.
SQL дает возможность определить критерии отбора необходимых строк во фразе WHERE предложения SELECT. В этом случае строки исходных таблиц будут включены в результирующую только если строка соответствует указанным критериям. Условие - это выражение, которое может быть истинным или ложным (логическое выражение или предикат), то есть принимать логические значения TRUE или FALSE соответственно. В результирующую таблицу включаются только те строки, для которых указанное во фразе WHERE условие равно TRUE (иными словами, которые удовлетворяют заданному условию).
В случае одной таблицы механизм работы предложения SELECT с фразой WHERE следующий.
Из таблицы, указанной во фразе FROM, выбирается очередная строка.
Она проверяется на соответствие условию во фразе WHERE.
Если результат равен TRUE, строка включается в результирующую таблицу и форматируется в соответствии с фразой SELECT, а если он равен FALSE, строка пропускается.
Далее будут рассмотрены основные выражения, допустимые для условия во фразе WHERE.
Использование простейших условий
Простейшими считаются условия, в которых используются операторы сравнения и логические операторы. Первые иногда также называются операторами отношений, а вторые — логическими связками. Кроме того, мы также будем использовать термин предикат для указания любого оператора, который использует в качестве
операндов атомарные значения или множества и возвращает истинностное значение (TRUE, FALSE).
Хотя такие условия являются простейшими в смысле семантики конструкций, они могут иметь довольно сложную структуру из многих операторов сравнений и вложенных друг в друга логических связок.
Операторы сравнения
Особенностью операторов сравнения является то, что независимо от типов операндов их результатом являются логические значения. Предположим, вы хотите получить список всех профессоров.
Запрос. Вывести фамилии профессоров.
SELECT Name AS Список_профессоров
FROM TEACHER
WHERE Post = * профессор';
СПИСОК_ПРОФЕССОРОВ
Сидоров Резван Ахромеев
Слово * профессор * в запросе является строковой константой, поэтому ее следует заключить в кавычки. Обратите внимание, что мы указали фразу SELECT без ключевого слова DISTINCT, так как тогда от нас была бы скрыта информация о существовании среди профессоров однофамильцев. Чтобы при выводе результирующий столбец имел содержательный заголовок, мы поименовали его как Список_профессоров.
Это первый пример использования предиката над строковым типом данных. Здесь столбец строкового типа сравнивается со строковой константой. Запрос выполнен правильно, однако нужно всегда помнить о том, что предикаты над строками являются чувствительными к регистру букв. Например, предикат 1 ИВАНОВ * = 1 Иванов1 будет ложным. Поэтому, если для некоторого профессора его должность была введена в таблицу TEACHER как 'Профессор', он не будет найден по условию WHERE Post = ' профессор'. Чтобы на предикаты над строками не влиял регистр букв, нужно использовать обычно имеющиеся в СУБД функции преобразования букв в прописные и строчные. В стандарте SQL, например, указаны функции UPPER и LOWER, выполняющие такие преобразования. Следовательно, для предыдущего запроса правильней будет записать условие фразы WHERE одним из следующих способов:
WHERE LOWER(Post) = 'профессор* WHERE UPPER(Post) = 'ПРОФЕССОР*
Запрос. Найти названия кафедр с фондом финансирования, превышающим 15 000.
SELECT Name
FROM DEPARTMENT
WHERE Fund > 15000;
NAME
базы данных базы данных
Здесь Fund является числовым столбцом, поэтому литерал 15000 заключать в кавычки незачем.
ПРИМЕЧАНИЕПРИМЕЧАНИЕВ двух приведенных выше примерах для формулировки условия мы использовали операторы сравнения. Для числовых и временных значений порядок имеет обычный смысл. Для строковых значений используется алфавитный порядок.
ПРИМЕЧАНИЕ
ПРИМЕЧАНИЕ
Точнее, порядок символов определяется их кодировкой. В стандарте SQL алфавитный порядок определен только для английских букв, но имеются средства для определения собственного порядка символов различных алфавитов.
Приведем несколько примеров использования операторов сравнения для столбцов строкового и временного типа. Обратите внимание, что сравнивать можно не только значение столбца с константой, но и значения столбцов между собой.
Запрос. Вывести фамилии и должности преподавателей, принятых на работу после 01.01.2002.
SELECT Name AS Фамилия, Post AS Должность
FROM TEACHER
WHERE Hi reDate > TO_DATEC01/01/2001', 'DD/MM/YYYY');
ФАМИЛИЯ ДОЛЖНОСТЬ
Хоренко преподаватель
Вибровский ассистент
Воропаев ассистент
Козлутин ассистент
Мартынов ассистент
Запрос. Вывести фамилии и должности преподавателей, фамилии которых в алфавитном порядке располагаются после фамилии Резван.
SELECT Name, Post
FROM TEACHER
WHERE UPPER(Name) > 'PE3BAH';
NAME POST
Сидоров профессор
Хоренко преподаватель
Запрос. Вывести фамилии преподавателей, у которых надбавка меньше ставки
в 2,5 и более раз.
SELECT Name AS Фамилии_преподавателей FROM TEACHER
WHERE 2.5 * Rise < Salary;
ФАМИЛИИ_ПРЕПОДАВАТЕЛЕЙ
Хоренко
Вибровский
Воропаев
Логические операторы
Операндами и результатом логических операторов (часто их называют логическими связками или булевыми операторами) являются логические значения.
В связи с возможным отсутствием данных (их значение при этом считается неопределенным) в SQL используется трехзначная логика (с логическими значениями TRUE, FALSE, UNKNOWN). Подробно она рассмотрена в уроке 10.
Стандартными логическими операторами являются AND, OR и NOT. Их действие показано в табл. 3.1-3.3 (в так называемых истинностных таблицах). Использование операторов сравнения вместе с логическими операторами предоставляет возможность формулировать составные условия для отбора строк таблиц. В науке логики существуют и другие логические операторы, однако они не используются в SQL, так как все их можно выразить через AND, OR и NOT.
Таблица 3.1. Значения логического оператора AND
Левый операнд
Правый операнд
TRUE
FALSE
TRUE
TRUE
FALSE
FALSE
FALSE
FALSE
Таблица 3.2. Значения логического оператора 0R
Левый операнд
Правый операнд
TRUE
FALSE
TRUE
TRUE
TRUE
FALSE
TRUE
FALSE
Таблица 3.3. Значения логического оператора NOT
Операнд
Результат
TRUE
FALSE
FALSE
TRUE
Если обобщить, оператор AND истинен только в том случае, когда истинны оба операнда, 0R — когда истинен хотя бы один из операндов, a NOT дает противоположное операнду значение.
Использование логического оператора AND
Логический оператор AND во многих случаях действует как связка «и» в русском языке. Рассмотрим несколько примеров с использованием этого оператора.
Запрос. Вывести названия факультетов, расположенных в корпусе 5 и имеющих фонд финансирования менее 30 000.
SELECT Name
FROM FACULTY
WHERE Building ='5* AND Fund < 30000/
NAME
кибернетика
Запрос. Вывести фамилии преподавателей, которые являются профессорами и ставка которых превышает 1050.
SELECT Name AS "Проф. со ставкой > 1050"
FROM TEACHER
WHERE UPPER(Post) = 'ПРОФЕССОР' AND Salary > 1050;
Проф. co ставкой > 1050
Сидоров
Резван
Запрос. Вывести названия кафедр корпуса 3 с фондом финансирования в диапазоне 12 000-15 000.
SELECT Name
FROM DEPARTMENT
WHERE Building = ’3' AND Fund >= 12000 AND Fund <= 15000;
NAME
лингвистика
Использование логического оператора OR
Логический оператор OR во многих случаях действует как связка «или» в русском языке. Рассмотрим несколько примеров.
Запрос. Вывести названия кафедр, фонд финансирования которых меньше И ООО или больше 25 000.
SELECT Name. Fund
FROM DEPARTMENT
WHERE Fund < 11000 OR Fund > 25000;
NAMEFUND
базы данных 26000
интернет10000
теория языков 10000 базы данных 27000'
Обратите внимание, что в полученной таблице присутствуют две кафедры баз данных. Они принадлежат разным факультетам, но мы еще не можем сформулировать такой запрос. Для этого нужно использовать несколько таблиц, что будет рассмотрено в следующем уроке.
Запрос. Вывести номера аудиторий, расположенных в корпусах 4 и 5.
SELECT Num. Building
FROM ROOM
WHERE Building = '4' OR Building = '5*;
NUM BUILDING
201 5
202 4
Обратите внимание на то, что для выражения логической связи «или» в русском языке часто может использоваться слово «и». Однако если бы во фразе WHERE последнего примера мы написали Bui 1 d1 ng = * 4' AND Building ='5', то обязательно получили бы пустой ответ, так как ни одна из аудиторий не может располагаться в двух корпусах одновременно.
Использование логического оператора NOT
Логический оператор NOT в русском языке передается словами «не» и «кроме».
Запрос. Вывести названия всех факультетов, кроме факультета информатики.
SELECT Name
FROM FACULTY
WHERE NOT LOWER(Name) = 'информатика';
NAME
кибернетика математика
Обратите внимание, что оператор NOT должен предшествовать выражению сравнения, а не ставиться перед оператором сравнения. То есть запись LOWER(Name) NOT = 'информатика1 будет неверной. Учитывая, что отрицанием оператора = является оператор <>, вместо указанного условия можно было бы записать LOWER(Name) <> 'информатика*. Это относится ко всем операторам сравнения, так как каждый из них имеет оператор, являющийся его отрицанием.
Комбинирование логических операторов
Логические операторы можно объединять, формируя составные условия. Возможность комбинирования обеспечивается тем, что любой логический оператор возвращает истинностное значение, а значит, его результат может использоваться в другом логическом операторе. Рассмотрим несколько примеров.
Запрос. Вывести названия, корпуса и фонды финансирования кафедр, расположенных в корпусах 3 или 6 и имеющих фонд финансирования меньше И ООО или больше 25 000.
SELECT Name AS "Название кафедры".
Building AS "Корпус",
Fund AS "Фонд финансирования"
FROM DEPARTMENT
WHERE (Building = '3' OR Building = "6') AND (Fund < 11000 OR Fund > 25000);
Название кафедрыКорпус Фонд финансирования
базы данныхб26000
интернет310000
теория языков310000
Когда в выражении используются несколько логических операторов, всегда следует помнить об их старшинстве, определяющем порядок вычисления. Оператор AND является более приоритетным по сравнению с OR, поэтому он выполняется раньше (как и в арифметике умножение выполняется до сложения). Если поря-
док нужно изменить, используйте круглые скобки, как это сделано и в предыдущем примере. Старшинство операторов указано в табл. 1.5.
Запрос. Вывести фамилии, должность, ставку и надбавку ассистентов, у которых либо ставка меньше 550, либо надбавка больше 160.
SELECT Name. Post. Salary. Rise
FROM TEACHER
WHERE LOWER(PoSt) = 'ассистент* AND (Salary < 550 OR Rise > 160);
NAME POST SALARY RISE
Вибровский ассистент570170
Козлутин ассистент530220
Мартынов ассистент530220
Выразительность уже описанных операторов позволяет написать весьма сложные условия. Опишите словами, например, следующий запрос:
SELECT Name
FROM TEACHER
WHERE (LOWER(Post) = 'профессор* OR Tel = *2661247*) AND (Salary < 650 OR Rise < 200 ) AND
NOT (UPPER(Name) <> 'ИВАНОВ* AND UPPER(Name) <> 'ГУСАК');
Использование выражений над столбцами
До сих пор в выражениях фразы WHERE мы использовали в качестве значения одного или обоих аргументов имена столбцов. Однако аргументами могут быть и выражения над столбцами.
Запрос. Показать фамилии преподавателей, чья зарплата (ставка плюс надбавка) превышает 1500.
SELECT NameAS "Фамилия преподавателя".
Salary + Rise AS "Его зарплата"
FROM TEACHER
WHERE Salary + Rise > 1500;
Фамилия преподавателя Его зарплата
Сидоров1540
Резван1570
Ахромеев1550
Запрос. Показать фамилии преподавателей, половина зарплаты которых превышает троекратную надбавку.
SELECT Name
FROM TEACHER
WHERE (Salary + Rise) / 2 > 3 * Rise;
строки не выбраны
В учебной базе данных таких преподавателей не оказалось.
Использование специальных операторов
В SQL имеются операторы сравнения, позволяющие проверять значения столбцов и выражений над ними на соответствие некоторым специальным условиям:
О принадлежность множеству;
О принадлежность диапазону;
О соответствие шаблону:
О соответствие регулярному выражению;
О неопределенное значение.
В этом разделе вы узнаете, как их использовать и как с их помощью создавать составные условия.
Проверка на принадлежность множеству
Оператор IN позволяет проверить, входит ли значение в указанное множество значений. В простейшем случае этот оператор имеет следующий синтаксис:
имя_столбца [NOT] IN (список_значений)
Здесь список значений представляет собой перечень разделенных запятыми констант, тип которых должен соответствовать типу столбца, чье имя приведено слева. Семантика этого предиката такова: он принимает значение TRUE, если значение столбца соответствует одной из констант списка. Приведем пример.
Запрос. Вывести типы занятий, проводимых на первой неделе в первые три дня.
SELECT DISTINCT Type AS "Тип занятия"
FROM LECTURE
WHERE WEEK = 1 AND LOWER(Day) IN ('пнд', 'втр', 'срд'):
Тип занятия
лаб
лекц
Отметим, что оператор IN в варианте с константами в правой части имеет эквивалентное представление с использованием логической связки OR. Так, предыдущий запрос может быть выражен следующим образом:
SELECT DISTINCT Type AS "Тип занятия"
FROM LECTURE
WHERE LOWER(Day)= 'пнд* OR LOWER(Day)= 'втр' OR LOWER(Day)= 'срд1;
Запрос. Вывести названия и номер корпуса кафедр, расположенных в корпусах 1, 3, 8 и 10.
SELECT Name. Building
FROM Department
WHERE Building IN (T', '3'. ’8’. *10');
NAMEBUILDING
интернет3
теория языков 3
лингвистика 3
Использование отрицания
Так как предикат IN возвращает истинностное значение, к нему можно применить логическое отрицание. Для этого следует воспользоваться нотацией NOT IN. В этом случае предикат будет истинным, если значение столбца не входит в указанный список.
Запрос. Вывести названия и номер корпуса кафедр, расположенных в любых корпусах, кроме 1, 3, 8 или 10.
SELECT Name AS "Название кафедры". Building AS "Корпус"
FROM Department
WHERE Building NOT IN (T, '3'. '8'. '10');
Название кафедры Корпус
базы данных6
программирование б базы данных5
Отметим, что нотация NOT IN введена в язык специально, так как, следуя общему принципу применения оператора NOT, можно использовать и такую конструкцию:
ПРИМЕЧАНИЕПРИМЕЧАНИЕNOT (имя_столбца IN (список_значений))
ПРИМЕЧАНИЕ
ПРИМЕЧАНИЕ
Внешние скобки здесь необязательны, так как операторы сравнения (а к ним относится и IN) имеют больший приоритет, чем логические связки. Однако мы рекомендуем их ставить для придания выражению большей наглядности.
Запрос. Вывести номера групп всех курсов, кроме первого и второго.
SELECT Num, Year
FROM SGROUP
WHERE NOT (Year IN (1, 2));
NUM YEAR
4084
5055
5045
3073
Использование выражений над столбцами
В левой части оператора IN вместо имени столбца можно использовать любое допустимое над столбцами таблицы выражение языка.
Запрос. Вывести фамилии преподавателей, зарплата которых (ставка + надбавка) равна 800, 900, 1000, 1100 или 1200.
SELECT Name AS "Фамилия преподавателя". Salary + Rise AS "Зарплата преподавателя"
FROM TEACHER
WHERE Salary + Rise IN (800, 900, 1000, 1100, 1200);
Фамилия преподавателя Зарплата преподавателя
12001200Рамишевский
1200
1200
900900800900900800Хоренко Кузинцев Недеведеев
900
900
800
900
900
800
Более того, элементами списка в правой части оператора IN тоже могут быть выражения над столбцами, как это показано в следующем примере:
SELECT Name, Salary, Salary + Rise
FROM TEACHER
WHERE Salary + Rise IN (Salary + 100, Salary + 200, Salary + 300, Salary + 400, Salary + 500);
Список значений может быть определен даже спецификацией нового запроса. Этот более сложный вариант предиката IN мы рассмотрим в уроке 7 при описании механизма вложения одних запросов в другие.
Использование неопределенного значения
Если среди значений в списке оператора NOT IN имеется неопределенное значение (NULL), то независимо от значения столбца он будет возвращать логическое значение UNKNOWN. Это значит, что в результирующую таблицу не будут включены никакие строки исходной таблицы. Рассмотрим пример.
Запрос. Показать факультеты, не располагающиеся в корпусах 1 или 3.
SELECT Name, Building
FROM FACULTY
WHERE Building NOT IN (T. '3');
NAME BUILDING
информатика 6 кибернетика 5
Этот запрос, как видно, возвращает две строки. Однако если один из элементов списка принимает неопределенное значение (в том числе как значение выражения), запрос не выдаст ни одной строки, независимо от содержания таблицы FACULTY:
SELECT Name, Building
FROM FACULTY
WHERE Building NOT IN (T, '3'. NULL);
Понятно, что вы не будете специально вставлять NULL в список значений, но будьте внимательны, когда для его получения используется подзапрос. Описанная ситуация характерна только для нотации NOT IN — на результат предиката IN наличие в его списке неопределенных значений не влияет.
Запрос. Показать факультеты, располагающиеся в корпусах 1 или 3.
SELECT Name, Building
FROM FACULTY
WHERE Building IN (T, '3', NULL);
NAME BUILDING
математика 3
ПРИМЕЧАНИЕПРИМЕЧАНИЕ
ПРИМЕЧАНИЕ
ПРИМЕЧАНИЕ
Объяснение этому дается в уроке 10, где рассмотрено использование в SQL неопределенного значения.
Проверка на принадлежность диапазону значений
Еще одной формой проверки вхождения элемента во множество является проверка на его принадлежность диапазону значений. Для этого применяется предикат BETWEEN, который определяет нахождение значения столбца между указанными минимальным и максимальным значениями. Синтаксис предиката следующий:
имя_столбца [NOT] BETWEEN минимум AND максимум
Проверять можно значения числовых, строковых и временных типов (для строк символов предполагается алфавитное упорядочение). Оператор BETWEEN является включающим - это означает, что крайние значения диапазона включаются в допустимые.
Запрос. Вывести фамилии преподавателей со ставкой в диапазоне 600-800.
SELECT Name
FROM TEACHER
WHERE Salary BETWEEN 600 AND 800;
NAME
Хоренко
Кузинцев
Завратинский
Наумов
Предикат BETWEEN эквивалентен применению двух предикатов сравнения - приведенный выше запрос может быть представлен, например, в таком виде:
SELECT Name
FROM TEACHER
WHERE Salary >= 600 AND Salary <= 800:
Если из диапазона нужно исключить крайние значения, задайте для этого дополнительные условия. Ниже приводятся три возможных варианта записи одного и того же запроса:
SELECT Name
FROM DEPARTMENT
WHERE Fund BETWEEN 11000 AND 15000 AND
Fund <> 11000 AND Fund <> 15000:
SELECT Name
FROM DEPARTMENT
WHERE Fund BETWEEN 11000 AND 15000 AND
Fund NOT IN (11000, 15000):
SELECT Name
FROM DEPARTMENT
WHERE Fund > 11000 AND Fund < 15000:
Как видим, запрос без оператора BETWEEN (третий вариант) является наиболее лаконичным.
ПРИМЕЧАНИЕ Если значение в столбце имеет точный числовой тип, можно просто
сузить диапазон.
Использование строковых значений
Использование в операторе BETWEEN в качестве границ диапазона строковых значений имеет особенности, связанные с упорядочением (это же относится и к другим операторам сравнения).
Запрос. Вывести фамилии преподавателей, начинающиеся на буквы от «3» до «Л».
SELECT Name
FROM TEACHER
WHERE UPPER(Name) BETWEEN '3' AND 'Л':
NAME
Кузинцев
Завратинский
Козлутин
Среди строк результата нет фамилий, начинающихся на букву «Л», хотя мы знаем, что одна такая существует. Дело в том, что при сравнении строк символов разной длины SQL предварительно дополняет более короткую строку символами пробела, а он в упорядочениях символов предшествует всем остальным. Поэтому строка, состоящая из буквы «Л» (дополненная пробелами), всегда будет меньше любой другой строки, в которой за начальной буквой «Л» следуют отличающиеся от пробела символы.
Чтобы это учесть, в качестве верхнего значения диапазона лучше всего указывать следующую по алфавиту букву (в данном случае — «М»). Приведем исправленный запрос, оставив неизменным его описание.
SELECT Name
FROM TEACHER
WHERE UPPER(Name) BETWEEN ’3' AND 'M';
NAME
Кузинцев Завратинский
Козлутин Лекарь
ПРИМЕЧАНИЕ Обратите внимание на то, что в зависимости от СУБД и операционной
системы возможны различные упорядочения прописного и строчного варианта букв. Чтобы избежать этого влияния на результат сравнения, используйте преобразование строчных букв в прописные (или наоборот).
Использование отрицания
Так как предикат BETWEEN возвращает истинностное значение, к нему можно применить логическое отрицание. Для этого следует воспользоваться нотацией NOT BETWEEN, в которой предикат будет истинным, только если значение столбца не входит в указанный диапазон. Представление отрицания нотацией NOT BETWEEN
введено в язык для большей наглядности, так как с предикатом BETWEEN можно стандартным образом использовать логический оператор NOT (то есть ставить отрицание ко всему выражению, а не к предикату):
NOT (имя_столбца BETWEEN минимум AND максимум)
Круглые скобки в данном случае можно и опустить, так как они не меняют порядка исполнения операторов. В нотации NOT BETWEEN крайние значения в диапазон не включаются.
Запрос. Вывести названия и номер корпуса кафедр, которые не расположены в корпусах 1, 2 и 3.
SELECT Name. Building
FROM DEPARTMENT
WHERE Building NOT BETWEEN T AND '3';
SELECT Name, Building
FROM DEPARTMENT
WHERE NOT (Building BETWEEN T AND '3*):
NAMEBUILDING5
базы данных .6 программирование 6 базы данных5
Использование выражений над столбцами
Как и в предикате IN, вместо имени столбца и границ диапазона можно использовать любое допустимое в языке выражение над столбцами таблицы, включая и функции.
Запрос. Показать фамилии преподавателей, принятых на работу между 01.01.2000 и 12.12.2001.
SELECT Name, Hi reDate
FROM TEACHER
WHERE HireDate BETWEEN TO_DATE(’01/01/2000'. 'DD/MM/YYYY') AND
TO_DATE('12/12/2001', 'DD/MM/YYYY');
NAME HIREDATE
Хоренко 10.10.2001
Козлутин 04.07.2001
Резван 11.11.2000
Запрос. Вывести данные преподавателей, зарплата которых (ставка + надбавка) находится в диапазоне от удвоенной величины надбавки до утроенной надбавки плюс 50.
SELECT Name, Salary + Rise, 2 * Rise, 3 * Rise + 50.
FROM TEACHER
WHERE Salary + Rise BETWEEN 2 * Rise AND 3 * Rise + 50;
NAME SALARY+RISE 2*RISE 3*RISE+50
Лекарь13308801370
Ахоомеев155010001550
Использование неопределенного значения
В стандарте SQL определены следующие правила обработки значения NULL в операторе BETWEEN:
О если проверяемое выражение или обе границы диапазона равны NULL, результат равен UNKNOWN;
О если проверяемое выражение и верхняя граница диапазона не равны NULL, а нижняя граница диапазона равна NULL, результат равен FALSE, когда проверяемое выражение больше верхней границы, и UNKNOWN — в остальных случаях;
О если проверяемое выражение и нижняя граница диапазона не равны NULL, а верхняя граница диапазона равна NULL, результат равен FALSE, когда проверяемое выражение меньше нижней границы, и UNKNOWN — в остальных случаях.
Таким образом, если в операторе BETWEEN где-либо встретится неопределенное значение, строки в результирующую таблицу включены не будут. В этом случае нужно использовать предикат NOT BETWEEN, как это показано в следующих примерах.
SELECT Num. Rating
FROM SGROUP
WHERE Rating NOT BETWEEN NULL AND 50;
NUM RATING
40856
50567
50455
SELECT Num. Rating
FROM SGROUP
WHERE Rating NOT BETWEEN 50 AND NULL;
NUM RATING
30748
20143
Первый запрос, по сути, отбирает группы с рейтингом больше 50, а второй — меньше 50.
Проверка на соответствие шаблону
Когда необходимо отобрать строки таблицы, в которых значение некоторого столбца совпадает с заданной строкой символов, следует использовать обычное сравнение, как это показано выше. Однако во многих случаях можно не знать точное представление в базе данных интересующего значения. Название одной и той же кафедры, например, может храниться в одном из следующих вариантов: О базы данных;
О организация баз данных;
О информационные системы и базы данных;
О базы данных и знаний.
Такая же ситуация возникает, когда не известно точное написание фамилии преподавателя, название дисциплины, факультета и т. п. Специально для таких слу-
чаев предназначен оператор сравнения LIKE, позволяющий отобрать из таблицы строки на основе частичного соответствия. Упрощенный синтаксис оператора следующий:
имя_столбца [NOT] LIKE шаблон [ESCAPE символ_пропуска]
Его можно использовать только с символьными значениями.
Использование шаблона
Оператор LIKE сравнивает значение столбца с множеством значений, определяемых шаблоном. Он представляет собой строку, в которой помимо обычных символов, составляющих основу поискового выражения, можно использовать так называемые подстановочные символы (иногда они называются групповыми символами). Имеется всего два подстановочных символа, различающихся тем, что именно на их месте может стоять:
% — любая последовательность символов, включая их отсутствие;
_ — один любой символ.
Подстановочные символы могут находиться в любом месте шаблона в любом наборе. Например, шаблону 'ЖИванЖ' соответствуют строки 'Иван', 'Иванов', 'Иванченко', 'Петр Иванович', а шаблону 'л_с_* - 'лист', 'леса*, 'лоск' (ноне 'лес', 'листок', 'плес').
Оператор LIKE, как и все другие, работающие с символьными строками, чувствителен к регистру букв, поэтому при его использовании мы рекомендуем использовать уже известные вам функции UPPERO и LOWER0.
Запрос. Найти фамилии преподавателей на букву «Н».
SELECT Name
FROM TEACHER
WHERE UPPER(Name) LIKE 'НЖ1:
NAME
Недеведеев
Наумов
Имейте в виду, что если вы запишете условие фразы WHERE как UPPER(Name) = 'НГ или даже как 'НЖ' LIKE UPPER(Name), фамилии преподавателей будут сравниваться со строкой ' НЖ'. Во втором случае выражение является синтаксически правильным оператором LIKE, однако в нем строка 'НЖ' не выступает в качестве шаблона, так как расположена перед ключевым словом LIKE.
Запрос. Указать преподавателей, в фамилиях которых первой буквой является «В», а третьей — «р».
SELECT Name
FROM TEACHER
«RE Name LIKE 'В_рЖ*:
NAME
Вооопаев
Запрос. Вывести названия кафедр, в которых присутствует словосочетание «база данных» (в различных грамматических формах).
SELECT Name
FROM DEPARTMENT
WHERE LOWERCName) LIKE ’ЖбазХданныГ;
NAME
базы данных
базы данных
В левой части оператора LIKE может находиться не только имя столбца, но и любое допустимое над столбцами выражение, как это показано в следующем примере.
Запрос. Указать преподавателей, в фамилию и название должности которых входит в сумме не меньше четырех букв «о».
SELECT Name, Post
FROM TEACHER
WHERE LOWERCName || Post) LIKE 'МоМоГ:
NAME POST
Сидоров профессор
Использование символа пропуска
Если с помощью оператора LIKE необходимо найти строки, в которые входят сами символы % или _, следует использовать так называемый символ пропуска (который называется также эскейп-символом). Поставив его в шаблоне перед символами % или _, вы укажете, что их не следует рассматривать как подстановочные. Символ пропуска указывается во фразе ESCAPE.
Запрос. Вывести данные кафедр, в названиях которых присутствует строка «си- стем_управл».
SELECT *
FROM DEPARTMENT
WHERE LOWERCName) LIKE 'кжтем^УправлГ ESCAPE 'V;
строки не выбраны
Здесь во фразе ESCAPE в качестве символа пропуска указана обратная косая черта. Ее наличие в шаблоне перед символом подчеркивания заставляет рассматривать его как обычный символ.
Запрос. Вывести данные факультетов, в названиях которых имеется символ подчеркивания.
SELECT *
FROM FACULTY
WHERE Name LIKE 'Г?_Г ESCAPE *?*;
строки не выбраны
Чтобы в шаблоне как обычный рассматривался сам символ пропуска, его следует поставить два раза. Например, в следующем запросе:
SELECT Name
FROM DEPARTMENT
WHERE Name LIKE 'XI3IIV ESCAPE V;
отыскиваются те кафедры, в названии которых имеются символы _ и / (причем в указанном порядке).
Если значение левой части предиката LIKE равно NULL, он принимает истинностное значение UNKNOWN, и соответствующая строка не будет включена в результирующую таблицу.
Проверка на соответствие регулярному выражению
Существенным расширением предиката LIKE является предикат SIMILAR ТО, в котором используется идея регулярных выражений, известная по инструментам операционных систем, и прежде всего UNIX. Синтаксис предиката SIMILAR ТО следующий:
строковое_выражение [NOT] SIMILAR ТО регулярное_выражение [ESCAPE символ_пропуска]
Этот предикат принимает значение TRUE, если строковое выражение соответствует регулярному выражению. В простейшем случае регулярное выражение является обычной строкой (например, ' Иванов1) или строкой с подстановочными символами $ и _, имеющими тот же смысл, что и в предикате LIKE. Однако возможности регулярных выражений намного шире. Рассмотрим их, последовательно переходя от простого к сложному.
Элементарным понятием регулярного выражения является перечисляемый_символ. Он может быть трех видов.
О обычный_символ - любой символ, допустимый в символьной строке. Обычный символ в регулярном выражении сопоставляется в проверяемой строке с ним самим.
О диапазоН-Символов - задается в виде [обычный_символ-обычный_символ]. Это выражение сопоставляется с любым символом из указанного диапазона.
О указатель_класса_символов - множество символов, обладающих определенным свойством. Указатель класса символов сопоставляется с любым символом своего класса, которые перечислены в табл. 3.4.
Таблица 3,4. Классы символов
Обозначение
Описание
[:ALPHA:]
[:LOWER:]
[:UPPER:] [:DIGIT:] [:ALNUM:]
[:SPACE:] [:WHITESPACE:]
Алфавитные символы
Строчные алфавитные символы
Прописные алфавитные символы
Цифровые символы
Алфавитно-цифровые символы
Символ пробела
Пробельные символы (горизонтальная и вертикальная табуляции, возврат каретки, перевод строки, подача формы)
Приведем примеры перечисляемых символов каждого рода:
'А''[2-ж]''[.-UPPER:]'
Следующее важное понятие - регулярный_набор_символов, который включает:
О [список_перечисляемых_символов] - сопоставляется с любым символом списка;
О [Асписок_перечисляемых_символов] - сопоставляется с любым символом, кроме тех, которые приведены в списке;
О [список_перечисляемых_символовАсписок_перечисляемых_символов] - сопоставляется с любым символом из первого списка, но за исключением символов из второго списка;
О _ — сопоставляется с одним любым символом.
Ниже указаны примеры регулярных наборов символов:
'оае' 'Е^прст]' '[дтр^лгт]' 'Еетру-х]' '[дор[:DIGIT:]]'
Первичное регулярное выражение включает следующие составляющие:
О обычный-СИмвол — сопоставляется именно с этим символом;
О регулярный_набор_символов — определен выше;
О (регулярное выражение) — круглые скобки группируют подвыражение, чтобы оно рассматривалось как единое целое при использовании операторов альтернативы или квантификации;
ОХ- сопоставляется с последовательностью из 0 или более символов.
Примеры первичного регулярного выражения:
'а' Т '[a-o[:ALNUM:][:DIGIT:]]''([апетА1234]*)'
Регулярный множитель - это либо первичное регулярное выражение само по себе, либо вместе со следующим за ним оператором квантификации, который указывает, сколько раз может повторяться предшествующее первичное регулярное выражение:
*
0 и более раз;
(т)
точно т раз;
+
1 и более раз;
(т.)
минимум т раз;
7
0 или 1 раз;
(т.п)
минимум т раз, но не более п раз.
Последние три оператора квантификации называются еще операторами повторения. Приведем примеры регулярных множителей:
'(a?)*' '([a-o[:ALNUM:]])+'’[:DIGIT:](6)' ’[: ALPHA:](1.30)’
Последовательность из одного или более регулярных множителей называется регулярный терм. Например:
'2а?б?_(13)+Г'[:ALPHA:](2)[:DIGIT:](6)’
Наконец, можно определить само регулярное выражение — это либо регулярный терм, либо два регулярных выражения, разделенных оператором альтернативы (|), который сопоставляет с проверяемой строкой либо регулярное выражение слева, либо регулярное выражение справа. Например, следующее регулярное выражение сопоставляется с различными названиями стандартов SQL:
’(SQL-(89|92|99|2003))|(SQL(1|2|3))'
В предикате SIMILAR ТО может также использоваться фраза ESCAPE, которая здесь имеет тот же смысл, что и в предикате LIKE. Рассмотрим примеры использования предиката SIMILAR ТО.
Запрос. Указать кафедры, в названии которых имеется слово, начинающееся на букву «т» и заканчивающееся буквами «ия».
SELECT *
FROM DEPARTMENT
WHERE LOWER(Name) SIMILAR TO '(t[:ALPHA:]*ия)|
([:ALPHA: ]+[:SPACE: ]t[ -.ALPHA: ]*ия) |
(t[:ALPHA:]*ия[:SPACE:][:ALPHA:]+)|
([ :ALPHA:]+[:SPACE:]t[-.ALPHA: ]*ия[ :SPACE: ][ :ALPHA: ]+)'
DEPPK FACFK NAMEHEAD BUILDING FUND
42 теория языков Глущенко 310000
В этом запросе мы указали на четыре возможных варианта:
О название кафедры состоит из одного необходимого слова;
О в названии кафедры такое слово не одно, и стоит в конце;
О в названии кафедры такое слово не одно, и стоит в начале;
О в названии кафедры такое слово не одно, и стоит в середине.
Проверка на неопределенное значение
Как мы уже отмечали, наличие значения NULL во фразе WHERE приводит к тому, что условие принимает истинностное значение UNKNOWN и соответствующая строка не включается в результат. Детальное описание работы с неопределенным значением вы можете найти в уроке 10, а здесь мы покажем, как обрабатывать значение NULL во фразе WHERE.
Чтобы проверить столбец на неопределенное значение, следует применить унарный оператор IS NULL, имеющий такой синтаксис:
имя_столбца IS [NOT] NULL
Этот оператор принимает истинностное значение TRUE, если столбец имеет неопределенное значение, и FALSE — в противном случае. В нотации IS NOT NULL его действие обратное.
Запрос. Вывести фамилии преподавателей, у которых не задан номер телефона или идентификационный код.
SELECT Name, IDCode, Tel
FROM TEACHER
WHERE IDCode IS NULL OR Tel IS NULL:
NAMEIDCODE TEL
Сидоров0123456789
Хоренко1234567890
Вибровский2345678901
Воропаев
Завратинский 3456789012
Резван1234567
12345672345678234567834567891234567234567823456783456789Недеведеев Ахромеев Наумов Дараганов
1234567
2345678
2345678
3456789
1234567
2345678
2345678
3456789
Запрос. Вывести фамилии преподавателей, у которых задан номер телефона, но не задан идентификационный код.
SELECT Name. IDCode. Tel
FROM TEACHER
WHERE IDCode IS NULL AND Tel IS NOT NULL:
NAME IDCODE TEL
Резван1234567
Недеведеев1234567
Ахромеев2345678
Наумов2345678
Дараганов3456789
Запрос. Вывести фамилии преподавателей, у которых задан и номер телефона, и идентификационный код.
SELECT Name. IDCode. Tel
FROM TEACHER
WHERE IDCode IS NOT NULL AND Tel IS NOT NULL:
NAME IDCODE TEL
Рамишевский 45678901234567890
Кузинцев56789012344567890
Козлутин67890123451234567
Лекарь34567890121234567
Мартынов78901234561234567
Самостоятельная работа
Выведите фамилии и ставки ассистентов.
Выведите фамилии и должности преподавателей, которые не являются профессорами.
Выведите фамилии и номера телефонов преподавателей, которые были приняты на работу до 01.01.2000.
Выведите названия кафедр, которые в алфавитном порядке располагаются перед кафедрой «программирование». Выводимый столбец должен иметь имя Название кафедры.
Выведите фамилии ассистентов, имеющих зарплату (ставка + надбавка) не более 1200.
Выведите номера групп 5 курса, имеющих рейтинг в диапазоне 40-80.
Выведите фамилии всех ассистентов со ставкой меньше 550 или надбавкой меньше 200.
Выведите фамилии доцентов с зарплатой (ставка + надбавка) в диапазоне 1100-1300.
Выведите типы лекций, которые имеются в расписании на среду, четверг и пятницу.
Выведите названия кафедр, содержащих слово «интернет» или буквы «мм».
Выведите фамилии преподавателей, у которых не задан номер телефона и идентификационный код.
Подведение итогов
Усвоив материал этого урока, вы научились:
0 формулировать условия с использованием операторов сравнений;
0 использовать логические операторы;
0 строить условия с использованием выражений над столбцами;
0 использовать оператор IN для проверки принадлежности множеству;
0 использовать оператор BETWEEN для проверки принадлежности диапазону;
0 использовать оператор LIKE для проверки на соответствие шаблону;
0 использовать оператор SIMILAR ТО для проверки на соответствие регулярному выражению;
0 использовать оператор IS NULL для проверки на неопределенное значение.
(К) УРОК(К) УРОКМноготабличные запросыМноготабличные запросы
(К) УРОК
(К) УРОК
Многотабличные запросы
Многотабличные запросы
При проектировании стремятся создавать таблицы, в каждой из которых содержалась бы информация об одном и только одном типе сущности. Это облегчает модификацию базы данных и поддержку ее целостности. Именно так мы поступили, создавая учебную базу данных. Однако сущности могут быть взаимосвязанными. Кафедры связаны с факультетами по признаку вхождения в их состав, преподаватели работают на кафедрах, группы принадлежат кафедрам и т. д. Связь между таблицами устанавливается за счет размещения специального столбца первичного ключа одной таблицы, которая называется родительской, в другой таблице, которая называется дочерней. Столбец (или совокупность столбцов) дочерней таблицы, определенный для связи с родительской таблицей, называется внешним ключом. Так, например, таблица кафедр содержит столбец FacFK, который для каждой строки кафедры содержит значение первичного ключа того факультета, которому принадлежит кафедра. Наличие внешних ключей является основной для инициирования поиска по многим таблицам.
Одна из наиболее важных особенностей предложения SELECT — это способность использования связей между различными таблицами, а также вывода содержащейся в них информации. Операция, которая приводит к соединению из двух таблиц всех пар строк, для которых выполняется заданное условие, называется соединением таблиц. Для того чтобы указать соединяемые таблицы, их следует перечислить через запятую во фразе FROM.
Декартово произведение таблиц
Соединение таблиц - это частный случай операции декартового произведения (или просто произведения'). Декартово произведение двух таблиц — это таблица, состоящая из всех возможных пар строк обеих таблиц. Это определение можно естественным образом расширить на любое количество таблиц. В SQL декартово произведение выражается указанием имен перемножаемых таблиц во фразе FROM
и указанием всех их столбцов во фразе SELECT. Так, произведение таблиц FACULTY и DEPARTMENT выражается следующим образом:
SELECT *
FROM FACULTY, DEPARTMENT
Так как результирующая таблица содержит много столбцов и они не помещаются по ширине страницы, мы приведем только интересующие нас столбцы произведения этих таблиц.
Запрос. Декартово произведение таблиц.
SELECT FACULTY.Name, FACULTY.FacPK.
DEPARTMENT.FacFK, DEPARTMENT.Name
FROM FACULTY, DEPARTMENT:
NAME
FACPK FACFK NAME
информатика
1
1 базы данных
информатика
1
1 программирование
информатика
1
1 интернет
информатика
1
2 базы данных
информатика
1
2 лингвистика
информатика
1
2 теория языков
кибернетика
2
1 базы данных
кибернетика
' 2
1 программирование
кибернетика
2
1 интернет
кибернетика
2
2 базы данных
кибернетика
2
2 лингвистика
кибернетика
2
2 теория языков
математика
3
1 базы данных
математика
3
1 программирование
математика
3
1 интернет
математика
3
2 базы данных
математика
3
2 лингвистика
математика
3
2 теория языков
Каждая строка таблицы факультетов оказалась соединенной с каждой строкой таблицы кафедр, в результате получилось 18 строк (3 факультета х 6 кафедр = 18 комбинаций).
В произведении может участвовать много таблиц. Например, произведение таблиц факультетов, кафедр и преподавателей записывается следующим образом:
SELECT *
FROM FACULTY, DEPARTMENT, TEACHER
Если предположить, что в вузе имеется 15 факультетов, 100 кафедр и 1500 преподавателей, то результирующая таблица будет содержать более двух миллионов строк (15 х 100 х 1500 - 2 250 000), и это при таких незначительных размерах исходных таблиц. Будьте внимательными, не используйте декартового произведения, тем более что эта операция не имеет какой-либо вразумительной семантики (она используется в математике как некоторая абстракция, благодаря которой можно легко объяснять другие математические операции над множествами и отношениями), но через декартово произведение можно определить семантику операции соединения.
Условие соединения
Соединение таблиц может быть указано во фразе WHERE или во фразе FROM. Сначала рассмотрим первый вариант. Большинство запросов, имеющих несколько таблиц во фразе FROM, содержат фразу WHERE, в которой указаны условия, попарно сравнивающие столбцы из различных таблиц. Такое условие называется условием соединения. В этом случае SQL предполагает сцепление только тех пар строк из разных таблиц, для которых условие соединения принимает истинное значение. Теоретически при соединении сначала выполняется декартово произведение указанных таблиц в одну, а затем из нее отбираются строки согласно условию соединения. Естественно, ни одна СУБД не работает таким образом.
Фраза WHERE помимо условия соединения может также содержать другие условия, каждое из которых ссылается на столбцы соединенной таблицы. Эти условия производят отбор строк соединенной таблицы.
Соединение таблиц по равенству
Если таблицы соединяются по равенству значений пары столбцов (группы столбцов) из различных таблиц, такая операция называется соединением таблиц по равенству. Соединение по равенству, в отличие от декартового произведения, позволяет соединить только те пары строк, которые действительно взаимосвязаны друг с другом. Так, например, мы можем соединить таблицы факультетов и кафедр по условию FACULTY.FacPK = DEPARTMENT.FacFK. В таком варианте мы соединяем таблицы осмысленно, так как каждая строка таблицы FACULTY соединяется только со строками соответствующих кафедр. На базе таблиц FACULTY и DEPARTMENT мы получаем таблицу со столбцами из обеих таблиц, имеющую строки с понятным смыслом. Можно также сказать, что в таблицу DEPARTMENT вместо столбца FacFK мы вставляем все характеристики (столбцы) соответствующего факультета из таблицы FACULTY."
Соединение таблиц используется, когда необходимо вывести значения столбцов:
О разных таблиц;
О одной таблицы, но отвечающих условию, заданному на другой таблице.
Эти два варианта, а также их комбинация, характерны для любого вида соединения, а не только по равенству. Перейдем к рассмотрению примеров.
Вывод столбцов разных таблиц
Этот вид запросов характерен тем, что фраза WHERE содержит только условие соединения, а список фразы SELECT содержит имена столбцов из различных таблиц.
Запрос. Вывести названия кафедр и номера их групп.
SELECT Name, Num
FROM DEPARTMENT, SGROUP
WHERE DepPK = DepFK;
SELECT DEPARTMENT.Name, SGROUP.Num
FROM DEPARTMENT, SGROUP
WHERE DEPARTMENT.DepPK = SGROUP.DepFK;
NAMENUM
базы данных 307 базы данных 408 программирование 505 программирование 504 интернет 201
Мы привели два варианта запроса. В первом имена столбцов не уточняются именами таблиц, а во втором — уточняются. В данном случае это не имеет значения, оба запроса корректны.
Уточнение имен столбцов
До тех пор, пока запрос относится к одной таблице, обращение к столбцам по их именам не вызывает проблем - в таблице все имена столбцов должны быть неповторяющимися. Однако как только запрос соединяет несколько таблиц, может возникнуть неоднозначность при ссылках на столбцы с одинаковыми именами из разных таблиц. Для разрешения этой неоднозначности во фразах SELECT и WHERE (как и в некоторых других фразах) имена столбцов необходимо уточнять именами таблиц.
Запрос. Вывести названия факультетов и их кафедр.
SELECT FACULTY.Name, DEPARTMENT.Name
FROM FACULTY. DEPARTMENT
WHERE FACULTY.FacPK = DEPARTMENT.FacFK;
NAME NAME
информатика базы данных
информатика программирование*
информатика интернет кибернетика теория языков кибернетика лингвистика кибернетика базы данных
В этом запросе мы уточнили имена столбцов во фразах SELECT и WHERE, хотя во втором случае это не обязательно, так как используются неповторяющиеся имена. Тем не менее, рекомендуем при соединении таблиц для наглядности уточнять имена столбцов. Обратите внимание на то, что в предыдущем примере отсутствует факультет математики — на нем нет кафедр.
Вывод столбцов с условием отбора
Вариант, когда отбираются строки одной таблицы, а условие задается с участием другой, используется довольно часто. Приведем примеры.
Запрос. Вывести названия кафедр факультета информатики.
SELECT DEPARTMENT.Name AS "Кафедры факультета информатики"
FROM FACULTY. DEPARTMENT
WHERE FACULTY.FacPK = DEPARTMENT.FacFK AND
LOWER(FACULTY.Name) = 'информатика*:
Кафедры факультета информатики
базы данных
программирование
интернет
Запрос. Вывести фамилии преподавателей, являющихся кураторами групп 5 курса.
SELECT TEACHER.Name
FROM TEACHER. SGROUP
WHERE TEACHER.TchPK - SGROUP.CurFK AND
SGROUP.Year = 5;
NAME
Лекарь
Завратинский
Запрос. Вывести фамилии доцентов кафедры программирования.
SELECT TEACHER.Name AS "Доценты кафедры программиров."
FROM DEPARTMENT. TEACHER
WHERE DEPARTMENT.DepPK = TEACHER.DepFK AND
LOWER(DEPARTMENT.Name) = 'программирование* AND LOWER(TEACHER.Post) = 'доцент';
Доценты кафедры программиров.
Рамишевский
Завратинский
Лекарь
В последнем запросе помимо условия соединения используется также отбор строк по условиям, заданным для разных таблиц.
Синонимы таблиц
Синонимы таблиц часто используются для задания более лаконичного имени таблицы, по которому можно сослаться на нее в любых других местах запроса. Приведем пример.
Запрос. Вывести названия кафедр, на которых имеются группы с рейтингом более 50.
SELECT DISTINCT d.Name
FROM DEPARTMENT d. SGROUP g
WHERE d.DepPK = g.DepFK AND g.Rating > 50;
NAME
базы данных
программирование
Запрос. Вывести фамилии преподавателей, у которых есть занятия в понедельник.
SELECT DISTINCT t.Name
FROM TEACHER t, LECTURE 1
WHERE t.TchPK = l.TchFK AND LOWER(Day) = 'пнд';
NAME
Вибровский
Хоренко
Дараганов
Запросы по трем и более таблицам
SQL позволяет формулировать запросы, которые предполагают использование трех и более таблиц. При этом следует применять ту же методику соединения, что и для двух таблиц. Рассмотрим простой пример соединения трех таблиц.
Запрос. Вывести названия тех кафедр факультета информатики, на которых работают профессора.
SELECT DISTINCT DEPARTMENT.Name
FROM FACULTY, DEPARTMENT, TEACHER
WHERE FACULTY.FacPK = DEPARTMENT.FacFK AND
DEPARTMENT.DepPK = TEACHER.DepFK AND
LOWER(FACULTY.Name) = 'информатика' AND
LOWER(TEACHER.Post) = 'профессор':
NAME
программирование
Для ответа на запрос необходимы три таблицы: на таблицах факультетов и преподавателей заданы условия отбора, а из таблицы кафедр следует вывести столбец названий. Поэтому три необходимые таблицы указываются во фразе FROM, а во фразе WHERE производится их соединение по условию равенства первичного и внешнего ключей:
FACULTY.FacPK = DEPARTMENT.FacFK -- соединение таблиц факультетов и кафедр
DEPARTMENT.DepPK = TEACHER.DepFK -- соединение таблиц кафедр и преподавателей
Таблица, образующаяся в результате соединений, будет иметь столько же строк, сколько имеется в таблице преподавателей (если все преподаватели работают на кафедрах). Выясним, почему это так, но сначала заметим, что результат соединения таблиц не зависит от порядка соединения. Поэтому рассмотрим случай, когда сначала мы соединяем таблицы кафедр и преподавателей, а затем результат соединяем с таблицей факультетов.
Так как между таблицами кафедр и преподавателей существует связь типа один- ко-многим, их соединение фактически означает приписывание к строке каждого преподавателя данных о его кафедре. Количество строк этого соединения будет равным количеству преподавателей. Связь между таблицами факультетов и кафедр также имеет тип один-ко-многим, поэтому второе соединение означает, что к каждой строке таблицы, полученной после первого соединения, приписываются
данные о факультете кафедры. Таким образом, количество строк останется равным числу преподавателей.
Вернемся к запросу. Последние два условия фразы WHERE отбирают строки из соединенной таблицы, а во фразе SELECT указан выводимый столбец. Ключевое слово DISTINCT указано в нем потому, что названия кафедр в соединенной таблице могут повторяться.
Запрос. Вывести фамилии ассистентов факультета информатикк.
SELECT TEACHER.Name AS "Ассистенты ф-та информатики"
FROM FACULTY. DEPARTMENT, TEACHER
WHERE FACULTY.FacPK = DEPARTMENT.FacFK AND
DEPARTMENT.DepPK = TEACHER.DepFK AND
UPPER(FACULTY.Name) = 'ИНФОРМАТИКА' AND
UPPER(TEACHER.Post) = 'АССИСТЕНТ':
Ассистенты ф-та информатики
Вибровский
Воропаев
Козлутин
Мартынов
В этом сдучае для ответа нужны две таблицы — факультетов и преподавателей. Однако они связаны между собой опосредованно, через таблицу кафедр. Поэтому для соединения таблиц факультетов и преподавателей следует использовать таблицу кафедр.
Сформулируем общую процедуру составления многотабличного запроса и приведем пример ее использования.
Определить множество таблиц, необходимых для ответа на запрос. В это множество должны входить таблицы, на столбцах которых сформулированы условия, а также те, столбцы которых необходимо вывести. Это так называемые базовые таблицы запроса.
В структуре взаимосвязанных таблиц найти путь, соединяющий базовые таблицы. Это так называемый путь вычисления запроса. В результате вы получите перечень таблиц, необходимых для формулировки запроса. Это так называемые таблицы запроса.
Во фразе FROM перечислить необходимые таблицы.
Во фразе WHERE соединить таблицы запроса и при необходимости задать условия отбора строк в базовых таблицах запроса.
Во фразе SELECT перечислить выводимые столбцы.
Запрос. Вывести названия дисциплин, которые читаются доцентами на факультете информатики, с указанием фамилий доцентов.
Базовыми для этого запроса являются таблицы FACULTY, TEACHER и SUBJECT. Путь вычисления запроса помимо базовых включает также таблицы DEPARTMENT и LECTURE. Поэтому фраза FROM должна выглядеть следующим образом:
FROM FACULTY. DEPARTMENT. TEACHER. LECTURE. SUBJECT
Необходимо такое соединение таблиц:
FACULTY.FacPK = DEPARTMENT.FacFK AND
DEPARTMENT.DepPK - TEACHER.DepFK AND
TEACHER.TchPK = LECTURE.TchFK AND
LECTURE.SbjFK = SUBJECT.SbjPK
Условие отбора строк соединенной таблицы выглядит так:
LOWER(FACULTY.Name) - 'информатика* AND
LOWER(TEACHER.Post) * 'доцент*
Наконец, необходимо вывести значения двух столбцов:
SELECT SUBJECT.Name, TEACHER.Name '
Графическая схема запроса показана на рис. 4.1.
Name = 'информатика' — условие отбораName = 'информатика' — условие отбораPost = 'доцент' — условие отбора Name — столбец для выводаPost = 'доцент' — условие отбора Name — столбец для выводаName — столбец для выводаName — столбец для выводаРис. 4.1. Схема многотабличного запросаРис. 4.1. Схема многотабличного запроса
Name = 'информатика' — условие отбора
Name = 'информатика' — условие отбора
Post = 'доцент' — условие отбора Name — столбец для вывода
Post = 'доцент' — условие отбора Name — столбец для вывода
Name — столбец для вывода
Name — столбец для вывода
Рис. 4.1. Схема многотабличного запроса
Рис. 4.1. Схема многотабличного запроса
Полный текст запроса выглядит следующим образом:
SELECT DISTINCT SUBJECT.Name AS "Название дисциплины". TEACHER.Name AS "Фамилия преподавателя"
FROM FACULTY, DEPARTMENT, TEACHER. LECTURE, SUBJECT
WERE FACULTY.FacPK - DEPARTMENT.FacFK AND
DEPARTMENT.DepPK » TEACHER.DepFK AND
TEACHER.TchPK - LECTURE.TchFK AND
LECTURE.SbjFK - SUBJECT.SbjPK AND LOWER(FACULTY.Name) - 'информатика* AND LOWER(TEACHER.Post) = 'доцент*;
Название дисциплины Фамилия преподавателя
охрана труда Завратинский проектирование компьютеров Рамишевский теория алгоритмов Лекарь
Будьте внимательными при определении пути вычисления запроса. В базе данных может существовать несколько путей соединения — выясните, какой именно нужен вам в данном запросе.
Вывод всех столбцов соединяемой таблицы
В многотабличном запросе конструкция SELECT * означает выбор всех столбцов соединенной таблицы. Например, результирующая таблица следующего запроса состоит из 21 столбца: 5 столбцов таблицы факультетов, 6 столбцов таблицы кафедр и 10 столбцов таблицы преподавателей.
SELECT *
FROM FACULTY f. DEPARTMENT d. TEACHER t
WHERE f.FacPK = d.FacFK AND d.DepPK = t.DepFK;
При наличии в запросе многих таблиц конструкция SELECT * становится не очень практичной. В связи с этим в различных СУБД предоставляется возможность использовать во фразе SELECT многотабличных запросов выражение имя таблицы.* для указания вывода всех столбцов конкретной таблицы. Например:
SELECT ТА d.Fund, t.*
FROM FACULTY f, DEPARTMENT d. TEACHER t
WHERE f.FacPK = d.FacFK AND d.DepPK = t.DepFK;
Другие виды соединений no равенству
Логическая связь между таблицами поддерживается взаимосоответствием столб- цов первичного и внешнего ключей. Все рассмотренные до сих под запросы для соединения таблиц использовали именно эту связь. Однако SQL позволяет связывать таблицы по любой паре столбцов, которые имеют сравнимые типы данных, независимо от того, имеет ли эта связь какой-либо смысл. Рассмотрим ряд примеров.
Запрос. Если фонд финансирования кафедры совпадает с фондом финансирования какого-нибудь из факультетов, вывести название этой кафедры вместе с названием соответствующего факультета.
SELECT d.Name AS "Название кафедры".
f.Name AS "Название факультета"
FROM FACULTY f. DEPARTMENT d
WHERE f.Fund - d.Fund;
Название кафедры Название факультета
базы данных кибернетика
Запрос. Вывести пары названий факультетов и кафедр, у которых совпадают номера корпуса.
SELECT f.Name AS "Название факультета",
d.Name AS "Название кафедры"
FROM FACULTY f, DEPARTMENT d WHERE f.Building = d.Building;
Название факультета Название кафедры
математика математика математика кибернетика информатика информатикаматематика математика математика кибернетика информатика информатикаинтернет теория языков лингвистика базы данных базы данных , программирование
математика математика математика кибернетика информатика информатика
математика математика математика кибернетика информатика информатика
Запрос. Вывести пары названий кафедр и фамилий преподавателей, у которых совпадают первичные ключи.
SELECT d.Name AS "Название кафедры".
t.Name AS "Фамилия преподавателя" FROM DEPARTMENT d. TEACHER t WHERE d.DepPK = t.TchPK;
Название кафедры Фамилия преподавателя
теория языков Рамишевский программирование Хоренко
базы данных интернет лингвистика базы данных
Вибровский Воропаев Кузинцев Завратинский
Если первые два запроса не лишены смысла, то последний абсолютно бессмысленный, так как в учебной базе данных первичные ключи лишены какого-либо содержания и используются только для идентификации строк своих таблиц.
Соединение таблиц по неравенству
До сих пор мы соединяли таблицы по равенству двух столбцов, однако SQL позволяет для соединения таблиц использовать любое допустимое для сравнения столбцов условие. Рассмотрим ряд примеров.
Запрос. Вывести названия факультетов, фонд финансирования которых меньше фонда финансирования какой-нибудь из кафедр.
SELECT DISTINCT f.Name
FROM FACULTY f, DEPARTMENT d
WHERE f.Fund < d.Fund;
NAME
информатика
математика
Запрос. Вывести названия кафедр, номер корпуса которых больше номера корпуса какого-нибудь из факультетов.
SELECT DISTINCT d.Name
FROM FACULTY f. DEPARTMENT d
WHERE d.Building > f.Building;
NAME
базы данных
программирование
Запрос. Вывести названия кафедр, которые не расположены в одном корпусе с деканатом факультета информатики.
SELECT DISTINCT d.Name AS "Названия кафедр"
FROM FACULTY f. DEPARTMENT d
WHERE d.Bull ding <> f.Bull di ng AND
LOWER(f.Name) = 'информатика*:
Названия кафедр
базы данных лингвистика теория языков интернет
Как вы можете убедиться по приведенным примерам, соединения таблиц по условиям, отличающимся от равенства, во многом искусственны. Поэтому в подавляющем большинстве случаев таблицы соединяются по равенству, а условия по неравенству используются для дополнительного отбора строк.
Самосоединение таблицы
Как правило, взаимосвязи существуют и в пределах одной таблицы. В одних случаях эти связи являются явными, например, когда внешний ключ ссылается на первичный ключ той же самой таблицы (как в случае столбца CHIEF таблицы TEACHER). В других случаях эта связь присутствует неявно, например, кафедры могут быть связаны между собой на основании того свойства, что располагаются в одном корпусе.
Для ответа на такие запросы следует осуществлять соединение таблицы со своей копией. Такое соединение иногда называют самосоединением таблицы. Несмотря на кажущуюся искусственность идеи самосоединения таблиц, существует множество запросов, которые требуют именно такого соединения. На приводимых далее примерах вы убедитесь в этом.
Чтобы произвести соединение таблицы со своей копией, необходимо указать во фразе FROM имя одной и той же таблицы два или большее количество раз, а во фразе WHERE — условие их самосоединения.
Однако в этом случае возникает следующая проблема — как ссылаться на столбцы различных копий таблицы. До сих пор проблема ссылки на столбцы с одинаковыми именами из разных таблиц разрешалась уточнением имени столбца именем таблицы. В нашем же случае соединяемые таблицы имеют одинаковые имена. Для разрешения этой проблемы без синонимов таблиц уже не обойтись. В нашем случае различным вхождениям одной и той же таблицы приписываются различные синонимы и именно по этим синонимам производится обращение к столбцам. Приведем примеры использования самосоединения.
Запрос. Вывести номера групп, рейтинг которых превышает рейтинг группы 504 пятого курса.
SELECT searched.Num
FROM SGROUP given, SGROUP searched
WHERE given.Num = 504 AND given.Year = 5 AND searched.Rating > given.Rating;
NUM
408 • 505
Запрос. Вывести фамилии преподавателей, зарплата которых больше, чем у преподавателя Сидорова.
SELECT needed.Name
FROM TEACHER needed, TEACHER given
WHERE needed.Sal ary + needed.Rise > given.Sal ary + given.Rise AND UPPER(g1ven.Name) = 'СИДОРОВ*:
NAME
Резван
Ахромеев
Симметричное соединение и удаление избыточности
При самосоединении по равенству обычно возникают избыточные строки. Рассмотрим следующий запрос.
Запрос. Вывести названия кафедр, располагающихся в том же корпусе, что и кафедра лингвистики.
SELECT needed.Name
FROM DEPARTMENT needed, DEPARTMENT given
WHERE needed.Building = given.Building AND
UPPER(g1ven.Name) = 'ЛИНГВИСТИКА';
NAME
интернет теория языков лингвистика
Обратите внимание, что в результат включена и сама кафедра лингвистики. Для того чтобы избавиться от ненужной результирующей строки, следует добавить условие отбора:
UPPER(needed.Name) о 'ЛИНГВИСТИКА'
При самосоединении по равенству можно получить симметричную результирующую таблицу. Суть симметричности заключается в том, что в таблице содержатся строки:
О с одинаковыми значениями всех столбцов;
О со всеми возможными перестановками значений столбцов.
Запрос. Вывести пары номеров групп, которые принадлежат одной кафедре.
SELECT gl.Num. g2.Num, gl.DepFK
FROM SGROUP gl. SGROUP g2
WHERE gl.DepFK = g2.DepFK;
NUM NUM DEPFK
307 3071
408 3071
307 4081
408 4081
505 5052
504 5052
505 5042
504 5042
ПРИМЕЧАНИЕПРИМЕЧАНИЕ201 2013
ПРИМЕЧАНИЕ
ПРИМЕЧАНИЕ
В этом запросе мы дополнительно вывели столбец с номером (первичным ключом) кафедры для большей наглядности.
Результирующая таблица оказалась симметричной, и в связи с этим содержит избыточные строки — пару групп (307,307), строки с парами (307,408) и (408,307). Простой способ избежать этого состоит в том, чтобы наложить ограничение на выбираемые пары значений таким образом, чтобы первое выдаваемое значение было меньше другого (или предшествовало ему в алфавитном порядке). Это делает результат асимметричным, поэтому пары с одинаковыми значениями, а также пары, заданные в обратном порядке, не будут появляться. Покажем это на примере варианта предыдущего запроса.
Запрос. Вывести пары номеров групп, которые принадлежат одной кафедре, без избыточных строк.
SELECT gl.Num, g2.Num, gl.DepFK
FROM SGROUP gl, SGROUP g2
WHERE gl.DepFK = g2.DepFK AND gl.Num < g2.Num;
NUM NUM DEPFK
307 4081
504 5052
Проверка правильности данных
Самосоединение можно использовать для проверки корректности данных. Например, мы точно знаем, что в нашем вузе нет однофамильцев, занимающих разные должности. С помощью самосоединения таблицы преподавателей мы можем убедиться, что их нет и в базе данных.
Запрос. Указать преподавателей-однофамильцев, которые занимают различные должности.
SELECT tchl.Name AS "Препод, с различ. должностями"
FROM TEACHER tchl. TEACHER tch2
WHERE tchl.Name = tch2.Name AND tchl.Post <> tch2.Post;
строки не выбраны
В учебной базе данных таких преподавателей не оказалось. Значит, в этом отношении база данных правильная.
Самосоединениеи другие соединения
Таблица может соединяться одновременно со своей копией и другими таблицами. В некоторых случаях вызывает затруднение как представление такого запроса в SQL, так и его анализ, если он написан другим человеком. Рассмотрим один подобный пример.
Запрос. Вывести пары преподавателей, которые читают одинаковые дисциплины в один и тот же день с указанием дисциплины и дня.
SELECT DISTINCT tl.Name AS ФИО_1, t2.Name AS ФИ0_2,
s.Name AS Предмет, 11.Day AS День
FROM LECTURE 11, LECTURE 12. TEACHER tl. TEACHER t2. SUBJECT s
WHERE ll.SbjFK = 12.SbjFK AND
LOWER(ll.Day) = L0WER(12.Day) AND
Il.TchFK = tl.TchPK AND 12.TchFK = t2.TchPK AND
ll.SbjFK = s.SbjPK AND tl.Name < t2.Name;
ФИО-1ФИ0_2ПРЕДМЕТДЕНЬ
Вибровский Хоренкооперационныесистемыпнд
ВоропаевРамишевскийпроектирование компьютеров втр
КузинцевМартыновбазы данныхсрд
Основная конструкция запроса — соединение таблицы LECTURE со своей копией по равенству номера предмета (11.SbjFK = 12 „ Sbj FK) и ограничение результата по равенству дней в обеих таблицах (LOWER( 11.Day) = LOWER( 12.Day)).
Если бы нужно было вывести не фамилии преподавателей и названия преподаваемых ими дисциплин, а только соответствующие первичные ключи, не нужно было бы указывать во фразе FROM таблицы TEACHER и SUBJECT, а также соединять их с таблицами лекций. В этом случае мы просто указали бы во фразе SELECT вывод столбцов ключей, а именно: Il.TchFK, 12.TchFK и ll.SbjFK. Но для того чтобы указать в результирующей таблице именно фамилии и названия, следует проложить путь к таблицам, где они содержатся (TEACHER и SUBJECT) — вот почему эти таблицы указаны во фразе FROM и соединяются с таблицей LECTURE в третьей и четвертой строках фразы WHERE.
Наконец, в пятой строке фразы WHERE мы делаем запрос (и его результирующую таблицу) асимметричным.
Запросы к иерархической структуре данных
В таблице преподавателей имеется столбец Chi ef, который ссылается на первичный ключ этой же таблицы. Таким образом, на одной таблице мы задали многоуровневую иерархическую структуру данных. В данном случае это иерархия подчинения, хотя таким же образом можно строить иерархию родословной или любую другую. SQL с помощью самосоединения таблицы позволяет выражать некоторые виды запросов к иерархической структуре. Приведем примеры.
Запрос. Вывести фамилии всех преподавателей, непосредственно подчиненных Сидорову.
SELECT sub.Name AS "Подчиненные Сидорова"
FROM TEACHER boss. TEACHER sub
WHERE UPPER(boss.Name) = 'СИДОРОВ* AND boss.TchPK = sub.Chief:
Подчиненные Сидорова
Рамишевский
Завратинский
Лекарь
Резван
Здесь мы используем столбец Chief, который указывает на руководителя преподавателя. Можно произвести тройное самосоединение таблицы преподавателей, например, для вывода фамилий подчиненных подчиненным Сидорова.
Запрос. Вывести фамилии преподавателей, которые непосредственно подчиняются тем преподавателям, которые являются непосредственными подчиненными Сидорова.
SELECT subSub.Name AS "Подчинен, подчиненных Сидорова"
FROM TEACHER boss, TEACHER sub. TEACHER subSub
WHERE UPPER(boss.Name) = 'СИДОРОВ* AND
boss.TchPK = sub.Chief AND sub.TchPK = subSub.Chief:
Подчинен, подчиненных Сидорова
Хоренко Воропаев Кузинцев Козлутин
Недеведеев
Для иерархической структуры можно формулировать множество видов запросов, например:
О найти всех подчиненных конкретного лица;
О найти всех подчиненных самого нижнего уровня иерархии;
О для конкретного лица найти всех его руководителей, вплоть до руководителя самого верхнего уровня.
В уроке 10 мы вернемся к рассмотрению возможностей SQL по работе с иерархическими структурами данных и познакомимся с рекурсивными запросами.
Внешнее соединение таблиц
Предположим, необходимо вывести список факультетов и их кафедр. Это достигается соединением таблиц FACULTY и DEPARTMENT по равенству значений первичного и внешнего ключей и выбором столбцов с названиями факультетов и кафедр. Но в таком случае, если на факультете кафедр нет, он не будет включен в результат.
Для того чтобы в списке присутствовали все факультеты, даже без кафедр, необходимо использовать внешнее соединение, которое расширяет возможности обычного соединения. Внешнее соединение возвращает строки, которые удовлетворяют
условию соединения, а также те строки одной из таблиц, для которых в другой не нашлось удовлетворяющих условию соединения строк. В Oracle синтаксис внешнего соединения имеет следующие два варианта:"
таблица.столбец оператор_сравнения таблица.столбец (+)
таблица.столбец (+) оператор_сравнения таблица.столбец
Когда в результат должны быть включены все строки таблицы, указанной в левой части, следует использовать первый вариант. Такое соединение называется левым внешним соединением. Если необходимо, чтобы в результате присутствовали все строки таблицы в правой части, следует использовать второй вариант. В этом случае говорят о правом внешнем соединении. Рассмотрим примеры.
Запрос. Вывести фамилии всех преподавателей с указанием их кафедры, если она есть.
SELECT d.Name AS "Название кафедры", t.Name AS "Фамилия преподавателя"
FROM DEPARTMENT d. TEACHER t
WHERE d.DepPK (+)= t.DepFK;
Название кафедры Фамилия преподавателя
программирование Сидоров программирование Рамишевский программирование Хоренко программирование Вибровский программирование Воропаев программирование Кузинцев программирование Завратинский программирование Козлутин программирование Лекарь программирование Мартынов программирование Резван программирование Недеведеев
Ахромеев Наумов Дараганов
Обратите внимание, что в результирующей таблице значения отсутствующего столбца принимают значение NULL.
Запрос. Вывести названия всех кафедр с указанием фамилий преподавателей, если они есть.
SELECT d.Name AS "Название кафедры", t.Name AS "Фамилия преподавателя"
FROM DEPARTMENT d, TEACHER t
WHERE d.DepPK = t.DepFK (+);
Название кафедры Фамилия преподавателя
базы данных
программирование Сидоров программирование Рамишевский программирование Хоренко программирование Вибровский программирование Воропаев
программирование Кузинцев программирование Завратинский программирование Козлутин программирование Лекарь программирование Мартынов программирование Резван программирование Недеведеев интернет теория языков лингвистика базы данных
Внешнее соединение и условие отбора
При внешнем соединении можно применять и дополнительные условия отбора строк. Как видно из следующих двух примеров, если условие относится к столбцам таблицы, к которой не применяется оператор внешнего соединения, то внешнее соединение происходит.
Запрос. Вывести названия всех кафедр корпуса 3 с указанием их преподавателей, если они есть.
SELECT d.Name AS "Название кафедры".
t.Name AS "Фамилия преподавателя"
FROM DEPARTMENT d. TEACHER t
WHERE d.DepPK = t.DepFK (+) AND d.Building = '3';
Название кафедры Фамилия преподавателя
интернет теория языков лингвистика
Здесь отсутствуют кафедры баз данных и программирования, так как они находятся в других корпусах, но остальные присутствуют, несмотря на то, что их преподаватели не указаны.
Запрос. Вывести названия всех кафедр, фонд финансирования которых больше 12 000, с указанием их преподавателей, если они есть.
SELECT d.Name AS "Название кафедры", t.Name AS "Фамилия преподавателя"
FROM DEPARTMENT d, TEACHER t -
WHERE d.DepPK = t.DepFK (+) AND d.Fund > 12000:
Название кафедры Фамилия преподавателя
базы данных лингвистика базы данных
В результирующей таблице присутствуют кафедры, удовлетворяющие условию отбора, причем условие внешнего соединения сохранилось. А теперь зададим условие отбора для столбца таблицы, к которой применяется оператор внешнего соединения.
Запрос. Вывести названия всех кафедр с указанием их преподавателей, если они есть, ставка которых больше 1000.
SELECT d.Name AS "Название кафедры", t.Name AS "Фамилия преподавателя"
FROM DEPARTMENT d, TEACHER t
WHERE d.DepPK = t.DepFK (+) AND t.sal ary > 1000;
Название кафедры Фамилия преподавателя
программирование Сидоров
программирование Резван
Как видим, внешнего соединения не произошло. В этом случае действует следующее правило: если к столбцу таблицы был применен оператор внешнего соединения, то чтобы внешнее соединение произошло, этот оператор должен применяться и для всех других столбцов этой таблицы, указанных во фразе WHERE. Таким образом, чтобы в последнем примере внешнее соединение произошло, его следует записать следующим образом:
SELECT d.Name AS "Название кафедры", t.Name AS "Фамилия преподавателя"
FROM DEPARTMENT d, TEACHER t
WHERE d.DepPK = t.DepFK (+) AND t.sal ary (+) > 1000:
Название кафедры Фамилия преподавателя
базы данных
программирование Сидоров
программирование Резван
интернет
теория языков
лингвистика базы данных
Вообще, оператор (+) можно применять только к столбцу, но этот столбец может входить в выражение, как в запросе выше. Приведем еще один пример использования дополнительных условий при внешнем соединении.
Запрос. Вывести названия кафедр и фамилии их преподавателей при условии, что фонд финансирования кафедры больше ставки их преподавателей (если они есть) на И 450.
SELECT d.Name AS "Название кафедры", t.Name AS "Фамилия преподавателя"
FROM DEPARTMENT d, TEACHER t
WHERE d.DepPK = t.DepFK (+) AND d.Fund > t.Sal ary + 11450;
Название кафедры Фамилия преподавателя
программирование Козлутин
программирование Мартынов
Внешнего соединения не произошло, так как столбец Salary таблицы преподавателей использован без оператора внешнего соединения. Если же мы его укажем, то получим результат с внешним соединением:
SELECT d.Name AS "Название кафедры", t.Name AS "Фамилия поеподавателя"
FROM DEPARTMENT d, TEACHER t
WHERE d.DepPK = t.DepFK (+) AND d.Fund > t.Sal ary (+) + 11450;
Название кафедры Фамилия преподавателя
базы данных
программирование Козлутин программирование Мартынов интернет теория языков лингвистика базы данных
Внешнее соединение трех и более таблиц
В запросе может быть использовано внешнее соединение более чем двух таблиц. При этом следует помнить, что если к столбцу таблицы А применен оператор внешнего соединения с таблицей В, то никакой другой столбец таблицы А не может содержать оператор внешнего соединения с таблицей, отличающейся от В. В следующем примере внешнее соединение применяется для трех таблиц - факультетов, кафедр и преподавателей.
Запрос. Вывести список всех факультетов с указанием их кафедр и преподавателей.
SELECT f.Name AS"Факультет",
d.Name AS"Кафедра",
t.Name AS"Преподаватель"
FROMFACULTY f,DEPARTMENT d, TEACHER t
WHERE f.FacPK = d.FacFK (+) AND d.DepPK = t.DepFK (+);
Факультет КафедраПреподаватель
информатика базы данных
информатика программирование Сидоров информатика программирование Рамишевский информатика программирование Хоренко информатика программирование Вибровский информатика программирование Воропаев информатика программирование Кузинцев информатика программирование Завратинский информатика программирование Козлутин информатика программирование Лекарь информатика программирование Мартынов информатика программирование Резван информатика программирование Недеведеев информатика интернет кибернетика теория языков кибернетика лингвистика кибернетика базы данных математика
В этом случае также можно использовать дополнительные условия отбора строк, но с учетом замечаний относительно внешнего соединения двух таблиц. Добавим условие в предыдущий запрос.
Запрос. Вывести список всех факультетов с указанием кафедр и преподавателей, если фонд финансирования кафедры превышает фонд финансирования самого факультета.
SELECTf.NameAS"Факультет".
d.NameAS"Кафедра",
t.NameAS"Преподаватель"
FROMFACULTY f.DEPARTMENT d,TEACHER t
WHERE f.FacPK = d.FacFK (+) AND d.DepPK = t.DepFK (+) AND d.Fund > f.Fund;
Факультет Кафедра Преподаватель
информатика базы данных
Как видим, все факультеты в результате не перечислены — для этого необходимо в дополнительном условии указать оператор (+).
SELECTf.NameAS"Факультет".
d.NameAS"Кафедра".
t.NameAS"Преподаватель"
FROMFACULTY f.DEPARTMENT d. TEACHER t
WHERE f.FacPK = d.FacFK (+) AND d.DepPK = t.DepFK (+) AND d.Fund (+) > f.Fund;
Факультет Кафедра Преподаватель
информатика базы данных кибернетика
математика
Соединения с использованием фразы FROM
Все рассмотренные выше типы и способы соединения таблиц можно осуществлять и с помощью фразы FROM. В ней, в соответствии со стандартом SQL, можно не только перечислить имена таблиц, участвующих в запросе, но и указать их соединение, для чего могут использоваться три различные конструкции.
Уточненное соединение предполагает явное задание условия соединения. Для этого можно использовать два варианта — фразу USING, с помощью которой указываются одноименные столбцы обеих таблиц, по равенству значений которых следует произвести соединение, или фразу ON, с помощью которой для соединения можно указать произвольное условие. Синтаксис уточненного соединения следующий:
таблица [INNER | {FULL | LEFT | RIGHT} [OUTER]] JOIN таблица {ON условие | USING .(список_столбцов)}
Естественное соединение выполняется по равенству значений всех пар одноименных столбцов таблиц и не требует задания каких-либо условий. Оно имеют следующий синтаксис:
таблица NATURAL [INNER | {FULL | LEFT | RIGHT} [OUTER]] JOIN таблица
Перекрестное соединение эквивалентно декартовому произведению таблиц. Его синтаксис самый простой:
таблица CROSS JOIN таблица
Внутреннее соединение
В операторе JOIN внутреннее соединение указывается ключевым словом INNER (впрочем, его можно опустить, так как соединение двух таблиц является внутренним по умолчанию). Если не совпадают имена столбцов, участвующих во внутреннем соединении, или соединение производится не по равенству значений, следует использовать уточненное соединение с фразой ON. В этом случае внутреннее соединение с помощью фразы FROM очень похоже на соединение с использованием фразы WHERE. Приведем пример обоих вариантов.
Запрос. Вывести названия факультетов и их кафедр, если они имеют одинаковый фонд финансирования.
SELECT FACULTY.Name, DEPARTMENT.Name
FROM FACULTY. DEPARTMENT
WHERE FACULTY.FacPK = DEPARTMENT.FacFK AND FACULTY.Fund = DEPARTMENT.Fund;
SELECT FACULTY.Name, DEPARTMENT.Name
FROM FACULTY JOIN DEPARTMENT
ON FACULTY.FacPK = DEPARTMENT.FacFK AND FACULTY.Fund = DEPARTMENT.Fund;
NAME NAME
кибернетика базы данных
При соединении с использованием фразы FROM дополнительное условие можно для увеличения наглядности запроса помещать во фразу WHERE. В этом случае предыдущий запрос примет такой вид:
SELECT FACULTY.Name, DEPARTMENT.Name
FROM FACULTY JOIN DEPARTMENT
ON FACULTY.FacPK = DEPARTMENT.FacFK
WHERE FACULTY.Fund = DEPARTMENT.Fund:
Запрос. Вывести названия факультетов и кафедр, если фонд финансирования кафедры больше фонда финансирования факультета, а декан факультета и заведующий кафедрой являются разными лицами.
SELECT FACULTY.Name, DEPARTMENT.Name
FROM FACULTY JOIN DEPARTMENT
ON FACULTY.FacPK - DEPARTMENT.FacFK AND FACULTY.Fund < DEPARTMENT.Fund AND FACULTY.Dean <> DEPARTMENT.Head;
NAME NAME
информатика базы данных
Сравните вышеприведенный запрос с такой формой его записи:
SELECT FACULTY.Name, DEPARTMENT.Name
FROM
FACULTY JOIN DEPARTMENT
ON FACULTY.FacPK = DEPARTMENT.FacFK
WHERE
FACULTY.Fund < DEPARTMENT.Fund AND
FACULTY.Dean <> DEPARTMENT.Head:
Если таблицы нужно соединить по равенству столбцов с одинаковыми именами, То в уточненном запросе вместо фразы ON лаконичней будет воспользоваться фразой USING. В ней нужно только перечислить имена соединяемых столбцов:
SELECT *
FROM FACULTY JOIN DEPARTMENT USING (Building. Fund):
Здесь мы производим внутреннее соединение таблиц по равенству корпусов и фондов факультетов и кафедр.
Наконец, можно использовать ключевое слово NATURAL, которое указывает на естественное соединение:
SELECT *
FROM FACULTY NATURAL JOIN ROOM:
В этом запросе производится внутреннее соединение таблиц факультетов и аудиторий по равенству корпусов их расположения (столбец Building).
Внешнее соединение
Во фразе FROM левое и правое внешние соединения указываются соответственно операторами LEFT OUTER JOIN и RIGHT OUTER JOIN (ключевое слово OUTER можно опустить). В дополнение к этим двум вариантам внешнего соединения во фразе FROM можно указывать полное внешнее соединение с помощью оператора FULL OUTER JOIN (ключевое слово OUTER можно опустить и в этом случае), которое представляет собой объединение левого и правого внешних соединений. Результирующая таблица при полном внешнем соединении двух таблиц содержит все строки внутреннего соединения этих таблиц, а также не включенные им строки и первой, и второй таблиц (дополненные значениями NULL для отсутствующих столбцов).
Запрос. Вывести все факультеты и кафедры с указанием пар факультет/кафедра, имеющих одинаковые фонды финансирования и расположенные в одном корпусе.
SELECT FACULTY.Name, DEPARTMENT.Name
FROM FACULTY FULL JOIN DEPARTMENT
ON FACULTY.Fund = DEPARTMENT.Fund AND
FACULTY.Building = DEPARTMENT. Building:
name name
кибернетика базы данных
математика
информатика
базы данных лингвистика интернет программирование теория языков
Для внешних соединений допустимы те же синтаксические варианты, что и для внутреннего. Приведенный выше запрос можно записать следующим образом:
SELECT FACULTY.Name, DEPARTMENT.Name
FROM FACULTY FULL JOIN DEPARTMENT USING (Fund. Bulldina):
Соединение трех и более таблиц
Во фразе FROM можно соединять и больше двух таблиц. Порядок соединений может уточняться круглыми скобками, как и в случае всех других выражений (в этом смысле JOIN рассматривается как оператор, возвращающий таблицу). Использование скобок важно в связи с тем, что результат нескольких внешних соединений зависит от порядка их выполнения — например, последовательное внешнее соединение таблиц факультетов, кафедр и преподавателей не обязательно равно последовательному внешнему соединению таблиц преподавателей, кафедр и факультетов.
Рассмотрим несколько примеров. В следующем запросе производится полное внешнее соединение таблиц факультетов и кафедр по равенству номеров корпусов их расположения, а затем внутреннее соединение полученной таблицы с таблицей преподавателей по равенству внешнего ключа таблицы преподавателей и первичного ключа таблицы кафедр.
SELECT FACULTY.Dean, DEPARTMENT.Head, TEACHER.Name
FROM (FACULTY FULL JOIN DEPARTMENT
ON FACULTY.Building = DEPARTMENT.Bull ding)
INNER JOIN TEACHER
ON DEPARTMENT.DepPK = TEACHER.DepFK;
DEAN HEAD NAME
Сидоров Федоров Сидоров
Сидоров Федоров Рамишевский
Сидоров Федоров Хоренко
Сидоров Федоров Вибровский
Сидоров Федоров Воропаев
Сидоров Федоров Кузинцев
Сидоров Федоров Завратинский
Сидоров Федоров Козлутин
Сидоров Федоров Лекарь
Сидоров Федоров Мартынов
Сидоров Федоров Резван
Сидоров Федоров Недеведеев
Более сложный пример. Сначала, как и в предыдущем запросе, соединяются таблицы факультетов и кафедр. Затем выполняется левое внешнее соединение таблиц преподавателей и групп по условию курирования преподавателем группы. И наконец, производится внутреннее соединение полученных таблиц по условию равенства первичного ключа таблицы кафедр внешнему ключу таблицы преподавателей.
SELECT FACULTY.Dean, DEPARTMENT.Head, TEACHER.Name, SGROUP.Num
FROM (FACULTY FULL JOIN DEPARTMENT
ON FACULTY.Bull ding = DEPARTMENT. Building)
INNER JOIN (TEACHER LEFT JOIN SGROUP
ON TEACHER.TchPK * SGROUP.CurFK)
ON DEPARTMENT.DepPK = TEACHER.DepFK;
DEAN HEAD NAME NUM
Сидоров Федоров Недеведеев
Сидоров Федоров Хоренко
Сидоров Федоров Вибровский
Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров СидоровСидоров Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров СидоровФедоров Мартынов
Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров
Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров Сидоров
Федоров Сидоров
Федоров Рамишевский
Федоров Резван
Федоров Воропаев
Федоров Козлутин
Федоров Кузинцев408
Федоров Кузинцев307
Федоров Завратинский 504
Федоров Лекарь505
Самостоятельная работа
Вывести все возможные пары строк преподавателей и групп.
Вывести названия дисциплин, которые читает преподаватель Лекарь.
Вывести названия кафедр, на которых читается дисциплина «базы данных».
Вывести названия факультетов, фонд финансирования кафедр которых превышает фонд финансирования факультета.
Вывести фамилии кураторов групп и номера групп, которые они курируют.
Вывести номера групп, которые принадлежат тем же кафедрам, что и группа 505.
Вывести фамилии преподавателей, имеющих зарплату больше, чем преподаватель Наумов.
Вывести названия факультетов, располагающихся в том же корпусе, что и кафедра программирования.
Вывести фамилии непосредственного и вышестоящего руководителей преподавателя Хоренко.
Произвести левое внешнее соединение таблиц преподавателей и лекций, а также лекций и дисциплин, причем отобрать только те лекции, которые читаются на первой неделе.
И. Выполнить полное внешнее соединение по равенству первичного ключа таблицы кафедр и внешнего ключа таблицы групп.
Перепишите запросы урока, заменив соединения во фразе WHERE на JOIN и сравните результаты выполнения.
Подведение итогов
Усвоив материал этого урока, вы научились:
соединять таблицы по равенству и по произвольному условию;
соединять три и более таблицы;
производить самосоединение таблицы;
строить асимметричные запросы;
строить запросы к иерархическим данным;
выполнять внешние соединения таблиц.
^Ж) УРОК^Ж) УРОКИспользование функцийИспользование функций
^Ж) УРОК
^Ж) УРОК
Использование функций
Использование функций
Функции SQL подобны любым другим операторам языка в том смысле, что они производят действия с данными и возвращают результат в качестве своего значения. Функции имеют тип, который определяется типом возвращаемого значения, поэтому можно говорить о числовых, строковых, временных функциях и т. д. От обычных операторов функции отличаются форматом представления:
имя_функцииЕ(аргументе. аргумент]...)]
Этот формат допускает, что функции могут иметь ноль, один или более аргументов, причем при отсутствии аргументов круглые скобки не используются.
Имеется два основных класса функций SQL: встроенные и определяемые пользователем. Встроенными являются функции, предопределенные в SQL. Ко второму классу относятся функции, которые пишутся пользователями на специальном языке, обеспечивающем использование всех возможностей SQL. Каждая СУБД использует для этого свой собственный язык. В Oracle, например, таким языком является PL/SQL.
В SQL определено множество встроенных функций различных категорий. На этом уроке мы рассмотрим:
О агрегатные (или групповые) функции, оперирующие значениями столбцов множества строк и возвращающие одно значение;
О функции одной строки, использующие в качестве аргументов значения столбцов одной строки и возвращающие одно значение.
Агрегатные функции
Аргументами агрегатных функций могут быть как столбцы таблиц, так и результаты выражений над ними. Агрегатные функции и сами могут включаться в другие арифметические выражения. В стандарте SQL определены следующие виды агрегатных функций: унарные, бинарные, инверсного распределения, гипотетические функции множеств.
Мы будем рассматривать только определенные в стандарте SQL -унарные агрегатные функции. Их перечень представлен в табл. 5.1. Конкретные СУБД расширяют этот список (в Oracle, например, определено около 30 агрегатных функций).
Таблица 5.1. Стандартные унарные агрегатные функции
Имя
Возвращаемое значение
COUNT
Количество значений в столбце или строк в таблице
SUM
Сумма
AVG
Среднее
MAX
Максимум
MIN
VAR_POP STDDEV_POP VAR_SAMP STDDEV_SAMP EVERY
Минимум
Дисперсия генеральной совокупности
Среднее квадратичное отклонение дисперсии генеральной совокупности
Выборочная дисперсия
Среднее квадратичное отклонение выборочной дисперсии
TRUE, если все значения TRUE
ANY, SOME
TRUE, если хотя бы одно значение TRUE
Общий формат унарной агрегатной функции следующий:
имя_функции([ALL | DISTINCT] выражение) [FILTER (WHERE условие)]
где DISTINCT указывает, что функция должна рассматривать только различные значения аргумента, a ALL — все значения, включая повторяющиеся (этот вариант используется по умолчанию). Например, функция AVG с ключевым словом DISTINCT для строк столбца со значениями 1, 1, 1 и 3 вернет 2, а при наличии ключевого слова ALL вернет 1,5. Фраза FILTER позволяет дополнительно отобрать строки таблицы, столбец которой используется в качестве аргумента функции.
В связи с тем, что эта возможность не реализована в Oracle, мы не можем ее продемонстрировать, но использование условий во фразе WHERE вам уже известно. Агрегатные функции применяются во фразах SELECT и HAVING. Здесь мы рассмотрим их использование во фразе SELECT (об агрегатных функциях во фразе HAVING см. урок 6). В этом случае выражение в аргументе функции применяется ко всем строкам входной таблицы фразы SELECT. Кроме того, во фразе SELECT нельзя использовать и агрегатные функции, и столбцы таблицы (или выражения с ними) при отсутствии фразы GROUP BY, которую мы рассмотрим в уроке 6.
Функция COUNT
Функция COUNT имеет два формата. В первом случае возвращается количество строк входной таблицы, во втором случае — количество значений аргумента во входной таблице:
COUNTC*)
COUNT([DISTINCT | ALL] выражение)
Простейший способ использования этой функции — подсчет количества строк в таблице (всех или удовлетворяющих указанному условию). Для этого используется первый вариант синтаксиса.
Запрос. Информация о скольких преподавателях имеется в базе данных?
SELECT COUNTC*) AS "К-во преподавателей"
FROM TEACHER;
К-во преподавателей
15
Запрос. Информация о скольких ассистентах имеется в базе данных?
SELECT COUNTC*) AS "К-во ассистентов"
FROM TEACHER
WHERE LOWER(Post) = 'ассистент';
К-во ассистентов
4
Запрос. Сколько ассистентов не имеют телефонов?
SELECT COUNTC*) AS "К-во ассистентов без телефонов"
FROM TEACHER
WHERE LOWERCPost) = 'ассистент' AND Tel IS NULL;
К-во ассистентов без телефонов
2
Запросы с агрегатными функциями можно строить и с использованием нескольких таблиц, так как входная таблица и в этом случае будет только одна.
Запрос. Сколько кафедр на факультете информатики?
SELECT COUNTC*) AS "К-во кафедр" FROM FACULTY f, DEPARTMENT d
WHERE f.FacPK = d.FacFK AND LOWERCf.Name) = 'информатика';
К-во кафедр
3
Запрос. Сколько преподавателей на факультете информатики?
SELECT COUNTC*) AS "К-во преп. на ф-те информатики"
FROM FACULTY f. DEPARTMENT d. TEACHER t
WHERE f.FacPK = d.FacFK AND
d.DepPK = t.DepFK AND
LOWERCf.Name) = 'информатика';
К-во преп. на ф-те информатики
Во втором варианте синтаксиса функции COUNT в качестве аргумента может быть использовано имя отдельного столбца. В этом случае подсчитывается количество либо всех значений в этом столбце входной таблицы, либо только неповторяющихся (при использовании ключевого слова DISTINCT).
Запрос, Сколько различных номеров телефонов содержится в таблице TEACHER?
SELECT COUNT(DISTINCT Tel) AS "К-во телефонов"
FROM TEACHER;
К-во телефонов
4
Запрос. На скольких различных должностях работают преподаватели кафедры программирования?
SELECT COUNTCDISTINCT Post)
FROM DEPARTMENT d, TEACHER t
WHERE d.DepPK = t.DepFK AND
LOWER(d.Name) = ’программирование’;
COUNT(DISTINCTPOST)
4
Аргумент может представлять собой также любое допустимое над столбцами входной таблицы выражение.
Запрос. Из таблицы TEACHER вывести количество определенных в базе значений зарплат (ставка + надбавка), а также количество различающихся зарплат.
SELECT COUNT (Salary + Rise), COUNTCDISTINCT Salary + Rise)
FROM TEACHER;
COUNT(SALARY+RISE) COUNTCDISTINCTSALARY+RISE)
1513
Функция SUM
Эта агрегатная функция подсчитывает сумму значений аргумента для всех строк входной таблицы. Аргумент должен иметь числовой тип или быть временным промежутком. В качестве аргумента может выступать имя столбца или выражение над столбцами входной таблицы. В этой функции также допускается использовать ключевые слова DISTINCT и ALL. Приведем примеры.
Запрос. Какой суммарный фонд финансирования всех факультетов?
SELECT SUM(Fund)
FROM FACULTY;
SUM(FUND)
75000
Запрос. Какая суммарная ставка всех ассистентов?
SELECT SUM(Salary)
FROM TEACHER
WHERE LOWER(Post) = 'ассистент';
SUM(SALARY)
2200
Запрос. Сколько профессоров в вузе и какова их суммарная зарплата?
SELECT COUNH*), SUM(Salary + Rise)
FROM TEACHER
WHERE UPPER(Post) = 'ПРОФЕССОР';
COUNH*) SUM(SALARY+RISE)
34660
Запрос. Сколько студентов пятого курса на факультете информатики?
SELECT SUM(Quantlty)
FROM FACULTY f, DEPARTMENT d, SGROUP g
WHERE f.FacPK = d.FacFK AND
d.DepPK = g.DepFK AND
Year = 5;
SUM(QUANTITY)
58
Функция AVG
Агрегатная функция AVG подсчитывает среднее значение аргумента для всех строк входной таблицы. Аргумент должен иметь числовой тип или быть временным промежутком. В качестве аргумента может выступать имя столбца или выражение над столбцами входной таблицы. Допускается использовать ключевые слова DISTINCT и ALL. Приведем ряд примеров.'
Запрос. Какой средний фонд финансирования всех кафедр?
SELECT AVG(Fund)
FROM DEPARTMENT;
AVG(FUND)
16516,6667
Запрос. Какая средняя ставка среди всех преподавателей?
SELECT AVG(Salary)
FROM TEACHER;•
AVG(SALARY)
741.333333
Запрос. Какое среднее значение ставки в вузе?
SELECT AVGCDISTINCT Salary)
FROM TEACHER;
AVG(DISTINCTSALARY)
811
Обратите внимание, что здесь мы использовали ключевое слово DISTINCT, чтобы применить AVG не ко всем имеющимся в таблице TEACHER ставкам, а только к различным значениям ставки.
Запрос. Какова средняя зарплата доцентов?
SELECT AVG(Salary + Rise) "Средняя зарплата доцентов"
FROM TEACHER
WHERE LOWER(Post) = ’доцент*;
Средняя зарплата доцентов
1190.25
Запрос. Сколько аудиторий в корпусе 6, какая их общая и средняя вместимость:
SELECT COUNT(*) AS "К-во ауд в к.6", SUM(Seats) AS "Общая вместимость", AVG(Seats) AS "Средняя вместимость"
FROM ROOM
WHERE Building = '6';
К-во ауд в к.6 Общая вместимость Средняя вместимость
416240,5
Функции MIN и МАХ
Эти функции позволяют находить максимальное (МАХ) и минимальное (MIN) значения аргумента для всех строк входной таблицы. Хотя и в этом допускается использование ключевых слов DISTINCT и ALL, они не оказывают влияния на результат. Аргумент этих функций может быть любого типа, для которого определено упорядочение, то есть числовой, строковый и временной.
Запрос. Какой максимальный фонд финансирования факультетов?
SELECT MAX(Fund)
FROM FACULTY;
MAX(FUND)
27000
Обратите внимание, что если бы вы захотели вместе с максимальным фондом получить и название этого факультета и написали бы этот запрос так:
SELECT Name, MAX(Fund)
FROM FACULTY;
то получили бы сообщение об ошибке:
SELECT Name, MAX(Fund) *
Ошибка в строке 1:
ORA-00937: групповая функция не является одногруппной
Ошибка возникает потому, что во фразе SELECT нельзя одновременно использовать имена столбцов (или выражения над столбцами) и агрегатные функции при отсутствии фразы GROUP BY. Составление таких запросов рассмотрено в уроке 7, посвященном вложенным запросам.
Запрос. Какова максимальная зарплата преподавателя ?
SELECT MAX(Salary + Rise)
FROM TEACHER;
MAX(SALARY+RISE)
1570
Запрос. Когда в последний раз принимали на работу преподавателя на кафедру программирования?
SELECT MAX(Hi redate)
FROM DEPARTMENT d, TEACHER t
WHERE d.DepPK = t.DepFK AND
LOWER(d.Name) = 'программирование*;
MAX(HIREDATE)
01.09.2003
Функции MAX и MIN, как уже сказано, применимы и к строковым столбцам (а также выражениям над такими столбцами). При этом предполагается упорядочение символьных строк по алфавиту.
Запрос. Вывести первое по алфавиту название кафедры с фондом финансирования больше 10 000.
SELECT MIN(Name)
FROM DEPARTMENT
WHERE Fund > 10000;
MIN(NAME)
базы данных
Функции VAR_POP, STDDEV_POP, VAR_SAMP, STDDEV_SAMP
Эти числовые функции имеют отношение к статистической обработке данных и вычисляются по следующим формулам:
VAR_POP(X) - (SUM(X * X) - SUM(X) * SUM(X) / N) / N
VAR_SAMP - (SUM (X * X) - SUM(X) * SUM(X) / N) / (N-l)
STDDEV_POP(X) - SQRT(VAR_POP(X))
STDDEV SAMP(X) = SQRT(VAR SAMP(X)) .
где N - количество значений X, к которым применяется функция. В этих функциях нельзя использовать ключевое слово DISTINCT, a ALL - можно (хотя, как мы знаем, оно применяется по умолчанию).
Запрос. Вывести статистические данные ставок преподавателей.
SELECTVAR_POP(Salary)AS”VAR_POP”.
STDDEV_POP(Salary)AS"STDDEVJW.
VAR_SAMP(Salary)AS"VAR_SAMP".
STDDEV_SAMP(Salary)AS"STDDEV_SAMP"
FROMTEACHER;
VAR_POP STDDEV_POP VAR_SAMP STDDEV_SAMP
39184.8889 197.951734 41983.8095 204,899511
функции EVERY, ANY, SOME
He все СУБД поддерживают эти функции. Они применяются к столбцам типа BOOLEAN, возвращаемое значение принадлежит этому же типу. Они также применяются к логическим выражениям над столбцами. Функция EVERY возвращает значение TRUE, если все значения в столбце (или все логические выражения над столбцами) являются TRUE, а функции ANY и SOME возвращают значение TRUE, если хотя бы одно значение в столбце (или одно логическое выражение над столбцами) является TRUE.
Допустим, что в таблице TEACHER имеется столбец логического типа с именем PhD, указывающий, имеет ли преподаватель степень доктора наук. Тогда можно было бы сформулировать следующие запросы.
Все ли профессоры являются докторами наук:
SELECT EVERY(PhD)
FROM TEACHER
WHERE LOWER(Post) = 'профессор';
Существуют ли доценты доктора наук:
SELECT SOME(PhD)
FROM TEACHER
WHERE LOWER(Post) = 'доцент':
Если бы нам нужны были фамилии таких преподавателей, запрос выглядел бы следующим образом:
SELECT Name
FROM TEACHER
WHERE LOWER(Post) = 'доцент' AND PhD;
Запрос. Вывести обобщенные сведения о зарплате преподавателей кафедр.
SELECT d.Name AS * Кафедра'.
EVERY(Salary + Rise > 1500) AS 'Все состоятельные',
SOMECSalary + Rise > 1500) AS 'Некоторые состоятельные'
bROM DEPARTMENT d, TEACHER t
WHERE d.DepPK = t.DepFK
GROUP BY d.Name:
КафедраВсе состоятельные Некоторые состоятельные
базы данных falsefalse
программирование falsetrue
интернет truetrue
Выражения с использованием агрегатных функций
Агрегатные функции не только могут иметь выражение в своем аргументе, но и сами могут использоваться в выражениях.
Запрос. Вывести процентное соотношение суммарной ставки к суммарной зарплате и наоборот.
SELECT SUM(Salary) * 100 / SUM(Rise)
AS "Процент ставки к зарплате", SUM(Rise) * 100 / SUM(Salary) AS "Процент зарплаты к ставке" FROM TEACHER;
Процент ставки к зарплате Процент зарплаты к ставке
237,55607842,0953237
Запрос. Какая разница между минимальной и максимальной зарплатой у доцентов?
SELECT MAXCSalary + Rise) - MINCSalary + Rise) FROM TEACHER
WHERE LOWER(Post) = доцент;
MAX(SALARY+RISE)-MIN(SALARY+RISE)
219
Отсутствующие и неопределенные значения в агрегатных функциях
Если аргумент агрегатной функции не содержит значений, функция COUNT возвращает 0, а все остальные — значение NULL.
Запрос. Сколько преподавателей имеют ставку более 4000?
SELECT COUNT(*)
FROM TEACHER
WHERE Salary > 4000:
COUNTC*)
0
Как правило, значение NULL «выводится» в виде пробелов, и в этом случае результат не ясен. В связи с этим рекомендуем воспользоваться функцией COALESCE, которая принимает значение своего первого аргумента, не равного NULL (см. описание этой функции в уроке 8). Приведем два варианта запроса — с использованием этой функции и без нес.-
Запрос. Вычислить максимальную надбавку преподавателей, которые имеют ставку более 4000.
SELECT MAX(Rise)
FROM TEACHER
WHERE Salary > 4000;
SELECT COALESCE(MAX(Rise). 0)
FROM TEACHER
WHERE Salary > 4000;
MAX(RISE)'
COALESCE(MAX(RISE),0)
О
функция COUNT(*) подсчитывает строки с учетом неопределенных значений и дубликатов, а все остальные агрегатные функции игнорируют строки аргумента с неопределенным значением. Помните об этом при их использовании, чтобы контролировать результат. Если для подсчета, например, среднего значения необходимо, чтобы значения NULL учитывались, замените их с помощью функции COALESCE на подходящее значение, например на 0.
Запрос. Подсчитать среднюю зарплату всех ассистентов, предполагая, что NULL в столбцах Salary и Rise означает отсутствие выплат.
SELECT AVG(COALESCE(Salary. 0) + C0ALESCE(R1se. 0)) AS "Средняя зарплата ассистентов"
FROM TEACHER
WHERE LOWER(Post) = 'ассистент':
Средняя зарплата ассистентов
740
Однострочные функции
Напомним, что эти функции используют в качестве аргумента одно значение (одного столбца одной строки таблицы) и возвращают в качестве своего результата также единственное значение. Мы рассмотрим эти функции по типам их apiy- ментов. Сначала приведем функции, имеющиеся в стандарте SQL (с указанием их эквивалентов в Oracle), а затем — представляющие интерес дополнительные Функции Oracle. В примерах этого раздела мы будем использовать специальную системную таблицу Oracle под именем DUAL, которая доступна для чтения всем пользователям. Она содержит только один столбец с именем DUMMY типа VARCHAR(1) и только одну строку со значением ' X'. Она используется в том случае, когда никакой таблицы не нужно вообще, так как результат запроса полностью определяется содержанием фразы SELECT.
Строковые функции
Эти функции используют в качестве аргумента строку символов и в качестве результата возвращают также символьную строку. Стандарт SQL предлагает варианты таких функций и для двоичных строк.
Функция SUBSTRING
Выбирает подстроку указанной длины из заданной строки, начиная с заданной позиции. Если длина не задана, подстрока выбирается до конца строки. Фраза USING указывает, в каких единицах заданы начало и длина — в символах или байтах. Функция применима и для двоичных строк, в этом случае фраза USING не используется.
SUBSTRINGCcTpona FROM начало [FOR длина] [USING CHARACTERS | OCTETS])
В Oracle аналогом этой функции является SUBSTRCстрока, начало[. длина]). Ее особенностью является то, что начало может быть задано отрицательным числом — в этом случае оно отсчитывается от правого конца строки.
SELECT Name AS "Факультет".
Substr(Name, 3) AS "3- символы".
Substr(Name. 3. 7) AS "3-7 символы".
SubstrCName, -7. 5) AS "-7-5 символы"
FROM FACULTY;
Факультет 3- символы3-7 символов -7-5 символов
информатика форматикаформатирмати
кибернетика бернетикабернетирнети
математика тематикатематикемати
Стандарт SQL предлагает также вариант этой функции, в котором можно использовать рехулярное выражение. В этом случае возвращается подстрока, совпадающая с заданным регулярным выражением.
SUBSTRINGCcTpoKa SIMILAR выражение ESCAPE символ)
Функции UPPER, LOWER
Эти функции мы уже рассматривали и многократно использовали. Они имеют следующий формат:
UPPER(строка)
LOWER(cTpoKa)
Приведем для них примеры с использованием фиктивной таблицы DUAL:
SELECT UPPER('Строка из прописных букв') AS "Все прописные" FROM DUAL;
Все прописные
СТРОКА ИЗ ПРОПИСНЫХ БУКВ
SELECT LOWER('Строка Из Строчных Букв') AS "Все строчные"
FROM DUAL;
Все строчные
строка из строчных букв
функция CONVERT
Преобразует символы строкового архумента в другие согласно заданной функции, которая в стандарте SQL не специфицируется.
CONVERT(строка USING функция)
В Oracle предлагается вариант этой функции, который производит преобразование строки символов из одной кодировки в другую.
CONVERT(строка, целевая_кодировка[. исходная_кодировка])
Пример:
SELECT CONVERTS А 6 tOOABCDE’. ’US7ASCII’, ’WE8IS08859P1’)
FROM DUAL;
CONVERTSAEIOOABCDE')
A E I О О А В C D E
Функция TRANSLATE
Транслитерирует символы исходной строки согласно отображению много-к-одно- му или один-к-одному между двумя, не обязательно различными наборами символов. Отображение задается указываемой функцией, которая в стандарте SQL не специфицируется.
TRANSLATE(строка USING функция)
В Oracle предлагается следующий вариант этой функции:
TRANSLATE (строка, исходный_набор, целевой_набор)
Она возвращает строку, в которой все символы архумента строка, встречающиеся в исходном наборе, заменяются на соответствующие символы целевого набора. Символы, которых нет в исходном наборе, не изменяются. Исходный набор может содержать больше символов, чем целевой. Если такие дополнительные символы существуют в транслитерируемой строке, они удаляются.
В приводимом примере все символы цифр заменяются на 191, символы ' ABCDZ * заменяются на ' X', ' X' на ' Z *, а * Y * удаляется:
SELECT TRANSLATE('2ARW229XYZ*. *012345678ABCDXZY*, '999999999XXXXZX*)
AS "Лицензия"
FROM DUAL;
Лицензия
9XRW999ZX
Функция TRIM
Эта функция возвращает строку архумента, удаляя указанный символ из начала и/или конца строки. Ключевые слова LEADING (в начале), TRAILING (в конце) и BOTH (с обеих сторон) указывают, где именно удаляются символы. По умолчанию удаление производится с обоих концов. Удаляемый символ определяется в аргументе символ (если он отсутствует, удаляются пробелы). Стандарт SQL предусматривает возможность применения этой функции и для двоичных строк.
TRIM(Г[LEADING I TRAILING I ВОТН1 [символ! FROM1 стоока)
Например:
SELECT TRIMUO' FROM '0009872348900') AS "Пример"
FROM DUAL:
Пример
98723489
Функция OVERLAY
Заменяет в исходной строке подстроку, начинающуюся с позиции начало и имеющую размер длина, на значение строки для замены. Стандарт SQL предусматривает возможность применения этой функции и для двоичных строк.
OVERLAY!исходная_строка PLACING строка_для_замены FROM начало [FOR длина] [USING CHARACTERS | OCTETS])
В Oracle такой функции нет, но имеется выполняющая аналогичное действие:
REPLACE!исходная_строка, подстрока[. строка_для_замены])
В исходной строке ее подстрока заменяется на строку для замены. Если строки для замены нет, подстрока удаляется. Приведем примеры:
SELECT 'На ашипках учемся* AS "Исходная строка".
TRANSLATE(REPLACE!'На ашипках учемся*, 'аш1, *ош*), *пе*. 'би') AS "Исправленная строка"
FROM DUAL;
Исходная строка Исправленная строка
На ашипках учемся На ошибках учимся
Далее мы приведем ряд полезных строковых функций, которые реализованы в Oracle, но отсутствуют в стандарте SQL.
Функция INITCAP
Преобразует в прописные первые буквы всех слов аргумента и в строчные — все остальные.
1Н1ТСАР(строка)
Например:
SELECT INITCAP!'все слова наЧИНАются с проПИСНЫХ букв') AS "Действие функции INITCAP"
FROM DUAL:
Действие функции INITCAP
Все Слова Начинаются С Прописных Букв
Функции LPAD, RPAD
Заполняют строку аргумента слева (функция LPAD) или справа (функция RPAD) указанными символами до указанного размера. В случае отсутствия третьего аргумента для заполнения используется пробел.
LPAD(cTpoKa, размер[, заполнитель])
РРАОСстрока. размер[. заполнитель])
Пример:
SELECT Name. LPAD(Name.l5. '*!'). RPAD(Name,15, '+') FROM FACULTY:
NAMELPAD(NAME.15/*!') RPAD(NAME,15,*+*)
информатика*!*!информатикаинформатика++++
кибернетика*!*!кибернетикакибернетика++++
математика*!*!*математикаматематика+++++
функция CHAR
Возвращает символ, код которого указан аргументом.
СНАР(целое_число)
Пример (используется кодировка Win 1251):
SELECT CHRC202) || CHR(206) || CHRC216) || CHRC202) || CHRC192) AS "Собака"
FROM DUAL:
Собака
КОШКА
Числовые функции над строками
Эти функции в аргументе используют строку символов, а в качестве результата возвращают число.
Функция POSITION
Определяет позицию первого вхождения подстроки в строку.
Р051ТЮМ(строка IN подстрока [USING CHARACTERS | OCTETS])
Подобная функция в Oracle предоставляет дополнительные возможности.
INSTR(cTpoKa. подстрокаЕ. позиция][. вхождение])
Аргумент позиция указывает, с какого символа следует искать совпадение, а параметр вхождение — какое по счету совпадение должно быть найдено. По умолчанию производится поиск первого вхождения с начала строки. Пример:
SELECT INSTRC небольшое изменение на этой неделе'. 'не'. 3. 2) AS "Поиск НЕ"
FROM DUAL:
Поиск НЕ
29
функции CHAR_LENGTH, OCTET_LENGHT
Возвращает длину заданной строки либо в символах, либо в байтах. Вторая функция используется для измерения длины двоичных строк.
CHAR_LENGTH( строка [USING CHARACTERS | OCTETS])
OCTETLENGTHI строка)
В Oracle для этого существуют функции LENGTH (строка), возвращающая длину в символах, и LENGTHB(cTpoKa), возвращающая длину в байтах. Приведем пример:
SELECT 'длина этой строки* AS "Строка",
LENGTH('длина этой строки*) "Ее длина"
FROM DUAL:
СтрокаЕе длина
длина этой строки 17
Функция ASCII
Эта функция отсутствует в стандарте SQL, но присутствует во многих СУБД и является весьма полезной. Она возвращает код первого символа в строке аргумента.
ASCII(строка)
Приведем пример:
SELECT ASCI К* Ш‘). ASCIK'O*), ASCIK'K*)
FROM DUAL:
ASCII('K') ASCII('O') ASCIK'Ш1)
216206‘202
Числовые функции над числами
Эти функции возвращают числовые значения на основании заданных в аргументе значений того же типа. Числовые функции используются для обработки данных, а также в условиях их поиска. Стандарт SQL предлагает ряд числовых функций с очевидной семантикой. Они перечислены в табл. 5.2.
Таблица 5.2. Стандартные числовые функции SQL над числами
ФункцияОписание
ABS(число)
Абсолютное значение
MOD(делимое. делитель)
Остаток от деления
ЕМ(число)
Натуральный логарифм
ЕХР(число)
Экспоненциальная функция (е в степени аргумента)
РОМЕР(число, степень)
Возведение числа в степень
SORT(число)
Квадратный корень
РЕООР(число)
Округление до целого числа вниз
СЕ1Е1Н6(число)
Округление до целого числа вверх *
R0UND(4Mcno. точность)
Округление до указанного количества знаков после запятой
Особой функцией является WIDTH BUCKET, с помощью которой можно легко строить гистограммы:
WIDTHBUCKETCчисло. минимум, максимум, количество)
Она разбивает числовой интервал между значениями аргументов минимум и максимум на количество диапазонов одинакового размера и возвращает номер диапазона, в который попадает число (значение столбца таблицы или выражения над столбцами). Если значение аргумента число выходит за указанные границы, создаются диапазоны с номерами 0 и количество + 1. Приведем пример:
SELECT Name. Salary. WIDTH_BUCKET(Salary, 500. 5000. 10)
AS "Группа по зарплате"
FROM TEACHER
WHERE LOWER(Post) IN ('профессор*, 'доцент'):
NAME SALARY Группа по зарплате
Сидоров
1070
2
Рамишевский
830
1
Завратинский
770
1
Лекарь
890
1
Резван
1100
2
Ахромеев
1050
2
Наумов
770
1
Некоторые СУБД расширяют приведенный выше набор функций, включая другие числовые функции, например вычисления обычных и гиперболических тригонометрических функций.
Временные функции
Эти функции используют в качестве аргумента типы даты, времени, временной отметки или временного промежутка. Тип возвращаемого значения не всегда соответствует типу аргумента.
Функция EXTRACT
Функция извлекает из операнда указанный компонент и возвращает его в виде числа.
EXTRACT(компонент FROM операнд)
Здесь операнд — это выражение временного типа, а компонент — временная единица, которая может иметь одно из следующих значений: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND. В следующем примере функция возвращает число 2005.
SELECT EXTRACTCYEAR FROM DATE '2005-12-13’)
FROM DUAL:
EXTRACT(YEARFROMDATE’2005-12-12*)
2005
Функция ABS
Эта функция возвращает абсолютное значение временного промежутка, заданного в аргументе.
ABS(временной_промежуток)
Функция CURRENT_DATE
Эта функция возвращает текущую дату. Аргументов она не имеет.
CURRENT_DATE
Так как в Oracle тип DATE содержит в себе и время, эта функция возвращает следующий результат:
SELECT CURRENT_DATE
FROM DUAL;
CURRENT_DATE
12-ДЕК-2005 19:18:03
Функции CURRENTTIME и LOCALTIME
Функции возвращают текущее время с указанием временной зоны (CURRENT_TIME) или без нее (LOCALTIME). Аргумент определяет точность представления дробной части секунд.
CURRENT_TIME[(точность)]
LOCALTIME[(точкость)]
Обе функции в Oracle не реализованы.
Функции CURRENTJTMESTAMP и LOCALTIMESTAMP
Возвращают текущую временную отметку с указанием временной зоны (CURRENT-TIMESTAMP) или без нее (LOCALTIMESTAMP). Аргумент, как и в предыдущем случае, определяет точность представления дробной части секунд.
CURRENT_TIMESTAMP[ (точность) ]
LOCALTIMESTAMP L(точность)]
В этом случае мы можем привести пример (-05:00 в результате является указанием временной зоны):
SELECT CURRENT_TIMESTAMP(6)
FROM DUAL:
CURRENT_TIMESTAMP(6)
13-ДЕК-2005 01.17.56.917550 PM -05:00
Многие СУБД существенно расширяют список функций, оперирующих датой и временем. Далее мы приведем некоторые из важных функций этого типа, которые используются в Oracle. Напоминаем, что тип DATE в Oracle содержит в себе как дату, так и время.
Функция SYS DATE
Возвращает текущую дату и время. В случае распределенной базы данных возвращает дату и время локальной базы. Аргументов данная функция, как и функция CURRENTJDATE, не имеет.
SYSDATE
Пример:
SELECT TO_CHAR(SYSDATE. 1DD-MON-YYYY HH24:MI:SS *) AS "Дата написания этих строк"
FROM DUAL;
Дата написания этих строк
12-ДЕК-2005 22:02:26
Функция ADD_MONTHS
Добавляет к дате, указанной в первом аргументе, количество месяцев второго ар- тумента.
ADD_MONTHS(naTa, месяц)
Приведем пример:
SELECT Hi reDate AS "Дата приема",
ADD_MONTHS(Hi reDate, 3) AS "Плюс 3 месяца"
FROM TEACHER
WHERE UPPER(Name) * ’ХОРЕНКО';
Дата приема Плюс 3 месяца
10.10.200110.01.2002
Функция LAST_DAY
Возвращает дату последнего дня того месяца, который указан в аргументе. Обычно используется для определения, сколько дней осталось до конца месяца.
LAST_DAY(дата)
Например:
SELECT SYSDATE AS "Дата сегодня",
LAST_DAY(SYSDATE) AS "Конец месяца",
LAST_DAY(SYSDATE) - SYSDATE AS "Осталось дней"
FROM DUAL;
Дата сегодня Конец месяца Осталось дней
12.12.200531.12,200519
Функция MONTHS_BETWEEN
Вычисляет количество месяцев между двумя указанными датами. Если дни в обеих датах совпадают или являются последними днями месяца, возвращает целое количество месяцев, иначе — результат представляется дробным числом.
MONTHS-BETWEENUaiaJ, дата_2)
Например, если вы хотите узнать, сколько месяцев уже проработал Хоренко, можно выполнить такой запрос:
SELECT 'Хоренко проработал ' ||
ROUND(MONTHS_BETWEEN(SYSDATE. HireDate).!) ||
' месяцев' AS "Стаж Хоренко"
FROM TEACHER
WHERE UPPER(Name) = ’ХОРЕНКО':
Стаж Хоренко
Хоренко проработал 50,1 месяцев
Если дата первого аргумента меньше, результат будет иметь отрицательное значение. Это дает возможность определить, произошло ли одно событие раньше другого. Например, следующий запрос позволяет выбрать всех преподавателей, принятых на работу после 22 июня 2002 года:
SELECT Name
FROM TEACHER
WHERE MONTHS_BETWEEN(Hi redate, DATE *2002-06-221) > 0;
NAME
Вибровский
Воропаев
Мартынов
Функция NEXTJ)AY
Возвращает ближайшую к первому параметру дату, в которой название дня недели совпадает с указанным во втором параметре.
NEXT_DAY(дата, день_недели)
Например, для определения даты ближайшей следующей пятницы относительно даты приема на работу преподавателя Резвана следует выполнить такой запрос:
SELECT TO_CHAR(Hi redate, ’DAY DD MONTH YYYY') AS "Дата приема Резвана", TO_CHAR(NEXT_DAY(Hiredate. ’пятница’), ’DAY DD MONTH YYYY’) AS "Следующая пятница"
FROM TEACHER
WHERE UPPER(Name) » 'PE3BAH':
Дата приема РезванаСледующая пятница
СУББОТА 11 НОЯБРЬ 2000 ПЯТНИЦА 17 НОЯБРЬ 2000
Функции преобразования
Стандарт SQL предлагает единственную функцию преобразования данных из одного типа в другой — это функция CAST. Но мы дополнительно рассмотрим несколько функций преобразования, поддерживаемых Oracle.
Функция CAST
Производит преобразование выражения, заданного первым аргументом, в тип, заданный вторым аргументом. Преобразование допускается только для определенных пар типов данных.
Пример запроса:,
SELECT NameAS "Фамилия",
1 SalaryAS "Зарплата как число",
CASTCSalary AS varchar(lO)) AS "Зарплата как строка" FROM TEACHER WHERE Chief - 16;
Фамилия
Зарплата как число Зарплата как строка
Рамишевский
830 830
Завратинский
770 770
Лекарь
890 890
Резван
1100 1100
Функция TO_CHAR
Эта функция имеет два варианта с разными типами первого аргумента:
TO_CHAR(flaTa[, формат])
ТО_СНАР(число[, формат])
В первом варианте она преобразует указанную дату в строку символов согласно формату представления даты, определенному вторым аргументом. Если второй аргумент отсутствует, преобразование производится согласно формату по умолчанию. Например:
SELECT Name AS "Фамилия".
TO_CHAR(Hiredate. ’MONTH DD DAY YYYY')
AS "Дата приема на работу"
FROM TEACHER
WHERE TchPK = 5;
Фамилия Дата приема на работу
Кузинцев ЯНВАРЬ 01 ВТОРНИК 1991
При этом в Oracle можно использовать элементы строки формата, перечисленные в табл. 5.3.
Таблица 5.3. Элементы строки формата Oracle при преобразовании даты
Элемент формата Описание
- / , : :
Разделяющие символы
'текст'
Текст в кавычках представляется в результате в указанном виде
YYYY
Год в виде четырех цифр
YYY YY Y
Последние 3, 2 или 1 цифра года
ММ
Номер месяца (01-12)
MON
Сокращенное название месяца
MONTH
Полное название месяца, дополненное справа пробелами до 9 символов
D
Номер дня недели (1-7)
Таблица 5.3 (продолжение)
Элемент формата
Описание
DAY
Полное название дня недели, дополненное справа пробелами до 9 символов
DD
День месяца (1-31)
DDD
День года (1-366)
НН НН12
Час дня (1-12)
НН24
Час дня (0-23)
MI
Минута (0-59)
Во втором варианте функция TO_CHAR преобразует заданное первым аргументом число в строку символов согласно формату представления, определенному вторым аргументом. Если формат отсутствует, в результирующей строке представляются все, и только значащие цифры числа. В табл. 5.4 приведены элементы строки формата в Oracle при преобразовании числа.
Таблица 5.4. Элементы строки формата Oracle при преобразовании числа
Элемент формата
Пример
Описание
9,999
Возвращает запятую в указанной позиции
99.99
Возвращает разделитель десятичной точки
$
$9999
Возвращает число со знаком доллара в начале
9
9999
Возвращает в указанной позиции цифру числа
0
0999
Возвращает нули в начале
0
9990
Возвращает нули в конце
Пример:
SELECT Name, TO_CHAR(Salагу + Rise, '$99,990.99’)
FROM TEACHER
WHERE HireDate > Date ’2002-01-0Г:
NAME TO_CHAR(SAL
Вибровский $740.00
Воропаев $720.00
Мартынов $750.00
Функция TO_DATE
Эта функция, о которой мы уже упоминали выше, преобразует строку символов, заданную первым аргументом, в дату, представленную в формате, указанном во втором аргументе. Если второй аргумент отсутствует, преобразование производится согласно формату по умолчанию.
TO_DATE(строка[. формат])
Пример:
SELECT Name, Hi reDate
FROM TEACHER
WHERE HireDate > TO_DATE('Июнь 24, 2002*, ’Month dd. YYYY’);
NAMENAMEHIREDATEHIREDATE
NAME
NAME
HIREDATE
HIREDATE
Вибровский 01.09.2003
Воропаев 02.09.2002
Мартынов 22.10.2002
Функция TO_NUMBER
Преобразует в число строку символов первого аргумента, представляющую число согласно формату второго аргумента.
TO_NUMBER(строка[, формат])
Пример:
SELECT ’1239645.98’ AS ’’Строка",
TO_NUMBER(’1239645.98’, ’9999999.99’) AS "Число"
FROM DUAL;
СтрокаЧисло
1239645.98 1239645,98
Функция DECODE
Эта функция имеет переменное число аргументов. Она последовательно сравнивает значение первого аргумента со значением аргумента из_п. Если для очередного из_п сравнение оказалось истинным, возвращается значение соответствующего аргумента в_п, а если совпадения не обнаружено, возвращается значение по умолчанию (если значение по умолчанию отсутствует, возвращается NULL).
DECODEC выражение, из_1, в_1[, из_2, в_2]...[, по_>молчанию])
Обратите внимание, что типы исходной строки и ее декодированного значения могут не совпадать. Выведем, например, все дни недели (с указанием номера этого дня в неделе), в которые проходят занятия:
SELECT DISTINCT Day AS ДЕНЬ,
DECODE(LOWER(Day), 'пнд', 1. 'втр', 2, 'срд'. 3, 'чтв', 4, 'птн', 5, ’суб’, 6, ’вое’, 7) AS НОМЕР FROM LECTURE;
ДЕНЬ НОМЕР
2153421534втр пнд птн срд чтв
2
1
5
3
4
2
1
5
3
4
Самостоятельная работа
Сколько преподавателей на кафедре программирования?
Лекции по скольким предметам читает преподаватель Лекарь?
Сколько занятий проводится в аудитории 311 корпуса 6?
Сколько аудиторий задействовано в учебном процессе и по скольким дисциплинам проводятся занятия?
Какое количество студентов посещают занятия преподавателя Рамишевского?
Какая средняя зарплата преподавателей факультета информатики?
Какое максимальное и минимальное количество студентов в группе?
Вывести средний фонд финансирования кафедр, предполагая, что при отсутствии значения фонд отсутствует.
Вывести с использованием функции SUBSTR фамилии преподавателей, которые начинаются на букву «Р».
Вывести номер позиции, в которой располагается третье вхождение подстроки 'OR'в строке 'CORPORATE FLOOR'.
И. Выведите в виде числа компонент месяца из даты '14.12.2005’.
Вывести количество месяцев между датами ‘13.07.1947 ’ и '14.12.2005'.
Подведение итогов
Усвоив материал этого урока, вы научились:
0 использовать агрегатные функции;
0 строить выражения с использованием агрегатных функций;
0 использовать в агрегатных функциях неопределенные значения;
0 использовать строковые функции;
0 использовать числовые функции;
0 использовать временные функции;
0 использовать функции преобразования.
Группировкаи сортировка
В этом уроке мы рассмотрим еще три фразы предложения SELECT, а именно: HAVING, GROUP BY и ORDER BY. Первая из них позволяет группировать строки таблицы и применять к созданным группам агрегатные функции. Рассмотрим простейшие варианты группировки, дополнительные возможности фразы GROUP BY будут изучены в уроке 10. Фраза HAVING используется вместе с фразой GROUP BY и позволяет формулировать условия на группах строк для дополнительного отбора. Наконец, фраза ORDER BY позволяет сортировать строки результирующей таблицы.
Запросы с группировкой строк
Описанные в предыдущем уроке агрегатные функции применялись ко всей таблице. Однако часто при создании отчетов появляется необходимость в формировании промежуточных итоговых значений, то есть относящихся к данным не всей таблицы, а ее частей.
Именно для этого предназначена фраза GROUP BY. Она позволяет все множество строк таблицы разделить на группы по признаку равенства значений одного или нескольких столбцов (и выражений над ними). Фраза GROUP BY должна располагаться вслед за фразой WHERE (если она отсутствует, то за фразой FROM). Общий синтаксис фразы GROUP BY следующий:
GROUP BY выражение[. выражение]...
При наличии фразы GROUP BY фраза SELECT применяется к каждой группе, сформированной фразой группировки. В этом случае и действие агрегатных функций, указанных во фразе SELECT, будет распространяться не на всю результирующую таблицу, а только на строки в пределах каждой группы. Каждое выражение в списке фразы SELECT должно принимать единственное значение для группы, то есть оно может быть:
О константой;
О агрегатной функцией, которая оперирует всеми значениями аргумента в пределах группы и агрегирует их в одно значение (например, в сумму);
О выражением, идентичным стоящему во фразе GROUP BY;
О выражением, объединяющим приведенные выше варианты.
Рассмотрим возможности фразы GROUP BY, переходя от простых вариантов ее использования к более сложным.
Группировка по одному столбцу
Группировка по значениям одного столбца является самым простым вариантом использования фразы GROUP BY. Приведем примеры.
Запрос. Для каждого корпуса подсчитать количество находящихся в нем кафедр.
SELECT Building AS "Корпус".
COUNT(*) AS "К-во кафедр"
FROM DEPARTMENT
GROUP BY Building:
Корпус К-во кафедр
3
1
2
Запрос. Для каждой из должностей указать суммарный фонд заработной платы.
SELECT Post AS "Должность", SUMCSalary + Rise) AS "Сумма зарплаты"
FROM TEACHER
GROUP BY Post:
Должность Сумма зарплаты
ассистент2960
доцент4761
преподаватель3420
профессор4660
Если в запросе используются фразы и WHERE, и GROUP BY, строки, не удовлетворяющие условию фразы WHERE, исключаются до выполнения группировки. Вследствие этого группировка производится только по тем строкам, которые удовлетворяют условию.
Запрос. Для каждого корпуса подсчитать количество аудиторий с количеством мест больше 30.
SELECT Building AS "Корпус",
COUNTC*) AS "К-во аудиторий"
FROM ROOM
WHERE Seats > 30
GROUP BY Building:
Корпус К-во аудиторий
41
51
62
1
В случае многотабличных запросов сначала производится соединение таблиц, а затем их группировка. Приведем примеры.
Запрос. Вывести названия факультетов и суммарный фонд финансирования их кафедр.
SELECT f.Name AS "Факультет".
SUM(d.Fund) AS "Фонд кафедр"
FROM FACULTY f, DEPARTMENT d
WHERE f.FacPK = d.FacFK
GROUP BY f.Name;
Факультет Фонд кафедр
информатика48000
кибернетика51100
Запрос. Для каждого факультета, расположенного в корпусе 6, вывести количество групп и студентов пятого курса.
SELECT f.Name, CountC*), SUM(Quantity) FROM FACULTY f, DEPARTMENT d, SGROUP g WHERE f.FacPK = d.FacFK AND
d.DepPK = g.DepFK AND
f.Building = *6* AND
Year = 5 GROUP BY f.Name;
NAME COUNTC*) SUM(QUANTITY)
информатика 258
Группировка по нескольким столбцам
SQL позволяет группировать строки таблицы и по нескольким столбцам. В этом случае имена столбцов перечисляются во фразе GROUP BY через запятую.
Запрос. Вывести количество лекций, читаемых доцентами по неделям.
SELECT t.Name, l.Week, CountC*)
FROM TEACHER t, LECTURE 1
WHERE t.TchPK - l.TchFK AND LOWER(t.Post)= 'доцент*
GROUP BY t.Name, 1.Week;
NAME WEEK COUNTC*)
Завратинский11
Лекарь11
Лекарь21
Рамишевский11
Рамишевский21
Запрос. Для каждой кафедры и должности вывести суммарную и среднюю зарплату преподавателей.
SELECT d.Name AS "Кафедра",
t.Post AS "Должность",
SUMCt.Salary + t.Rise) AS "Сумма зарп.",
ROUNDCAVGCt.Salary + t.Rise), 1) AS "Сред, зарп."
FROM DEPARTMENT d, TEACHER t WHERE d.DepPK = t.DepFK GROUP BY d.Name, t.Post;
Кафедра
Должность
Сумма зарп. Сред.
. зарп.
программирование
ассистент
2960
740
программирование
доцент
3641
1213,7
программирование
преподаватель
2600
866,7
программирование
профессор
3110
1555
Даже при группировке по двум и более столбцам этот вариант фразы GROUP BY обеспечивает только один уровень группировки. Так, приведенный выше запрос обеспечивает только одну итоговую строку для пары значений кафедра-должность. Вычисление итоговых значений для групп различного уровня мы рассмотрим в уроке 10.
Использование выражений
Хотя стандарт SQL не допускает группировку по выражениям над столбцами, некоторые СУБД такую возможность предоставляют. В этом случае во фразе SELECT также можно использовать выражение группировки, однако нельзя выводить по отдельности столбцы, участвующие в этом выражении.
Запрос. Для каждого значения зарплаты, не превышающего 800, вывести это значение и количество преподавателей, такую зарплату получающих.
SELECT Salary + Rise, COUNT(*)
FROM TEACHER ‘
WHERE Salary + Rise <« 800
GROUP BY Salary + Rise;
SALARY+RISE COUNTC*)
7201
7401
7502
8001
Запрос. Для каждой группы ассистентов кафедры программирования, фамилии которых начинаются на одну букву, вывести эту букву, количество преподавателей и их суммарную зарплату.
SELECT UPPER(SUBSTR(t.Name, 1, D) AS "Б". COUNT(*) AS "Количество”, SUMCSalary + Rise) AS "Зарплата"
FROM TEACHER t, DEPARTMENT d
WHERE t.DepFK = d.DepPK AND
LOWER(d.Name) = 'программирование* AND UPPER(t.Post) = 'АССИСТЕНТ*
GROUP BY UPPER(SUBSTR(t.Name, 1, 1));
Б Количество Зарплата
В21460
К1750
М1750
Вложение агрегатных функций
Если фраза GROUP BY в запросе отсутствует, то во фразе SELECT нельзя вкладывать агрегатные функции друг в друга. Например, следующий запрос приведет к ошибке:
SELECT AVG(MIN(Salary))
FROM TEACHER;
0RA-00978: вложенная групповая функция без GROUP BY
Однако при наличии фразы GROUP BY такое вложение допускается. Оно интерпретируется следующим образом: сначала для каждой группы выполняется вложенная агрегатная функция, затем к полученной таким образом промежуточной таблице применяется внешняя агрегатная функция. Двойное вложение, например MAX(AVG(MIN(Salагу))), недопустимо. Приведем пример.
Запрос. Вывести среднее значение среди минимальных и максимальных ставок для каждой группы преподавателей, занимающих одну должность, а также минимальное и максимальное значения среди средних ставок.
SELECT AVGCMIN(Salary)) AS AVG_MIN,
AVG(MAX(Sal агу)) AS AVG_MAX, MIN(AVG(Salary)) AS MIN_AVG, MAX(AVGCSalary)) AS MAX_AVG FROM TEACHER
GROUP BY Post;
AVG_MIN AVG_MAX MIN_AVG MAX_AVG
730 807,5550 1073,33333
Так как в результате вложения агрегатных функций получается таблица с одной строкой, что еще можно указать для вывода во фразе SELECT? Только агрегатную функцию, примененную к выражению группировки (но не само выражение группировки).
Запрос. Вывести последнюю и первую по алфавиту должности, а также среднее значение минимальных ставок каждой должности.
SELECT MAX(Post) AS MAX_POST,
MIN(Post) AS MIN_POST, AVG(MIN(Salary)) AS AVG_MIN FROM TEACHER
GROUP BY Post:
MAX_POST MIN_POST AVG_MIN
профессор ассистент 730
Следующий запрос, в котором во фразе SELECT указан вывод группируемого столбца, является ошибочным:
SELECT Post, AVG(MIN(Salary)) AS AVG_MIN
FROM TEACHER
GROUP BY Post;
SELECT Post, AVG(MIN(Salary)) AS AVG_MIN *
Ошибка в строке 1:
0RA-00937: групповая функция не является одногруппной
Значение NULL в столбцах группировки
Значение NULL не равно ничему, даже самому себе. То есть значение выражения NULL = NULL не равно TRUE (подробно интерпретация значения NULL приводится в уроке 10). Если придерживаться этого правила, то при группировке по столбцу, содержащему NULL, возникают проблемы. Дело в том, что каждая строка, содержащая NULL в столбце группировки, должна рассматриваться как отдельная группа, что неудобно практически. В связи с этим в стандарте SQL определено: при группировке значение NULL следует считать равным себе. Приведем пример.
Запрос. Для каждого имеющегося номера телефона указать количество преподавателей, которые им пользуются.
SELECT COALESCE (Tel. 'NULL VALUE') AS "Телефоны". Count(*)
FROM TEACHER
GROUP BY Tel;
Телефоны COUNT(*)
45678902
34567891
23456782
12345675
NULL VALUE5
Как видим, пятеро преподавателей не пользуются указанными номерами телефонов и все эти строки сгруппированы в одну. Это правило остается в силе и в случае группировки по нескольким столбцам.
Запрос. Вывести суммарную зарплату для каждой из групп ассистентов, имеющих одинаковые идентификационные номера и телефоны.
SELECT COALESCE(IDCode, 'отсутствует') AS IDCode,
COALESCE(Tel, 'отсутствует') AS Telephone, AVG(Salary + Rise)
FROM TEACHER
WHERE LOWER(Post) = 'ассистент*
GROUP BY IDCode, Tel;
IDCODE TELEPHONE AVG(SALARY+RISE)
2345678901
отсутствует
740
7890123456
1234567
750
6789012345
1234567
750
отсутствует
отсутствует
720
Условие отбора групп
Предположим, что нужно узнать номера корпусов, суммарное количество мест в аудиториях которых превышает 100. Приведенная ниже формулировка запроса является неверной:
SELECT Building
FROM ROOM
WHERE SUM(Seats) > 100
GROUP BY Building;
WHERE SUM(Seats) > 100 *
Ошибка в строке 3:
0RA-00934: групповая функция здесь не разрешена
Дело в том, что фраза WHERE проверяет на соответствие условию строки исходных таблиц, а мы указали в ней агрегатную функцию. Для отбора строк среди полученных групп следует применять фразу HAVING. Она играет такую же роль для групп, что и фраза WHERE для исходных таблиц, и может использоваться лишь при наличии фразы GROUP BY. В предложении SELECT фразы WHERE, GROUP BY и HAVING обрабатываются в следующем порядке.
Фразой WHERE отбираются строки, удовлетворяющие указанному в ней условию.
Фраза GROUP BY группирует отобранные строки.
Фразой HAVING отбираются группы, удовлетворяющие указанному в ней условию.
В связи с вышесказанным, предыдущий запрос необходимо записать так.
Запрос. Указать корпуса, суммарное количество мест в аудиториях которых превышает 100.
SELECT Building
FROM ROOM
GROUP BY Building
HAVING SUM(Seats) > 100;
BUILDING
6
Уникальность условия отбора
Значение условия, указываемого во фразе HAVING, должно быть уникальным для всех строк каждой группы. Поэтому правила использования имен столбцов и агрегатных функций во фразе HAVING такие же, как и для фразы SELECT при наличии фразы GROUP BY. Это значит, что во фразе HAVING в качестве операндов сравнения можно использовать только группируемые столбцы или агрегатные функции. Рассмотрим пример.
Запрос. Вывести номера корпусов, суммарное количество мест в аудиториях которых превышает 100. При этом учитывать только аудитории с количеством мест больше 30.
SELECT Building
FROM ROOM
GROUP BY Building
HAVING Seats > 30 AND SUM(Seats) > 100;
HAVING Seats > 30 AND SUM(Seats) > 100 *
Ошибка в строке 4:
ORA-00979: выражение не является выражением GROUP BY
Приведенный запрос оказался неверным потому, что значения столбца Seats не являются уникальными в пределах одной группы, а значит, и условие Seats > 30
не будет иметь в пределах группы единственного значения. Приведем правильный вариант запроса.
SELECT Building
FROM ROOM
WHERE Seats > 30
GROUP BY Building
HAVING SUM(Seats) > 100:
BUILDING
6
Использование столбцов группировки во фразе HAVING
Рассмотрим использование во фразе HAVING условий отбора, заданных для группируемых столбцов (или выражений над ними). Для этого усложним предыдущий запрос.
Запрос. Выяснить, в каких из корпусов 1, 6, 7 и 8 суммарное количество мест в аудиториях превышает 100. При этом учитывать только аудитории с количеством мест больше 30.
SELECT Building
FROM ROOM
WHERE Seats > 30
GROUP BY Building
HAVING Building IN ('Г. '6'. '7'. '8') AND SUM(Seats) > 100;
BUILDING
6
Рассмотрим несколько еще более сложных примеров использования фраз GROUP BY и HAVING.
Запрос. Вывести названия факультетов, фонды финансирования которых более чем на 20 000 меньше суммарного фонда финансирования всех их кафедр. Указать также фонд финансирования факультета, суммарный фонд финансирования всех его кафедр и разницу между этими значениями.
SELECT f.Name, f.Fund. SUM(d.fund), f.Fund - SUM(d.fund)
FROM FACULTY f. DEPARTMENT d
WHERE f.FacPK = d.FacFK
GROUP BY f.Name. f.Fund
HAVING f.Fund < SUM(d.fund) + 20000;
NAME FUND SUM(D.FUND) F.FUND-SUM(D.FUND)
информатика 2500048000-23000
кибернетика 2700051100-24100
Обратите внимание, что группировка по фонду факультета не создает новых групп по отношению к группировке по названию факультета, так как на каждом факультете имеется только один фонд финансирования. Нам пришлось указать группировку по фонду факультета только из-за того, что этот столбец указан во
фразе SELECT, а в ней могут присутствовать только те столбцы, по которым производится группировка.
Запрос. Вывести названия кафедр факультета информатики, на которых работают два и более профессоров. Указать также количество профессоров и их суммарную зарплату.
SELECT d.Name, Count(*), SUMCt.salary + t.Rise)
FROM FACULTY f, DEPARTMENT d, TEACHER t
WHERE f.FacPK - d.FacFK AND d.DepPK - t.DepFK AND
LOWER(f.Name) - 'информатика* AND
LOWER(t.Post) - 'профессор*
GROUP BY d.Name/
HAVING COUNT(*) > 1: *
NAMECOUNT(*) SUMCT.SALARY+T.RISE)
программирование 23110
Фраза HAVING без фразы GROUP BY
Выше мы указали, что фраза HAVING может использоваться лишь при наличии фразы GROUP BY. Из этого правила синтаксис SQL допускает только одно исключение: когда вся таблица интерпретируется как одна группа. В этом случае в списке фразы SELECT можно использовать только константы, агрегатные функции и выражения над ними. Приведем примеры.
Запрос. Если суммарная зарплата всех преподавателей превышает 15 000, вывести их минимальную ставку, максимальную надбавку и суммарную зарплату.
SELECT MIN(Salary), MAX(Rise), SUM(Salary + Rise)
FROM TEACHER
HAVING SUM(Salary + Rise) > 15000;
MIN(SALARY) MAX(RISE) SUM(SALARY+RISE)
53050015801
При наличии фразы WHERE сначала производится отбор строк согласно ее условию, и только после этого применяется условие фразы HAVING.
Запрос. Если суммарная зарплата всех ассистентов превышает 2500, вывести их среднюю ставку, среднюю надбавку и суммарную зарплату.
SELECT AVG(Salary), AVG(Rise). SUM(Salary + Rise)
FROM TEACHER
WHERE LOWER(Post) = 'ассистент*
HAVING SUM(Salary + Rise) > 2500;
AVG(SALARY) AVG(RISE) SUM(SALARY+RISE)
5501902960
На практике фраза HAVING очень редко используется без фразы GROUP BY, из-за чего такая возможность предоставляется не во всех СУБД.
Сортировка результирующих строк
Как мы уже отмечали, строки в таблицах базы данных неупорядочены. Также не- упорядочены и строки результирующей таблицы запроса, однако для их упорядочения в предложении SELECT можно воспользоваться фразой ORDER BY. Она сортирует по значению указанных в ней столбцов (и выражений над столбцами) строки результирующей таблицы запроса. Синтаксис этой фразы следующий:
ORDER BY спецификация_сортировки[, спецификация_сортировки]...
где спецификация_сортировки имеет такой синтаксис:
выражение_сортировки [направление_сортировки] [положение-NULL]
Сортировать можно по столбцам (выражениям) тех типов, для которых определены операции сравнения. Это относится, в частности, к символьным строкам, числам и временным значениям. Можно указывать направление сортировки и место расположения строк, имеющих значение NULL для выражений сортировки.
Далее в этом уроке мы рассмотрим общие способы упорядочения результирующих строк. Правила и возможности сортировки при использовании теоретико-множественных операторов изучаются в уроке 9, сортировка при использовании иерархических запросов рассматривается в уроке 10.
Сортировка по столбцу или выражению
Сортировать строки результирующей таблицы запроса можно по отдельным столбцам, совокупности столбцов, а также по одному или нескольким выражениям над столбцами. Ниже рассматриваются все эти варианты.
Сортировка по столбцу
Простейший вариант сортировки — это сортировка по одному из столбцов результирующей таблицы.
Запрос. Вывести алфавитный список фамилий профессоров и доцентов.
SELECT Name
FROM TEACHER
WHERE LOWER(Post) = 'профессор* OR LOWER(Post) = 'доцент*
ORDER BY Name;
NAME
Ахромеев
Завратинский
Лекарь
Наумов
Рамишевский
Резван
Сидоров
Запрос. Вывести номера групп и их рейтинг по возрастанию рейтинга.
SELECT Num. Rating
FROM SGROUP
ORDER BY Rating;
NUM RATING
20143
30748
50455
40856
50567
Сортировка по выражению над столбцами
Упорядочивать строки можно не только по значению столбца, но и по значению выражения над столбцами.
Запрос. Вывести фамилии ассистентов и их зарплату по ее возрастанию.
SELECT Name, Salary + Rise
FROM TEACHER
WHERE LOWER(Post) - 'ассистент*
ORDER BY Salary + Rise:
NAME SALARY+RISE
Воропаев720
Вибровский740
Козлутин750
Мартынов750
Сортировка по столбцу, отсутствующему в результирующей таблице
SQL позволяет упорядочивать строки результирующей таблицы не только по тем столбцам, которые в ней присутствуют, но и по столбцам исходной таблицы и выражениям над ними. Эту ситуацию можно проинтерпретировать следующим образом.
Если столбец (выражение) сортировки отсутствует в списке фразы SELECT, он неявно добавляется в него.
Производится указанная сортировка.
Добавленный столбец удаляется из результирующей таблицы.
Запрос. Вывести фамилии ассистентов по возрастанию их зарплаты.
SELECT Name
FROM TEACHER
WHERE LOWER(Post) = 'ассистент*
ORDER BY Salary + Rise:
NAME
Воропаев Вибровский Козлутин Маотынов
Как видим, строки выведены в том же порядке, что и в предыдущем запросе, хотя столбцы выражения сортировки отсутствуют в результирующей таблице.
Запрос. Вывести по порядку дни недели, в которые проходят занятия.
SELECT DISTINCT Day FROM LECTURE ORDER BY Day;
DAY
втр пнд ПТН срд чтв
Запрос выполняется, но дни недели упорядочены не по алфавиту, а это не то, что нам нужно. Возможное решение — воспользоваться функцией DECODE, с помощью которой каждому дню недели можно поставить в соответствие порядковый номер и отсортировать результат по этим номерам.
SELECT DISTINCT Day
FROM LECTURE
ORDER BY DECODE(LOWER!Day). 'пнд', 1. 'втр'. 2, 'срд'. 3, 'чтв'. 4, ''птн*, 5. 'суб'. 6. 'вое*, 7);
DAY
пнд втр срд чтв ПТН
Указание порядкового номера столбца сортировки
Столбец сортировки может быть указан не только его именем, но и его порядке- вым номером в списке фразы SELECT. Это оказывается полезным в том случае, когда необходимо сортировать не по столбцу, а по выражению. Так, если в предыдущем примере нужно было бы вывести и номер дня недели, функцию DECODE следовало дополнительно применить и во фразе SELECT. Для избежания повторного написания (и выполнения) этой функции укажем ее один раз в списке фразы SELECT, а во фразе ORDER BY укажем ее порядковый номер в этом списке.
Запрос. Вывести по порядку полные названия дней недели, в которые проходят занятия.
SELECT DISTINCT
DECODE(LOWER(Day). 'пнд', 'понедельник*, 'втр', 'вторник', 'срд', 'среда', 'чтв', 'четверг', 'птн', 'пятница', 'суб', 'суббота', 'вое', 'воскресенье') AS ДЕНЬ,
DECODE(LOWERCDay), 'пнд', 1, 'втр', 2, 'срд', 3. 'чтв*, 4, 'птн', 5. 'суб', б, 'вое', 7) AS НОМЕР
FROM LECTURE
ORDER BY 2:
понедельникпонедельник1234512345ДЕНЬ НОМЕР
понедельник
понедельник
1
2
3
4
5
1
2
3
4
5
вторник среда
четверг пятница
Использование для сортировки синонима столбца
Если сортировка производится по столбцу или выражению, указанному в списке фразы SELECT, для указания сортируемого столбца (выражения) во фразе ORDER BY можно воспользоваться синонимом. Например, сортировку по синониму в предыдущем запросе можно указать как ORDER BY НОМЕР.
Направление сортировки
Во всех до сих пор приводимых примерах сортировка производилась в порядке возрастания значений. В SQL такой порядок определен по умолчанию. Однако есть возможность и явно указать направление сортировки с помощью ключевых слов ASC (по возрастанию) и DESC (по убыванию), которые следует располагать после имени сортируемого столбца (выражения).
Запрос. Вывести фамилии ассистентов и дату их приема на работу по возрастанию даты.
SELECT Name, Hi reDate
FROM TEACHER
WHERE LOWER(Post) = 'ассистент'
ORDER BY Hi reDate ASC;
NAME HIREDATE
Козлутин 04.07.2001
Воропаев 02.09.2002
Мартынов 22.10.2002
Вибровский 01.09.2003
Запрос. Вывести фамилии доцентов в обратном алфавитном порядке и их зарплату.
SELECT Name AS Фамилия, Salary + Rise AS Зарплата
FROM TEACHER
WHERE LOWER(Post) = 'доцент'
ORDER BY Name DESC;
ФАМИЛИЯ ЗАРПЛАТА
Рамишевский1200
Наумов1120
Лекарь1330
Завратинский1111
Сортировка значения NULL
Так как значение NULL не равно никакому другому значению, стандарт SQL предоставляет возможность явно указать его расположение. Для этого используются
ключевые слова NULLS FIRST (в начале) или NULLS LAST (в конце), которые располагаются вслед за указанием направления сортировки.
По умолчанию используется NULLS LAST при упорядочении по возрастанию и NULLS FIRST при упорядочении по убыванию. Приведем возможные варианты.
Запрос. Вывести фамилии и идентификационные коды ассистентов в порядке кодов.
SELECT Name. IDCode
FROM Teacher
WHERE LOWER(Post) = 'ассистент'
ORDER BY IDCode ASC NULLS FIRST;
NAME IDCODE
Воропаев
Вибровский 2345678901
Козлутин 6789012345
Мартынов 7890123456
SELECT Name. IDCode
FROM Teacher
WHERE LOWER(Post) = 'ассистент'
ORDER BY IDCode ASC NULLS LAST;
NAME IDCODE
Вибровский 2345678901
Козлутин 6789012345
Мартынов 7890123456
Воропаев
Запрос. Вывести фамилии и идентификационные коды ассистентов по уменьшению кодов.
SELECT Name. IDCode
FROM Teacher
WHERE LOWER(Post) = 'ассистент*
ORDER BY IDCode DESC NULLS FIRST;
NAME IDCODE
Воропаев
Мартынов 7890123456
Козлутин 6789012345
Вибровский 2345678901
SELECT Name, IDCode
FROM Teacher
WHERE LOWER(Post) = 'ассистент'
ORDER BY IDCode DESC NULLS LAST;
NAME IDCODE‘
Мартынов 7890123456
Козлутин 6789012345
Вибровский 2345678901
Воропаев
Сортировка по нескольким столбцам
Для упорядочения строк результирующей таблицы по нескольким столбцам следует во фразе ORDER BY привести список этих столбцов. Для каждого из них можно также указать направление сортировки и расположение строк со значениями NULL. При упорядочении по нескольким столбцам сначала производится сортировка строк в указанном порядке по первому столбцу из списка, затем набор строк с одинаковым значением отсортированного столбца сортируется по второму столбцу и т. д. Запрос. Вывести номера телефонов и фамилии преподавателей. Упорядочить по убыванию номеров телефонов и по возрастанию фамилий.
SELECT Tel. Name
FROM TEACHER
ORDER BY Tel DESC, Name;
TEL NAME
Вибровский Воропаев Завратинский Сидоров Хоренко 4567890 Кузинцев 4567890 Рамишевский 3456789 Дараганов 2345678 Ахромеев 2345678 Наумов 1234567 Козлутин 1234567 Лекарь 1234567 Мартынов 1234567 Недеведеев 1234567 Резван
Строки со значениями NULL в результате расположены в положении по умолчанию.
Сортировка и группировка
Если фраза ORDER BY используется в предложении SELECT вместе с фразой GROUP BY, правила формирования выражений сортировки такие же, как и правила формирования выражений в списке фразы SELECT. То есть в этом случае в качестве выражений во фразе ORDER BY можно использовать:
О константы;
О агрегатные функции;
О выражения, указанные во фразе GROUP BY;
С) выражения, объединяющие приведенные выше варианты.
Запрос. Показать количество студентов на каждом курсе, упорядочив по уменьшению количества.
SELECT Year, SUM(Quanti'ty)
FROM SGROUP
GROUP BY Year
ORDER BY SUM(Quantity) DESC:
YEAR SUM(QUANTITY)
5234523458
5
2
3
4
5
2
3
4
35
33
27
Определение упорядоченности символов
Чтобы сортировать символьные строки, следует определить порядок символов. Возможности SQL по работе с наборами символов кратко описаны в уроке 1. Конкретные СУБД, как правило, предоставляют свои возможности определения упорядоченности символов, в том числе для национальных алфавитов.
Порядок может быть также указан в конкретном запросе при использовании во фразе ORDER BY соответствующих функций. Выше приводились примеры использования функции DECODE для указания порядка сортировки дней недели. Этой функцией можно воспользоваться для указания сортировки небольшого количества строк символов. Более мощной является функция TRANSLATE, с помощью которой можно определить последовательность сортировки символов. Приведем пример.
Запрос. Вывести фамилии преподавателей в следующем порядке: для первых 10 букв русского алфавита в обратном порядке, для остальных — согласно алфавиту.
SELECT Name
FROM TEACHER
ORDER BY TRANSLATE(UPPER(Name). 'АБВГДЕЖЗИК'. 'КИЗЖЕДГВБА');
NAME
Козлутин
Кузинцев
Завратинский
Дараганов
Вибровский
Воропаев
Ахромеев
Лекарь
Мартынов
Недеведеев
Наумов
Резван
Рамишевский
Сидоров
Хоренко
Обратите внимание на сортировку вторых букв при совпадающей первой.
Самостоятельная работа
Для каждого преподавателя вывести количество читаемых дисциплин.
Вывести количество занятий в каждый день недели.
Для каждого курса вывести средний рейтинг групп.
Для каждого корпуса подсчитать количество располагающихся в нем кафедр и минимальный фонд финансирования среди этих кафедр.
Для каждого факультета вывести количество дисциплин, читаемых их преподавателями.
Для каждого факультета вывести количество читаемых для их студентов дисциплин.
Для каждой пары значений преподаватель-аудитория вывести количество лекций.
Вывести номера корпусов, если суммарный фонд финансирования расположенных в них кафедр превышает 100 000.
Вывести номера групп пятого курса кафедры программирования, которые имеют более 10 пар в первую неделю.
Вывести названия предметов и группы, в которых эти предметы читаются. Упорядочить по названиям предметов в алфавитном порядке, по номерам групп по убыванию.
И. Вывести фамилии преподавателей, отсортировав их по номерам курсов и номерам групп, в которых они являются кураторами.
Вывести фамилии преподавателей согласно следующему порядку букв (как прописных, так и строчных): ЭЮЯМНОПРСТУФХЦЧШЩАБВГДЕЖЗИЙ КЛЪЫЬ.
Подведение итогов
Усвоив материал этого урока, вы научились:
0 формулировать запросы с группировкой по отдельным столбцам или выражениям;
0 использовать группировку по нескольким столбцам или выражениям;
0 вкладывать агрегатные функции друг в друга;
0 группировать по* значению NULL;
0 задавать условия для отбора групп;
0 сортировать результаты запроса по отдельным столбцам и выражениям;
0 сортировать по нескольким столбцам и выражениям;
0 сортировать по столбцам и выражениям, отсутствующим в результирующей таблице;
0 использовать синонимы столбцов и их порядковые номера для указания сортировки;
0 указывать направление сортировки;
0 сортировать значения NULL;
0 использовать функции для указания специфической сортировки.
^ ) УРОК Вложенные запросы
SQL позволяет вкладывать одни запросы в другие, используя тем самым результаты вычисления одних запросов в других запросах. Вложенный запрос — это заключенный в круглые скобки запрос, присутствующий во фразах WHERE, HAVING, FROM или START WITH предложения SELECT или других предложений, использующих эти фразы. Вложенный запрос еще называют подзапросом или дочерним запросом, а запрос, внешний к вложенному, называют также родительским или внешним.
Подзапросы разделяются на два вида — простые и связанные (или коррелированные). Они различаются также по фразам, в которых встречаются. Подзапросы используются в следующих случаях:
О получение множества значений для условия фраз WHERE и HAVING предложения SELECT, а также предложений UPDATE и DELETE (см. урок 13);
О получение входной таблицы запроса во фразе FROM предложений SELECT, INSERT, UDPATE и DELETE;
О вставка множества строк в целевую таблицу в предложениях INSERT и CREATE TABLE (см. уроки 11 и 13);
О определение одного или множества значений, которые приписываются существующим строкам в предложении UPDATE (см. урок 13);
О определение множества строк представления в предложении CREATE VIEW (см. урок 14).
Особым случаем использования вложенного запроса является его включение в список фразы SELECT (такой подзапрос должен быть скалярным).
Далее мы детально рассмотрим возможности простых и связанных подзапросов во фразе WHERE, а затем рассмотрим специфику их использования во фразах HAVING и FROM. Следует отметить, что SQL обладает большой избыточностью — он часто предоставляет возможность нескольких вариантов формулировки одного и того же запроса. Это относится и к вложенным запросам. Один из разделов этого урока посвящен описанию вариантов представления вложенных запросов.
Подзапросы во фразе WHERE
Во фразу WHERE (и фразу HAVING) подзапросы включаются с помощью операторов IN, EXISTS, ALL, SOME, ANY или одного из операторов сравнения (=, <>, <, <=, >, >=). Здесь мы рассмотрим использование операторов сравнения и оператора IN, остальные будут рассмотрены в следующем уроке.
Простые подзапросы
Простым вложенным запросом называется такой, результат которого не зависит от внешнего запроса. Такие подзапросы обрабатываются системой «снизу вверх» — первым обрабатывается подзапрос самого нижнего уровня, полученное множество значений используется в подзапросе более высокого уровня и т. д.
Вложение с использованием операторов сравнения
В этом случае подзапрос должен возвращать единственное значение, которое и сравнивается со значением столбца внешнего запроса.
Запрос. Вывести названия всех кафедр, расположенных в том же корпусе, что и факультет информатики.
SELECT Name
FROM DEPARTMENT
WHERE Building = (SELECT Building
FROM FACULTY
WHERE LOWER(Name) = 'информатика');
NAME
базы данных программирование
Если подзапрос вернет более одного значения, произойдет ошибка. Приведем пример.
Запрос. Вывести названия кафедр, расположенных в тех же корпусах, что и факультеты информатики или кибернетики.
SELECT Name
FROM DEPARTMENT
WHERE Building - (SELECT Building
FROM FACULTY
WHERE LOWER(Name) = 'информатика' OR LOWER(Name) = 'кибернетика');
WHERE Building = (SELECT Building
ошибка в строке 3:
ORA-01427: подзапрос одиночной строки возврашает более одной строки
В этом случае следует использовать оператор IN (что рассмотрено ниже) или записать запрос с использованием соединения таблиц.
SELECT d.Name
FROM FACULTY f. DEPARTMENT d
WHERE f.FacPK = d.FacFK AND
f.Building = d.Building AND (LOWER(f.Name) = 'информатика' OR
LOWER(f.Name) = 'кибернетика');
NAME
базы данных программирование базы данных
Можно использовать любые операторы сравнения, однако следите, чтобы подзапрос возвращал единственное значение.
Запрос. Вывести названия факультетов, фонды финансирования которых меньше фонда финансирования кафедры баз данных факультета информатики.
SELECT Name
FROM FACULTY
WHERE Fund < (SELECT d.Fund
FROM FACULTY f. DEPARTMENT d
WHERE f.FacPK = d.FacFK AND
LOWER(f.Name) = 'информатика* AND LOWER(d.Name) = 'базы данных');
NAME
информатика
математика
Обратите внимание — во всех приведенных выше запросах сначала вычисляется подзапрос, затем полученное значение используется в предикате внешнего запроса. Именно в этом суть простых запросов.
Использование одной таблицы во внешнем и вложенном запросе
Внешний и вложенный запросы могут использовать одну и ту же таблицу.
Запрос. Вывести фамилии преподавателей, имеющих большую ставку, чем Ах- ромеев.
SELECT Name FROM TEACHER
WHERE Salary > (SELECT Salary FROM TEACHER
WHERE UPPER(Name) = 'AXPOMEEB');
NAME"
Сидоров
Резван
Отметим, что имя TEACHER в запросе и подзапросе означает различные вхождения одной таблицы. Чтобы показать это явно, можно использовать синонимы таблиц, например:
SELECT x.Name FROM TEACHER x
WHERE x.Sal ary > (SELECT y.Sal ary FROM TEACHER у
WHERE UPPER(y.Name) = 'AXPOMEEB');
Запрос. Вывести номера групп, имеющих больший рейтинг, чем группа 504.
SELECT Num FROM SGROUP
WHERE Rating > (SELECT Rating FROM SGROUP WHERE Num = 504):
NUM
505
408
Сравнивать можно значения не только столбцов, но и любых допустимых над ними выражений.
Запрос. Вывести фамилии преподавателей, зарплата которых более чем на 100 превышает удвоенную зарплату Воропаева.
SELECT Name FROM TEACHER
WHERE Salary + Rise - 100 >
(SELECT (Salary + Rise) * 2 FROM TEACHER WHERE UPPER(Name) = 'ВОРОПАЕВ');
NAME
Резван
Ахромеев
Обратимость предикатов с подзапросами
Долгое время в SQL существовало следующее ограничение — подзапрос должен располагаться только справа от оператора сравнения, что выражается таким синтаксисом:
выражение_над_столбцами оператор подзапрос
Сейчас это ограничение снято и подзапрос можно располагать слева, то есть в соответствии с таким синтаксисом:
подзапрос оператор выражение_над_столбцами
Например, последний приведенный запрос можно записать в следующем виде:
SELECT Num FROM SGROUP
WHERE (SELECT Rating FROM SGROUP
WHERE Num = 504) < Rating;-
Более того, можно использовать подзапросы с обеих сторон оператора сравнения, то есть в соответствии с таким синтаксисом:
подзапрос оператор подзапрос
Для простых вложенных запросов этот вариант является возможным, но бессмысленным — такое выражение будет принимать истинностное значение, не зависящее от внешнего запроса. Приведем пример:
SELECT Name FROM FACULTY
WHERE (SELECT COUNT(*) FROM DEPARTMENT) <> (SELECT COUNT(*) FROM TEACHER);
Если количество кафедр действительно не равно количеству преподавателей, то будут просто выведены все факультеты, иначе не будет выведено ничего.
Вложенный запрос в операторе IN
Предикат IN уже рассматривался. Напомним — он проверяет вхождение элемента во множество, в качестве элемента может выступать имя столбца или скалярное выражение, а в качестве множества — явно заданный список значений или подзапрос. Использование подзапроса в качестве второго операнда IN позволяет избежать ограничения на единственность значения, возвращаемого подзапросом.
Запрос. Вывести названия факультетов, расположенных в тех же корпусах, что и кафедры программирования и лингвистики.
SELECT Name FROM FACULTY
WHERE Building IN (SELECT Building FROM DEPARTMENT
WHERE LOWER(Name) = 'программирование* ORLOWER(Name) = 'лингвистика');
NAME
математика
информатика
Так как кафедры программирования и лингвистики могут располагаться в разных корпусах, следует воспользоваться оператором IN, а не оператором равенства.
Запрос. Вывести названия кафедр, расположенных в тех же корпусах, что и кафедры факультета информатики.
SELECT Name
FROM DEPARTMENT
WHERE Building IN
(SELECT d.Building
FROM DEPARTMENT d. FACULTY f
WHERE d.FacFK = f.FacPK AND
LOWER(f.Name) = 'информатика');
NAME
интернет теория языков лингвистика базы данных программирование
В этом примере во вложенном запросе соединяются две таблицы, чтобы получить корпуса кафедр факультета информатики. В результате присутствуют и кафедры самого факультета информатики. Если они не нужны, избавиться от них можно включением во внешний запрос еще одного условия:
SELECT DISTINCT Name FROM DEPARTMENT
WHERE Building IN (SELECT d.Building FROM DEPARTMENT d. FACULTY f
WHERE d.FacFK = f.FacPK AND
LOWER(f.Name) = 'информатика')
AND DepPK NOT IN (SELECT DepPK FROM DEPARTMENT d. FACULTY f WHERE d.FacFK = f.FacPK AND
LOWER(f.Name) = 'информатика')';
NAME
теория языков лингвистика
Второй вложенный запрос выбирает множество кафедр факультета информатики (их первичные ключи), а с помощью предиката NOT IN указывается, что такие кафедры не должны быть включены в результирующую таблицу.
В операторе IN можно использовать и подзапрос, возвращающий единственное значение. Вообще, в любой ситуации, где используется оператор сравнения =, можно использовать оператор IN, причем в этом случае не будет возникать ошибка, когда подзапрос возвращает множество значений. Здесь есть и преимущества, и недостатки. Преимущества очевидны — вы не беспокоитесь относительно возможных ошибок. Однако если семантика вашей предметной области такова, что подзапрос" всегда должен выдавать единственное значение, при использовании оператора IN вы можете пропустить ошибки, существующие в данных. В этом случае вы получите некорректный результат, так как успешно исполняемый подзапрос будет базироваться на некорректных исходных данных. Если же вы воспользуетесь оператором -, получите отказ с выводом сообщения об ошибке и он будет для вас сигналом о неправильном состоянии базы данных.
Например, необходимо узнать, в каких других аудиториях проводятся лекции по тому же предмету, который читается в аудитории 201 корпуса 6 во вторник на 4-й паре нечетной недели:
SELECT DISTINCT Num
FROM ROOM г, LECTURE 1
WHERE r.RomPK = l.RomFK AND
1.SbjFK IN (SELECT SbjFK
FROM LECTURE Lee. ROOM Rom
WHERE Lee.RomFK = Rom.RomPK AND
Rom. Num = 201 AND
Rom.Building = '6' AND LOWER(Day) = 'втр' AND Lesson = 4 AND Week = 1)
AND NOT r.Num = 201:
Кратко прокомментируем текст запроса. Для ответа на поставленный вопрос необходимы таблицы аудиторий и лекций, так как значения из первой необходимо вывести, а на второй заданы условия. Поэтому мы их соединяем — и во внешнем, и во вложенном запросах. Таблица лекций содержит данные о читаемом предмете — столбец SbjFK. Поэтому обращения к таблице предметов не нужно, достаточно сравнить значения этого столбца. Наконец, с помощью последней строки фразы WHERE внешнего запроса из результата исключается сама аудитория 201.
В результате вычисления этого запроса вы можете не получить ни одного номера аудитории (это означает, что либо в аудитории 201 корпуса 6 на 4-й паре нечетной недели вообще нет занятий, либо предмет, который читается на этой паре нечетной недели, в других аудиториях не читается) или несколько номеров. Если с базой данных все в порядке, вы получите именно то, что искали. Однако если в базе данных из-за недостаточного обеспечения ее целостности в таблице LECTURE окажется несколько строк с данными о том, что в аудитории 201 корпуса 6 на 4-й паре нечетной недели проводятся занятия по разным предметам, вы получите некорректный результат.
Поэтому если из-за семантики предметной области подзапрос не должен выдавать множество значений, лучше использовать оператор =. В этом случае сообщение ошибке типа подзапрос одиночной строки возвращает более одной строки означает, что состояние данных некорректно и необходимо обратиться к администратору базы данных для снятия этой некорректности и формулировки дополнительных ограничений, которые бы не допускали этого в будущем.
Табличные вложенные запросы
До сих пор мы сравнивали значения отдельных столбцов внешнего запроса с результатом подзапроса, который также возвращает значение одного столбца. Однако в SQL такое сравнение предусмотрено и для нескольких столбцов. При этом применимы операторы равенства (=), неравенства (<>) и вхождения во множество (IN). Обобщенный синтаксис в этом случае имеет следующий вид:
(списоК-Выражений) {= | <> | [NOT] IN) (подзапрос)
Истинность операции = означает совпадение результата подзапроса со всеми значениями из списка выражений, операции <> — что хотя бы одно значение из списка выражений не совпадает с результатом подзапроса, а оператора IN — указывает на совпадение всех значений из списка выражений хотя бы для одной строки возвращаемой подзапросом таблицы.
Запрос. Вывести фамилии преподавателей, имеющих ту же должность и телефон, что и Козлутин.
SELECT Name FROM TEACHER
WHERE (Post. Tel) = (SELECT Post, Tel FROM TEACHER
WHERE UPPER(Name) = 'КОЗЛУТИН') AND UPPER(Name) <> 'КОЗЛУТИН';
NAME
Мартынов
Запрос. Вывести номера групп, куратор или кафедра которых не совпадают с куратором и кафедрой группы 307.
SELECT Num FROM SGROUP
WHERE (DepFK, CurFK) <> (SELECT DepFK, CurFK FROM SGROUP
WHERE Num =307);
NUM
505
504
201
Группа 408 не выведена, так как у нее тот же куратор и кафедра, что и у группы 307.
Возврат подзапросом пустого множества
Если подзапрос возвратит пустое множество строк, то предикат, использующий этот подзапрос, примет логическое значение UNKNOWN. Какое именно логическое значение примет в этом случае условие фразы WHERE, зависит от структуры условия (это имеет отношение к правилам трехзначной логики, которые будут рассмотрены в уроке 10). Если это условие примет значение UNKNOWN или FALSE, ни одна строка таблицы внешнего запроса не будет включена в результат, то есть он будет пустым.
Коррелированные подзапросы
Коррелированным вложенным запросом называется такой, результат которого зависит от результата внешнего запроса. Подзапрос является коррелированным, когда в нем (во фразах WHERE, HAVING или START WITH) указан столбец таблицы внешнего запроса. Такое обращение к столбцам родительского запроса называется внешней ссылкой. Если быть точнее, внешняя ссылка — это имя столбца одной из таблиц фразы FROM внешнего запроса, но не входящего ни в одну из таблиц фразы FROM подзапроса.
Запросы с коррелированными подзапросами обрабатываются следующим образом.
Выбирается строка внешнего запроса.
Вычисляется подзапрос. При этом в качестве значения внешней ссылки используется значение соответствующего столбца выбранной строки внешнего запроса.
Результат подзапроса возвращается во внешний запрос, где проверяется на соответствие условию. Если сравнение истинно, текущая строка внешнего запроса включается в результирующую таблицу.
Выбирается следующая строка внешнего запроса и указанные действия повторяются до перебора всех его строк.
Таким образом, коррелированный подзапрос вычисляется заново для каждой строки внешнего запроса. Этим он отличается от простого подзапроса, который вычисляется только один раз. Поэтому коррелированный подзапрос называют еще соотнесенным или связанным подзапросом. Рассмотрим несколько примеров.
Запрос. Вывести названия факультетов, кафедры которых расположены в корпусе 3.
SELECT Name FROM FACULTY
WHERE 3 IN (SELECT Building FROM DEPARTMENT
WHERE FACULTY.FacPK = DEPARTMENT.FacFK);
NAME
информатика
кибернетика
Здесь во фразе WHERE подзапроса мы ссылаемся на столбец FacPK таблицы FACULTY внешнего запроса (внешняя ссылка), что делает подзапрос коррелированным. Вычисляется этот запрос следующим образом.
Во внешнем запросе выбирается строка таблицы FACULTY.
Во вложенном запросе формируется множество номеров корпусов, в которых располагаются кафедры факультета, указанного в выбранной строке внешнего запроса.
Во внешнем запросе проверяется, содержит ли результат подзапроса корпус с номером 3. Если так, данные текущей строки внешнего запроса включаются в результирующую таблицу.
Цикл повторяется для каждой строки внешнего запроса.
Обратите внимание, что в этом примере в качестве левого операнда оператора IN мы впервые использовали константу.
В коррелированных подзапросах разрешается использовать все те возможности, которые мы описали ранее для простых подзапросов. Коррелированные подзапросы, как и простые, могут вкладываться во внешние с помощью операторов сравнения.
Запрос. Вывести названия и номера корпусов факультетов, фонд финансирования которых меньше суммарного фонда финансирования их кафедр.
SELECT Name AS "Факультет”, Building AS "Корпус"
FROM FACULTY
WHERE Fund < (SELECT SUM(Fund) FROM DEPARTMENT
WHERE DEPARTMENT.FacFK = FACULTY.FacPK);
Факультет Корпус
информатика б кибернетика 5
Запрос. Вывести фамилии преподавателей, имеющих две пары на второй неделе.
SELECT Name FROM TEACHER t WHERE 2 = (SELECT COUNT(*)
FROM LECTURE 1
WHERE l.TchFK = t.TchPK AND Week = 2):
NAME
Дараганов
Вернемся к использованию подзапросов в обоих операндах операторов сравнения.
Запрос. Вывести фамилии преподавателей, имеющих столько же пар на второй неделе, сколько их имеет Хоренко на первой неделе.
SELECT Name
FROM TEACHER t
WHERE (SELECT COUNT(*)
FROM TEACHER t2, LECTURE 12
WHERE t2.TchPK = 12.TchFK AND
UPPER(t2.Name) = -'ХОРЕНКО')
(SELECT COUNT(*)
FROM LECTURE 1
WHERE 1.TchFK » t.TchPK AND Week = 2):
NAME
Дараганов
От предыдущего этот запрос отличается тем, что вместо константы 2 используется подзапрос, возвращающий количество занятий у Хоренко на первой неделе. Этот подзапрос является простым, то есть независимым от внешнего. Но SQL допускает, чтобы оба подзапроса были коррелированными, как в следующем примере.
Запрос. Вывести фамилии преподавателей, имеющих на первой неделе больше пар, чем на второй.
SELECT Name
FROM TEACHER t
WHERE (SELECT COUNK*)
FROM LECTURE 1
WHERE 1.TchFK = t.TchPK AND Week = 1)
(SELECT COUNK*) FROM LECTURE 1 WHERE 1.TchFK = t.TchPK AND Week = 2);
NAME
Завратинский
Козлутин
Коррелированный подзапрос может базироваться на той же таблице, что и внешний запрос.
Запрос. Вывести номера корпусов, в которых располагается только одна кафедра.
SELECT Building FROM DEPARTMENT dl
WHERE Building NOT IN (SELECT Building FROM DEPARTMENT d2
WHERE dl.DepPK <> d2.DepPK);
BUILD
5
Рассмотрим, как мы получили результат. Для каждой кафедры, отбираемой во внешнем запросе, в подзапросе вычисляется множество корпусов, в которых располагаются остальные кафедры. Если корпус, в котором расположена отобранная кафедра, не содержится во множестве корпусов, возвращенном подзапросом, он включается в выходную таблицу.
Этот же запрос можно выразить по-другому:
SELECT Building
FROM DEPARTMENT dl
WHERE 1 = (SELECT COUNT(Building)
FROM DEPARTMENT d2
WHERE dl.Bull di ng = d2.Building):
Здесь в подзапросе для таблицы DEPARTMENT подсчитывается количество строк с тем номером корпуса, который определен текущей строкой внешнего запроса. Если это количество равно 1, значит, в этом корпусе находится только один факультет.
В отличие от простых подзапросов, если коррелированный подзапрос возвратит пустое множество строк, результат запроса не обязательно будет пустым. Дело именно в том, что подзапрос вычисляется для каждой строки внешнего запроса. Если он вернет пустое множество для одних строк внешнего запроса, то для других может вернуть и непустое.
Многоуровневая вложенность запросов
Вложенный запрос и сам может содержать вложенный запрос, обеспечивая тем самым многоуровневую вложенность. Глубина вложенности стандартом SQL не ограничивается, но может быть ограничена в конкретной СУБД. В многоуровневых запросах внешняя ссылка коррелированного подзапроса не обязательно должна ссылаться на уровень выше — ссылаться можно на любой верхний уровень.
Запрос. Вывести фамилии доцентов факультета информатики.
SELECT Name FROM TEACHER
WHERE LOWER(Post) = 'доцент' AND
DepFK IN (SELECT DepPK FROM DEPARTMENT
WHERE FacFK = (SELECT FacPK FROM FACULTY
WHERE LOWER(NAME) = 'информатика'));
NAME
Рамишевский
Завратинский
Лекарь
Подзапрос подзапроса возвращает первичный ключ факультета информатики. Подзапрос выше формирует список кафедр факультета информатики (в нем используется предикат =, так как факультетов с одинаковыми названиями не должно быть). Внешний запрос выводит фамилии доцентов, работающих на кафедрах, возвращенных подзапросом (здесь используется предикат IN, так как на факультете может быть несколько кафедр).
Запрос. Вывести фамилии преподавателей, которые имеют одно занятие на четной неделе по той же дисциплине, которая читается Вибровским в понедельник на первой паре нечетной недели.
SELECT Name FROM TEACHER t
WHERE 1 =
(SELECT COUNH*) FROM LECTURE 1
WHERE 1.TchFK = t.TchPK AND Week = 2 AND
l.SbjFK =
(SELECT 12.SbjFK FROM LECTURE 12
WHERE Week = 1 AND Day = *пнд* AND Lesson = 1 AND
TchFK =
(SELECT TchPK FROM TEACHER t2
WHERE t2.Name - 'Вибровский')))
AND t.Name <> 'Вибровский';
NAME
Хоренко
Два нижних вложенных запроса дают первичный ключ дисциплины, по которой проводит занятие преподаватель Вибровский в понедельник на первой паре нечетной недели (предполагается, что имеется только один Вибровский). Подзапрос верхнего уровня подсчитывает количество занятий преподавателя, отобранного внешним запросом, на второй неделе по дисциплине, читаемой Вибровским в указанное время. Снова предполагается, что такая дисциплина может быть
только одна. Наконец, во внешнем запросе проверяется, равно ли 1 подсчитанное в подзапросе верхнего уровня количество занятий.
Замена вложенного запроса соединением
Некоторые вложенные запросы могут быть представлены как соединение двух или более таблиц. Представим некоторые общие случаи таких эквивалентных замен в табл. 7.1, после которой последовательно приведем примеры для них. Далее используются следующие обозначения:
О R, S — таблицы;
О А, В, С — столбцы таблицы R;
О D, Е, F - столбцы таблицы S;
О const - константа;
0 9— один из предикатов =, <>, <=, >=, <, >.
Во второй колонке таблицы дополнительно указан предикат, используемый во фразе WHERE внешнего запроса (предикат NOT IN ни для простого подзапроса, ни для коррелированного в общем случае через соединение не выражается).
Таблица 7.1. Эквивалентность подзапросов и соединений
Вид подзапроса
Предикат
Подзапрос
Соединение
Простой
е
SELECT R.A
SELECT R.A
FROM R
FROM R. S
WHERE R.B 9
WHERE R.B 8 S.D AND
(SELECT S.D
S.E = const;
FROM S
WHERE S.E = const);
IN
SELECT R.A
SELECT DISTINCT R.A
FROM R
FROM R, S
WHERE R.B IN
WHERE R.B = S.D AND
(SELECT S.D
S.E = const);
FROM S
WHERE S.E = const);
Коррелированный
е
SELECT R.A
SELECT R.A
FROM R
FROM R. S
WHERE R.B 9
WHERE R.B 9 S.D AND
(SELECT S.D
R.C = S.F AND
FROM S
S.E = const);
WHERE R.C = S.F AND
S.E = const):
IN
SELECT R.A
SELECT DISTINCT R.A
FROM R
FROM R, S
WHERE R.B IN
WHERE R.B = S.D AND
(SELECT S.D
R.C = S.F AND
FROM S
S.E = const;
WHERE R.C = S.F AND
S.E = const);
ПРИМЕЧАНИЕПРИМЕЧАНИЕSELECT d.NameFROM DEPARTMENT dWHERE d.Bull ding <>(SELECT f.Building FROM FACULTY f WHERE d.FacFK = f.FacPK AND f.Name = 'информатика');SELECT d.NameFROM DEPARTMENT dWHERE d.Bull ding <>(SELECT f.Building FROM FACULTY f WHERE d.FacFK = f.FacPK AND f.Name = 'информатика');SELECT d.NameFROM DEPARTMENT d, FACULTY f WHERE d.Building <> f.Building AND d.FacFK = f.FacPK AND f.Name = 'информатика*:SELECT d.NameFROM DEPARTMENT d, FACULTY f WHERE d.Building <> f.Building AND d.FacFK = f.FacPK AND f.Name = 'информатика*:
ПРИМЕЧАНИЕ
ПРИМЕЧАНИЕ
SELECT d.Name
FROM DEPARTMENT d
WHERE d.Bull ding <>
(SELECT f.Building FROM FACULTY f WHERE d.FacFK = f.FacPK AND f.Name = 'информатика');
SELECT d.Name
FROM DEPARTMENT d
WHERE d.Bull ding <>
(SELECT f.Building FROM FACULTY f WHERE d.FacFK = f.FacPK AND f.Name = 'информатика');
SELECT d.Name
FROM DEPARTMENT d, FACULTY f WHERE d.Building <> f.Building AND d.FacFK = f.FacPK AND f.Name = 'информатика*:
SELECT d.Name
FROM DEPARTMENT d, FACULTY f WHERE d.Building <> f.Building AND d.FacFK = f.FacPK AND f.Name = 'информатика*:
В коррелированных подзапросах (и эквивалентных соединениях) вместо столбца R. В может использоваться константа.
Запрос. Вывести названия кафедр, фонд финансирования которых не меньше, чем фонд финансирования факультета кибернетики.
SELECT d.NameSELECT d.Name
FROM
WHERE
DEPARTMENT dFROM DEPARTMENT d. FACULTY f
d.Fund >=WHERE d.Fund >= f.Fund AND
(SELECT f.Fundf.Name - 'кибернетика';
FROM FACULTY f
WHERE f.Name = 'кибернетика'):
Запрос. Вывести фамилии преподавателей, имеющих занятия в понедельник.
SELECT t.Name
SELECT DISTINCT t.Name
FROM TEACHER t
FROM TEACHER t, LECTURE 1
WHERE t.TchPK IN
WHERE t.TchPK = 1.TchFK AND
(SELECT 1.TchFK
l.Day = 'пнд*;
FROM LECTURE 1
WHERE l.Day = 'пнд');
Запрос. Для факультета информатики вывести названия кафедр, расположенных в других корпусах.
Запрос. Вывести названия факультетов, фонд финансирования которых совпадает с фондом финансирования хотя бы одной из его кафедр, имеющей фонд финансирования более 10 000.
SELECT DISTINCT f.NameFROM FACULTY f, DEPARTMENT dWHERE f.Fund = d.Fund AND d.FacFK = f.FacPK AND d.Fund •> 10000:SELECT DISTINCT f.NameFROM FACULTY f, DEPARTMENT dWHERE f.Fund = d.Fund AND d.FacFK = f.FacPK AND d.Fund •> 10000:SELECT f.Name
SELECT DISTINCT f.Name
FROM FACULTY f, DEPARTMENT d
WHERE f.Fund = d.Fund AND d.FacFK = f.FacPK AND d.Fund •> 10000:
SELECT DISTINCT f.Name
FROM FACULTY f, DEPARTMENT d
WHERE f.Fund = d.Fund AND d.FacFK = f.FacPK AND d.Fund •> 10000:
FROM FACULTY f
WHERE f.Fund IN
(SELECT d.Fund
FROM DEPARTMENT d
-WHERE d.FacFK = f.FacPK AND d.Fund > 10000):
Приведенные правила эквивалентности можно применить и в случае многоуровневых запросов'
Запрос. Сколько студентов на факультете информатики?
SELECT SUM(g.Quantity)
SELECT SUM(g.Quantity)
FROM SGROUP g
FROM SGROUP g, DEPARTMENT d. FACULTY f
WHERE g.DepFK IN
WHERE g.DepFK = d.DepPK AND
(SELECT d.DepPK
d.FacFK = F.FacPK AND
FROM DEPARTMENT d
LOWER(f.Name) = 'информатика';
WHERE d.FacFK IN
(SELECT F.FacPK
FROM FACULTY f
WHERE LOWER(f.Name) = 'информатика*));
Отметим, что когда список фразы SELECT подзапросов содержит агрегатные функции, общий алгоритм приведения подзапросов к соединению не известен. Тем не менее, в некоторых случаях это можно сделать.
Запрос. Вывести фамилии преподавателей, которые имеют два занятия во вторую неделю.
SELECT NameFROM TEACHER. LECTUREWHERE TEACHER.TchPK = LECTURE.TchFK ANDWeek = 2GROUP BY TEACHER.TchPK. TEACHER.NameHAVING COUNT(*) = 2;SELECT NameFROM TEACHER. LECTUREWHERE TEACHER.TchPK = LECTURE.TchFK ANDWeek = 2GROUP BY TEACHER.TchPK. TEACHER.NameHAVING COUNT(*) = 2;SELECT Name
SELECT Name
FROM TEACHER. LECTURE
WHERE TEACHER.TchPK = LECTURE.TchFK AND
Week = 2
GROUP BY TEACHER.TchPK. TEACHER.Name
HAVING COUNT(*) = 2;
SELECT Name
FROM TEACHER. LECTURE
WHERE TEACHER.TchPK = LECTURE.TchFK AND
Week = 2
GROUP BY TEACHER.TchPK. TEACHER.Name
HAVING COUNT(*) = 2;
FROM TEACHER
WHERE 2 =
(SELECT COUNTS)
FROM LECTURE
WHERE LECTURE.TchFK = TEACHER.TchPK AND Week = 2);
Однако учтите, что даже эквивалентные формы имеют разные возможности. Например, соединение позволяет включать в результирующую таблицу столбцы из любой соединяемой таблицы, в случае же подзапроса выводить можно только столбцы таблицы внешнего запроса.
Простые и коррелированные подзапросы во фразе SELECT
Мы уже отмечали ранее возможность использования подзапросов во фразе SELECT. Такие подзапросы могут быть простыми и коррелированными.
При использовании простого подзапроса (который вычисляется однократно) возвращенный им результат вставляется во все строки, формируемые внешним запросом. Кроме того, помешенный во фразу SELECT подзапрос должен возвращать только одно значение. Например, если вы попытаетесь вычислить максимальное и минимальное значения в одном подзапросе, получите сообщение об ошибке:
SELECT Name. Fund.
(SELECT MAX(Fund) AS "MAX(Fund)". MIN(Fund) AS "MIN(Fund)" FROM DEPARTMENT)
FROM FACULTY;
(SELECT MAX(Fund) AS "MAX(Fund)".
*
ошибка в строке 2:
ORA-00913: слишком много значений
В этом случае подзапрос нужно указать столько раз, сколько значений он должен вернуть.
Запрос. Для каждого факультета вывести его название, фонд финансирования, а также максимальный и минимальный фонды финансирования кафедр вуза.
SELECT Name. Fund,
(SELECT MAX(Fund) FROM DEPARTMENT) AS "MAX(Fund)".
(SELECT MIN(Fund) FROM DEPARTMENT) AS "MIN(Fund)"
FROM FACULTY:
NAME FUND MAX(Fund) MIN(Fund)
информатика 250002700010000
кибернетика 270002700010000
математика 230002700010000
Приведенный пример является искусственным. Прежде всего потому, что нет непосредственной связи между информацией о факультете и агрегированными данными о кафедрах. При использовании простых подзапросов во фразе SELECT это случается почти всегда. Одним из немногих исключений является ситуация, когда выводятся только агрегированные данные.
Запрос. Вывести средние значения фондов финансирования факультетов и кафедр, а также их процентное соотношение.
SELECT (SELECT AVG(Fund) FROM FACULTY) AS "AVG-FAC-Fund", (SELECT AVG(Fund) FROM DEPARTMENT) AS "AVG-DEP-Fund", (SELECT AVG(Fund) FROM FACULTY) * 100 / (SELECT AVG(Fund) FROM DEPARTMENT) AS "Percent"
FROM DUAL:
AVG-FAC-Fund AVG-DEP-Fund Percent.
2500016516.6667 151.36226
f ^ПРИМЕЧАНИЕ Обратите внимание, что скалярные подзапросы могут использовать- —лся в выражениях соответствующего типа.
Область использования коррелированных подзапросов во фразе SELECT намного шире, так как в этом случае возвращаемое подзапросом значение вычисляется для текущей строки внешнего запроса.
Запрос. Для каждого факультета вывести его название, фонд финансирования и процентное соотношение величины этого фонда к суммарному фонду финансирования всех кафедр факультета.
SELECT f.Name AS "Факультет", f.Fund AS "Фонд".
f.Fund * 100 / (SELECT SUM(Fund) FROM DEPARTMENT d WHERE d.FacFK = f.FacPK) AS "Процент"
FROM FACULTY f;
Факультет Фонд Процент
информатика 25000 52,0833333
кибернетика 27000 52,8375734 математика 23000
Здесь в подзапросе вычисляется фонд финансирования всех кафедр факультета, отобранного внешним запросом. Затем возвращенное подзапросом значение используется в выражении для подсчета процентного соотношения.
Подзапросы во фразе SELECT могут быть и многоуровневыми, как в следующем примере.
Запрос. Вывести названия факультетов, количество их кафедр, преподавателей и студентов.
SELECT f.Name AS "Факультет",
(SELECT COUNT(*) FROM DEPARTMENT d
WHERE d.FacFK - f.FacPK) AS "К-во кафедр",
(SELECT COUNT(*) FROM TEACHER t
WHERE t.DepFK IN
(SELECT DepPK FROM DEPARTMENT d
WHERE d.FacFK - f.FacPK)) AS "К-во open.",
(SELECT COALESCE(SUM(Quant1ty), 0) FROM SGROUP s
WHERE s.DepFK IN
(SELECT DepPK FROM DEPARTMENT d
WHERE d.FacFK - f.FacPK)) AS "К-во студ."
FROM FACULTY f;
Факультет К-во кафедр К-во преп. К-во студ.
информатика312153
кибернетика300
математикаООО
Простые и коррелированные подзапросы во фразе HAVING
Во фразе HAVING можно использовать как простые, так и коррелированные подзапросы. Для внешних ссылок коррелированного подзапроса должны использоваться только те элементы внешнего запроса, которые могут использоваться во фразе HAVING непосредственно. Вспомним — во фразе HAVING можно использовать только агрегатные функции, аргументами которых являются имена столбцов таблиц запроса, или имена столбцов, используемых во фразе GROUP BY. Причиной этого является то, что предикат фразы HAVING оценивается для групп строк таблицы, а не для отдельных строк. Следовательно, коррелированный подзапрос будет выполняться для каждой группы, сформированной во внешнем запросе.
Запрос. Вывести названия факультетов, суммарный фонд финансирования кафедр которых на 20 000 превышает максимальный имеющийся фонд финансирования кафедры факультета.
SELECT fl.Name
FROM FACULTY fl. DEPARTMENT dl
WHERE fl.FacPK = dl.FacFK'
GROUP BY fl.Name
HAVING SUM(dl.Fund) > (SELECT 20000 + MAX(d2.Fund)
FROM FACULTY f2. DEPARTMENT d2
WHERE f2.FacPK = d2.FacFK AND
fl.Name = f2.Name);
NAME
информатика кибеонАтика
Запрос. Вывести фамилии преподавателей кафедры программирования, читающих меньше лекций, чем все преподаватели, кафедра которых не указана.
SELECT t.Name FROM TEACHER t, LECTURE 1
WHERE t.TchPK = 1.TchFK AND
t.DepFK = (SELECT d.DepPK FROM DEPARTMENT d
WHERE LOWER(d.Name) = 'программирование')
GROUP BY t.TchPK. t.Name
HAVING COUNT(*) < (SELECT COUNT(*) FROM TEACHER t2, LECTURE 12
WHERE t2.DepFK IS NULL AND
t2.TchPK = 12.TchFK);
NAME
Завратинский
Козлутин
Простые подзапросы во фразе FROM
В списке фразы FROM могут содержаться не только имена таблиц, но и возвращающие таблицы подзапросы (только простые). Для обращения к таким таблицам во внешнем запросе им нужно приписать синоним, указав его после подзапроса, а для имен столбцов использовать имена или синонимы столбцов во фразе SELECT подзапроса (такое использование подзапросов эквивалентно представлениям, о которых пойдет речь в уроке 14).
Подавляющее большинство запросов, во фразе FROM которых указаны подзапросы, могут быть выражены и без вложения. Однако существует класс запросов, которые либо нельзя представить иным способом, либо они будут выражены намного сложнее. Это запросы, которые предполагают предварительное вычисление независимых запросов и совместное использование их результатов, как в следующих примерах.
Запрос. Вывести средний фонд финансирования факультетов и среднюю ставку преподавателей.
SELECT Fac.AvgFund AS "Сред, фонд факультетов",
Tch.AvgSal AS "Сред, ставка преподавателей"
FROM (SELECT AVG(Fund) AS AvgFund FROM FACULTY) Fac, (SELECT AVG(Salary) AS AvgSal FROM TEACHER) Tch;
Сред, фонд факультетов Сред, ставка преподавателей
25000741,333333
Запрос. Вывести названия кафедр, процент их преподавателей по отношению к общему числу преподавателей вуза и процент суммарной зарплаты преподавателей кафедры по отношению к суммарной зарплате преподавателей вуза.
SELECT Tl.Name AS "Отдел",
Tl.numTchr / Т2.total Count * 100 AS "Процент препод.",
Tl.Sal Sum / T2.total Sal * 100 AS "Процент зарплаты"
FROM (SELECT d.Name, COUNT(*) AS numTchr, SUM(t.Salary + t.Rise) AS Sal Sum FROM TEACHER t. DEPARTMENT d
WHERE t.DepFK = d.DepPK
GROUP BY d.Name) Tl,
(SELECT COUNT(*)AS total Count,
SUM(Salary + Rise) AS totalSa!
FROM TEACHER) T2;
ОтделПроцент препод. Процент зарплаты
программирование8077,9127903
Здесь первый подзапрос во фразе FROM возвращает таблицу, в которой для каждой из кафедр вычислено количество и суммарная зарплата ее преподавателей. Этой таблице присваивается синоним Т1. Второй подзапрос во фразе FROM возвращает таблицу из одной строки, в которой указаны общее количество и суммарная зарплата преподавателей вуза. Этой таблице присваивается синоним Т2. Наконец, во фразе SELECT внешнего запроса подсчитываются процентные соотношения.
Обратите внимание, что во внешнем запросе для соединения таблиц Т1 и Т2 не указано никакого условия — перемножение количества строк, характерное для декартового произведения, в данном случае не приводит к росту их числа, так как вторая таблица содержит только одну строку. Приведем также пример, когда таблицы, получаемые из подзапросов фразы FROM, необходимо соединить условием.
Запрос. Вывести такие пары кафедр, у первой из которых соотношение фонда финансирования и количества студентов выше, чем у второй.
SELECT dl.Name, dl.SFund, dl.SStd, dl.FPerS, d2.Name, d2.SFund, d2.SStd, d2.FPerS
FROM (SELECT dep.Name, dep.FundASSFund,
SUM(grp.Quantity)ASSStd,
dep.Fund / SUM(grp.Quantity) AS FPerS
FROM DEPARTMENT dep, SGROUP grp
WHERE dep.DepPK = Grp.DepFK
GROUP BY dep.Name, dep.Fund) dl,
(SELECT dep.Name, dep.FundASSFund,
SUM(grp.Quantity)ASSStd,
dep.Fund / SUM(grp.Quantity) AS FPerS
FROM DEPARTMENT dep, SGROUP grp
WHERE dep.DepPK = Grp.DepFK
GROUP BY dep.Name, dep.Fund) d2
WHERE dl.FPerS > d2.FPerS;
NAME SFUND SSTD FPERS NAMESFUND SSTD FPERS
базы данных 26000 60 433.33 интернет 10000 35 285.71 базы данных 26000 60 433.33 программирование 12000 58 206.90 интернет 10000 35 285.71 программирование 12000 58 206.90
Здесь оба подзапроса фразы FROM являются идентичными и формируют промежуточные таблицы, необходимые для получения результирующей таблицы. Во фразе WHERE внешнего запроса промежуточные таблицы соединяются поставленным Условием.
Самостоятельная работа
Вывести номера групп, имеющих больший рейтинг, чем группа 307.
Вывести фамилии преподавателей, занимающих ту же должность, что и Хо- ренко.
Вывести названия предметов, читающихся по понедельникам и вторникам нечетной недели.
Вывести номера групп, кураторами которых являются доценты.
Вывести номера групп, рейтинг которых меньше минимального рейтинга групп пятого курса.
Вывести названия факультетов, суммарный фонд финансирования кафедр которых больше суммарного фонда финансирования кафедр факультета информатики.
Вывести названия кафедр, преподаватели которых ведут занятия по дисциплине «базы данных».
Вывести название предмета, по которому читается меньше всего пар.
Для кафедры программирования вывести количество студентов и читаемых на ней предметов.
Для каждого преподавателя кафедры программирования вывести процент его зарплаты по отношению к суммарной зарплате всех преподавателей кафедры и процент количества проводимых им занятий по отношению к общему количеству занятий, проводимых преподавателями этой кафедры.
Подведение итогов
Усвоив материал этого урока, вы научились:
0 создавать простые вложенные запросы во фразе WHERE с использованием операторов сравнения и предиката IN;
0 использовать табличные вложенные запросы;
0 создавать коррелированные подзапросы во фразе WHERE;
0 строить запросы с многоуровневой вложенностью запросов;
0 заменять вложенный запрос на соединение;
0 использовать простые и коррелированные подзапросы во фразах SELECT и HAVING;
0 использовать простые вложенные запросы во фразе FROM.
Дополнительные операторы и выражения
SQL обладает огромными возможностями. В книге столь скромных размеров не представляется возможным рассказать обо всех них. Однако мы не можем обойти использование операторов EXISTS, ANY, SOME и ALL, включенных еще в первую версию стандарта. В этом уроке мы рассмотрим также выражения и функции выбора вариантов, включенные в язык позже и придавшие SQL гибкость, характерную для языков программирования. Особенно это относится к выражению CASE. Наконец, в последнем разделе показано, как средствами SQL можно выразить теоретико-множественные предикаты, не включенные в язык в явной форме.
Использование оператора EXISTS
Унарный оператор сравнения EXISTS проверяет, является ли пустым множество, специфицированное в его аргументе. Так как в SQL единственным способом спецификации множества является предложение SELECT, операндом оператора EXISTS должен быть подзапрос:
[NOT] EXISTS подзапрос
Если множество непустое, предикат EXISTS принимает истинное значение, а если пустое — ложное. Вариант NOT EXISTS изменяет логику EXISTS — если подзапрос не возвращает ни одной строки, NOT EXISTS дает TRUE, а если хотя бы одну — то FALSE. Оператор EXISTS может использоваться во фразах WERE и HAVING.
Оператор EXISTS с простыми подзапросами
Операндом оператора EXISTS может быть и простой, и коррелированный подзапрос. Сначала рассмотрим примеры использования простого подзапроса. Обратите внимание, что предикат EXISTS не использует возвращаемые подзапросом значения, а только проверяет, пустой результат или нет. Поэтому во фразе SELECT подзапроса можно указывать возврат всех столбцов символом *.
Запрос. Если имеется хотя бы одна группа с рейтингом более 50, вывести номера и рейтинги всех групп.
SELECT Num, Rating FROM SGROUP
WHERE EXISTS (SELECT * FROM SGROUP
WHERE Rating >50);
NUM RATING
505
67
504
55
307
48
408
56
201
43
Оператор EXISTS возвращает истинностное значение, поэтому его можно комбинировать с логическими связками (AND, OR, NOT).
Запрос. Вывести номера и количество мест в аудиториях корпуса 6 с вместимостью 25 и более мест, если в этом корпусе имеется хотя бы одна аудитория с вместимостью более 50 мест.
SELECT Num, Seats FROM ROOM
WHERE Building = *6' AND Seats >= 25 AND
EXISTS (SELECT * FROM ROOM
WHERE Building = *6* AND Seats >50);
NUM SEATS
20180
10425
11040
Оператор EXISTS с коррелированными подзапросами
Оператор EXISTS довольно редко используется с простыми подзапросами, так как в этом случае они по своему содержанию в основном являются искусственными. Чаще всего с оператором EXISTS используются коррелированные запросы. Рассмотрим несколько однотипных примеров возрастающей сложности.
Запрос. Вывести названия и фонды финансирования факультетов, на которых имеется хотя бы одна кафедра.
SELECT Name, Fund FROM FACULTY
WHERE EXISTS (SELECT * FROM DEPARTMENT
WHERE DEPARTMENT.FacFK = FACULTY.FacPK);
NAME FUND
информатика 25000
кибернетика 27000
Здесь с помощью условия подзапроса DEPARTMENT.FacFK = FACULTY.FacPK производится связывание подзапроса с внешним запросом.
Запрос. Вывести названия факультетов, на которых работает хотя бы один преподаватель.
SELECT Name FROM FACULTY'
WHERE EXISTS (SELECT * FROM TEACHER
WHERE DepFK IN (SELECT DepPK FROM DEPARTMENT WHERE FacFK = FacPK));
NAME
информатика
Запрос можно сформулировать и следующим образом: «Вывести название факультета, если существуют преподаватели, работающие на его кафедрах». В примере запрос третьего уровня формирует список кафедр факультета, определяемого текущей строкой запроса верхнего уровня, а запрос второго уровня выбирает преподавателей всех отобранных кафедр. Обратите внимание на последнюю строку запроса - фразу WHERE FacFK = FacPK. Здесь FacFK ссылается на столбец таблицы кафедр, a FacPK — на столбец таблицы факультетов.
Запрос. Вывести названия факультетов с фондом финансирования более 20 000, на которых работает хотя бы один профессор и которые имеют больше двух кафедр.
SELECT Name FROM FACULTY
WHERE Fund > 20000 AND-- 1-е выражение
<= (SELECT COUNT(*) FROM DEPARTMENT-- 2-е выражение
WHERE FacFK - FacPK) AND
EXISTS (SELECT * FROM TEACHER-- 3-е выражение
WHERE LOWER(Post) = 'профессор* AND
DepFK IN (SELECT DepPK FROM DEPARTMENT
WHERE FacFK = FacPK));
NAME
информатика
Запрос содержит три выражения во фразе WHERE, соединенные логической связкой AND. Первое выражение отбирает записи по значению фонда финансирования факультета. Второе — факультеты, имеющие больше двух кафедр. Третье выражение проверяет существование на факультете профессоров, отбираемых в подзапросе.
Комбинирование оператора EXISTS с соединением
К предикату EXISTS применимы все те варианты, которые мы рассмотрели для операторов сравнения, в частности использование в соединении нескольких таблиц, причем как во внешнем запросе, так и в подзапросе.
Запрос. Вывести фамилии ассистентов кафедры программирования, которые имеют хотя бы одно лабораторное занятие по предмету «базы данных».
SELECT t.Name
FROM TEACHER t, DEPARTMENT d
WHERE- t.DepFK = d.DepPK AND
LOWER(d.Name) = 'программирование* AND
LOWER(t.Post) = 'ассистент* AND
EXISTS (SELECT *
FROM LECTURE 1, SUBJECT s
WHERE l.SbjFK - S.SbjPK AND
LOWER(s.Name) - 'базы данных' AND l.TchFK - t.TchPK AND Type - 'лаб');
NAME
Мартынов
Соединение таблиц TEACHER и DEPARTMENT во внешнем запросе необходимо в связи с тем, что требуется вывести фамилии преподавателей, а условие задано для названия кафедры. Соединение таблиц LECTURE и SUBJECT во внутреннем запросе обусловлено тем, что необходимо вывести список лекций с дополнительным условием на название дисциплины.
Запрос. Вывести фамилии доцентов факультета информатики, курирующих группы пятого курса кафедры программирования.
SELECT t.Name
FROM TEACHER t. DEPARTMENT d. FACULTY f
WHERE t.DepFK = d.DepPK AND d.FacFK = f.FacPK AND
LOWER(f.Name) = 'информатика* AND
LOWER(t.Post) = 'доцент* AND
EXISTS (SELECT *
FROM SGROUP s, DEPARTMENT d2
WHERE s.DepFK = d2.DepPK AND
LOWER(d2.Name) = 'программирование* AND
s.CurFK = t.TchPK AND Year - 5);
NAME
Завратинский
Лекарь
Использование оператора NOT EXISTS
Как мы уже отметили, оператор NOT EXISTS является противоположным EXISTS. Рассмотрим примеры.
Запрос. Вывести фамилии преподавателей, не имеющих занятий в расписании.
SELECT Name FROM TEACHER
WHERE NOT EXISTS (SELECT * FROM LECTURE
WHERE LECTURE.TchFK = TEACHER.TchPK);
NAME
Сидоров
Ахромеев
Наумов
Запрос. Вывести названия факультетов без преподавателей.
SELECT f.Name FROM FACULTY f •
WHERE NOT EXISTS (SELECT * FROM TEACHER t
WHERE t.DepFK IN (SELECT d.DepPK FROM DEPARTMENT d
WHERE d.FacFK=f.FacPK));
name
кибернетика
математика
В подзапросе нижнего уровня формируется множество кафедр факультета, указанного в текущей строке запроса верхнего уровня. Подзапрос среднего уровня формирует множество преподавателей, работающих на найденных кафедрах.
Оператор EXISTS и агрегатные функции
Стандарт SQL допускает, чтобы подзапрос, являющийся операндом оператора EXISTS, содержал во фразе SELECT агрегатную функцию. Однако будьте внимательны - при этом в некоторых случаях вы можете получить не то, что ожидали. Дело в том, что агрегатная функция может вернуть значение NULL, после чего оператор EXISTS вернет значение UNKNOWN. Это значит, что текущая строка внешнего запроса не будет включена в результирующую таблицу. Приведем пример без использования агрегатной функции и аналогичный — с нею.
Запрос. Вывести фамилии преподавателей, которые проводят занятия в аудитории 201 корпуса 6.
SELECT t.Name FROM TEACHER t
WHERE LOWER(t.Post) = 'доцент* AND
EXISTS (SELECT * FROM ROOM r
WHERE r.Num = 201 AND r.Building = *6* AND r.RomPK IN (SELECT l.RomFK FROM LECTURE 1 WHERE l.TchFK = t.TchPK));
NAME
Рамишевский
Лекарь
SELECT t.Name FROM TEACHER t
WHERE LOWER(t.Post) = 'доцент* AND
EXISTS (SELECT COUNT(*) FROM ROOM r
WHERE r.Num = 201 AND r.Building = *6* AND
r.RomPK IN (SELECT l.RomFK FROM LECTURE 1 . WHERE l.TchFK = t.TchPK));
NAME
Рамишевский
Завратинский
Лекарь
Наумов
Если в обоих случаях подзапрос будет формировать таблицу с непустым множеством строк, то оба запроса эквивалентны. Однако если множество окажется пустым, результаты будут разные. В первом случае предикат EXISTS будет иметь значение FALSE и строка, как и ожидается, будет включена в результат. Во втором случае функция COUNT(*) вернет 0, предикат EXISTS приобретет значение TRUE — и текущая строка будет включена в результат! Преподаватели Завратинский и Наумов нс ведут занятия в указанной аудитории, однако перечислены в результате второго запроса. Подобное может произойти и при использовании агрегатных функций с оператором NOT EXISTS.
Запрос. Вывести фамилии преподавателей, не имеющих занятий в расписании.
SELECT Name FROM TEACHER
WHERE NOT EXISTS (SELECT * FROM LECTURE
WHERE LECTURE.TchFK = TEACHER.TchPK);
NAME
Сидоров
Ахромеев
Наумов
SELECT Name FROM TEACHER
WHERE NOT EXISTS (SELECT MAX(LECTURE.TchFK) FROM LECTURE
WHERE LECTURE.TchFK = TEACHER.TchPK);
строки не выбраны
Если преподаватель ведет какие-то лекции, то в обоих вариантах он не будет включен в результат. Однако если он не ведет ни одной лекции, то в первом случае он, как и следовало ожидать, будет включен в результат, а во втором случае — нет. Во втором случае в столбце TchFK таблицы LECTURE будет отсутствовать значение столбца TchPK из таблицы TEACHER для текущего преподавателя. Поэтому значением аргумента функции МАХ является NULL и сама функция возвращает значение NULL. Значение предиката NOT EXISTS от NULL равно UNKNOWN — следовательно, текущая строка внешнего запроса не включается в результат.
V ) ВНИМАНИЕ Использование агрегатных функций во фразе SELECT подзапроса, являющегося операндом оператора EXISTS (или NOT EXISTS), может привести к неверным результатам.
Замена оператора EXISTS функцией COUNT или соединением таблиц
Оператор EXISTS проверяет, является множество пустым или нет, а агрегатная функция COUNT подсчитывает количество элементов во множестве. Когда количество элементов во множестве больше 0, оно непустое, когда равно 0 — пустое. Таким образом, оператор EXISTS (и NOT EXISTS) всегда может быть заменен на функцию COUNT, но не наоборот. Приведем примеры таких замен.
Запрос. Вывести названия кафедр, имеющих хотя бы одну группу.
SELECT Name FROM DEPARTMENT
WHERE EXISTS (SELECT * FROM SGROUP
WHERE SGROUP.DepFK = DEPARTMENT.DepPK):
SELECT Name FROM DEPARTMENT
WHERE 0 < (SELECT COUNH*) FROM SGROUP
WHERE SGROUP.DepFK - DEPARTMENT.DepPK);
NAME
базы данных программирование интернет
Запрос. Вывести названия кафедр, не имеющих ни одной группы.
SELECT Name FROM DEPARTMENT
WHERE NOT EXISTS (SELECT * FROM SGROUP
WHERE SGROUP.DepFK = DEPARTMENT.DepPK);
SELECT Name FROM DEPARTMENT
WHERE 0 = (SELECT COUNT(*) FROM SGROUP
WHERE SGROUP.DepFK = DEPARTMENT.DepPK);
NAME
теория языков лингвистика базы данных
Не удивляйтесь, что кафедра баз данных включена в оба списка — в учебной базе данных имеется две таких кафедры.
Если подзапрос является коррелированным, вместо оператора EXISTS можно использовать соединение тех же таблиц, что указаны во внешнем и вложенном запросах при использовании EXISTS, причем по тому же условию. Оператор NUT EXISTS не может быть заменен соединением.
Запрос. Вывести фамилии преподавателей, являющихся кураторами.
SELECT TEACHER.Name FROM TEACHER
WHERE EXISTS (SELECT * FROM SGROUP
WHERE SGROUP.CurFK = TEACHER.TchPK);
SELECT DISTINCT TEACHER.Name FROM TEACHER, SGROUP
WHERE SGROUP.CurFK = TEACHER.TchPK;
NAME
Кузинцев
Завратинский
Лекарь
При соединении таблиц преподавателей и групп по условию SGROUP.CurFK - TEACHER. TchPK будут соединены только те строки таблицы преподавателей, первичные ключи которых присутствуют среди значений столбца CurFK таблицы групп. А это как раз те преподаватели, которые являются кураторами.
Запрос. Вывести номера групп не пятого курса, рейтинг которых выше, чем у какой-нибудь группы пятого курса.
SELECT gl.Num FROM SGROUP gl
WHERE gl.Year <> 5 AND
EXISTS (SELECT * FROM SGROUP g2
WHERE gl.Rating > g2.Rati ng AND g2.Year = 5);
SELECT gl.Num FROM SGROUP gl, SGROUP g2
WHERE gl.Year <> 5 AND
gl.Rati ng > g2.Rati ng AND g2.Year = 5;
NUM
Использование оператора EXISTS во фразе HAVING
Операторы EXISTS и NOT EXISTS могут использоваться во фразе HAVING. Подзапросы при этом могут быть простыми и коррелированными. Для простых подзапросов специальных ограничений нет. Для коррелированных подзапросов необходимо, чтобы либо все внешние ссылки указывали на столбцы, по которым производится группировка, либо чтобы они использовались в качестве аргументов агрегатных функций.
Запрос. Вывести названия факультетов и суммарные фонды финансирования их кафедр, если в базе данных присутствуют сведения хотя бы об одном преподавателе.
SELECT f.Name, SUM(d.Fund)
FROM FACULTY f, DEPARTMENT d
WHERE f.facPK = d.facFK
GROUP BY f.Name
HAVING EXISTS (SELECT * FROM TEACHER);
NAME SUM(D.FUND)
информатика48000
кибернетика51100
В учебной базе данных имеется информация о преподавателях, поэтому предикат EXISTS принимает истинное значение. В результирующей таблице присутствуют только те факультеты, на которых имеются кафедры.
Запрос. Вывести названия факультетов и суммарные фонды финансирования их кафедр, если суммарный фонд финансирования кафедр превышает 50 000.
SELECT f.Name, SUM(d.Fund) FROM FACULTY f. DEPARTMENT d WHERE f.facPK = d.facFK GROUP BY f.FacPK, f.Name HAVING EXISTS (SELECT * '
FROM DEPARTMENT d2
WHERE d2.FacFK = f.FacPK AND SUM(d.Fund) > 50000);
NAME SUM(D.FUND)
кибернетика 51100
Обратите внимание, что без оператора EXISTS этот запрос может быть выражен намного проще:
SELECT f.Name. SUM(d.Fund) FROM FACULTY f, DEPARTMENT d WHERE f.facPK = d.facFK GROUP BY f.FacPK. f.Name HAVING SUM(d.Fund) > 50000;
Использование операторов ANY, SOME и ALL
Эти три оператора расширяют возможности операторов сравнения и применяются в случае, когда правый операнд является множеством. Синтаксис их использования следующий: скалярное_выражение оператор_сравнения {ANY | SOME | ALL} спецификация_множества
В качестве спецификации множества может выступать список литералов соответствующего типа или подзапрос. Подзапрос должен возвращать значения того же типа, который имеет левый операнд.
Операторы ANY и SOME
Операторы SOME и ANY производят сравнение единственного значения левого операнда с множеством значений правого операнда. Это сравнение производится в соответствии с используемым оператором сравнения (=, <>, >, <, <=, >=). Если оператор сравнения истинен хотя бы для одного значения во множестве, результатом будет TRUE, в противном случае — FALSE; если множество правого операнда пустое, результатом будет FALSE, а если правый операнд имеет значение NULL, результатом будет UNKNOWN.
>> ^ПРИМЕЧАНИЕ Операторы SOME и ANY являются взаимозаменяемыми — вместо оператора ANY можно использовать SOME и наоборот.
Запрос. Вывести названия факультетов, фонды финансирования которых меньше фонда финансирования хотя бы одной из кафедр факультета информатики.
SELECT Name FROM FACULTY
WHERE Fund < SOME (SELECT DEPARTMENT.Fund FROM DEPARTMENT, FACULTY
WHERE DEPARTMENT.FacFK = FACULTY.FacPK ANDUPPERCFACULTY.Name) = 'ИНФОРМАТИКА');
NAME
информатика
математика
Запрос. Вывести фамилии доцентов, зарплата которых больше, чем ставка хотя бы одного из профессоров.
SELECT t.Name FROM TEACHER t
WHERE LOWER(t.Post) = 'доцент' AND
Salary + Rise > SOME (SELECT Salary FROM TEACHER t2*
WHERE L0WER(t2.Post) = 'профессор');
NAME
Рамишевский
Завратинский
Лекарь
Наумов
Замена оператора SOME операторами IN или EXISTS
Условию = SOME равносилен предикат IN. Однако если оператору SOME предшествует любой другой оператор сравнения, эквивалентности нет. Следующие два запроса эквивалентны.
Запрос. Вывести названия кафедр, фонды финансирования которых равны фонду финансирования хотя бы одного факультета.
SELECT Name FROM DEPARTMENT
WHERE Fund = SOME (SELECT Fund FROM FACULTY):
SELECT Name FROM DEPARTMENT
WHERE Fund IN (SELECT Fund FROM FACULTY);
NAME
базы данных
Любой запрос, который может быть сформулирован с помощью оператора SOME (и, как мы увидим позже, оператора ALL), может быть переписан с использованием оператора EXISTS, хотя наоборот будет неверно. Приведем пример такой замены. Запрос. Вывести названия кафедр, фонды финансирования которых больше фонда финансирования хотя бы одного факультета.
SELECT Name FROM DEPARTMENT
WHERE Fund > SOME (SELECT Fund FROM FACULTY);
SELECT Name FROM DEPARTMENT
WHERE EXISTS (SELECT Fund FROM FACULTY
WHERE DEPARTMENT.Fund > FACULTY.Fund);
NAME
базы данных базы данных
Как видно из приведенного примера, суть такой замены заключается в том, чтобы перенести сравнение от оператора SOME внутрь подзапроса и заменить SOME на оператор EXISTS (подзапрос при этом становится коррелированным). Строго говоря, вариант с оператором EXISTS не полностью идентичен варианту с оператором SOME (или ALL) из-за различной обработки значения NULL. Однако оператор SOME (ANY) удобнее в использовании, чем EXISTS, который требует дополнительного связывания подзапроса.•
Замена оператора SOME агрегатной функцией
Условие < SOME равносильно утверждению «меньшее значение, чем наибольшее из существующих», а условие > SOME — утверждению «большее значение, чем наименьшее из существующих». С учетом сказанного становится очевидной возможность замены таких условий функциями МАХ и MIN. Покажем на примерах, как это делается.
Запрос. Вывести названия кафедр, фонды финансирования которых больше фонда финансирования хотя бы одного факультета.
SELECT Name FROM DEPARTMENT
WHERE Fund > SOME (SELECT Fund FROM FACULTY);
SELECT Name FROM DEPARTMENT
WHERE Fund > (SELECT MIN(Fund) FROM FACULTY);
NAME
базы данных базы данных
Запрос. Вывести названия кафедр, фонды финансирования которых меньше фонда финансирования хотя бы одного факультета. *
SELECT Name FROM DEPARTMENT
WHERE Fund < SOME (SELECT Fund FROM FACULTY);
SELECT Name FROM DEPARTMENT
WHERE Fund < (SELECT MAX(Fund) FROM FACULTY);
NAME
базы данных программирование интернет
теория языков лингвистика
Оператор ALL
В отличие от операторов SOME и ANY, оператор ALL принимает значение TRUE, если все члены множества правого операнда удовлетворяют условию сравнения. В ином случае оператор ALL принимает значение FALSE. Если множество является пустым, значением оператора ALL будет TRUE, а если правый операнд имеет значение NULL, значением оператора ALL будет UNKNOWN.
Запрос. Вывести номера групп, рейтинги которых ниже рейтинга любой из групп пятого курса кафедры программирования.
SELECT Num FROM SGROUP
WHERE Rating < ALL (SELECT Rating FROM SGROUP g. DEPARTMENT d
WHERE g.DepFK = d.DepPK AND
. LOWER(d.Name) = 'программирование* AND g.Year = 5);
NUM
307
201
Запрос. Вывести фамилии преподавателей любой кафедры, кроме кафедры программирования, принятых на работу раньше, чем любой из ассистентов кафедры программирования.
SELECT t.Name
FROM TEACHER t. DEPARTMENT d
WHERE t.DepFK = d.DepPK AND
LOWER(d.Name) <> 'программирование* AND
Hi reDate < ALL (SELECT Hi reDate
FROM TEACHER t2, DEPARTMENT d2
WHERE t2.DepFK = d2.DepPK AND
L0WER(d2.Name) = 'программирование* AND
L0WER(t2.Post) = 'ассистент');
строки не выбраны
Предыдущий запрос не возвращает строк, однако если обратиться к учебной базе данных, в ней можно обнаружить преподавателей, кафедра которых не указана (значение столбца DepFK равно NULL). Если считать, что они не работают на кафедре программирования, включить их в результат можно с помощью оператора UNION (он подробно рассматривается в уроке 9):
SELECT t.Name
FROM TEACHER t. DEPARTMENT d
WHERE t.DepFK - d.DepPK AND
LOWER(d.Name) <> 'программирование* AND
Hi reDate < ALL (SELECT Hi reDate
FROM TEACHER t2, DEPARTMENT d2
WHERE t2.DepFK = d2.DepPK AND
L0WER(d2.Name) = 'программирование* AND
L0WER(t2.Post) = 'ассистент*)
UNION
SELECT t.Name
FROM TEACHER t
WHERE t.DepFK IS NULL AND
Hi reDate < ALL (SELECT Hi reDate
FROM TEACHER t2. DEPARTMENT d2
WHERE t2.DepFK = d2.DepPK AND
LOWER(d2.Name) = 'программирование* AND L0WER(t2.Post) = 'ассистент');
NAME
Ахромеев Наумов Дараганов
СОВЕТ При формулировке условий в запросах помните, что в базе данных могут присутствовать значения NULL, а они не равны никакому значению, даже самому себе.
Замена оператора ALL оператором EXISTS
Как и в случае с оператором SOME, оператор ALL можно заменить на оператор EXISTS, вернее на его форму NOT EXISTS. Покажем это на примере одного из приведенных ранее запросов.
Запрос. Вывести номера групп, рейтинги которых ниже рейтинга любой из групп пятого курса кафедры программирования.
SELECT Num FROM SGROUP
WHERE Rating < ALL (SELECT Rating FROM SGROUP g, DEPARTMENT d
WHERE g.DepFK = d.DepPK AND
LOWER(d.Name) = 'программирование* AND
g.Year = 5);
SELECT Num FROM SGROUP gout
WHERE NOT EXISTS (SELECT Rating FROM SGROUP gin, DEPARTMENT din
WHERE gin.DepFK = din.DepPK AND
gout.Rati ng >= gin.rating AND
LOWER(din.Name) = 'программирование* AND
.gin.Year = 5);
NUM
307
201
Как видите, суть замены состоит в указании в подзапросе такого сравнения, которое противоположно использованному при операторе SOME. При этом простой подзапрос становится коррелированным. Однако будьте внимательны — операторы
ALL и EXISTS по-разному обрабатывают неопределенные значения. Если в приведенном примере столбец Rating будет иметь одно или несколько значений NULL, запросы окажутся не эквивалентны. В этом случае в первом запросе условие < ALL будет принимать значение UNKNOWN и соответствующие строки выбраны не будут. Во втором же запросе выражение gout.Rating >- gin.rating примет значение UNKNOWN для всех строк таблицы SGROUP, поэтому подзапрос вернет пустое множество строк. Для пустого множества предикат NOT EXISTS истинен, а значит, строки с неопределенными значениями столбца rating будут включены в результат. Чтобы и при наличии неопределенных значений в столбце rating запросы были эквивалентны, нужно поступить следующим образом:
SELECT Num FROM SGROUP gout
WHERE gout.Rati ng IS NOT NULL AND
NOT EXISTS (SELECT Rating FROM SGROUP gin. DEPARTMENT din
WHERE gin.DepFK = din.DepPK AND
gout.Rati ng >= gin.rating AND
LOWER(din.Name) = 'программирование' AND gin. Year = 5);
Описанная замена операторов ALL и EXISTS применима для всех условий сравнения.
Использование в операторе ALL равенства и неравенства
Оператор ALL гораздо чаще используется с неравенствами, чем с равенствами — значение левого операнда будет равно всем значениям правого операнда, только если все значения правого операнда совпадают. Рассмотрим следующий запрос.
Запрос. Вывести номера групп, рейтинг которых равен рейтингу любой группы пятого курса.
SELECT Num FROM SGROUP
WHERE Rating =ALL (SELECT Rating FROM SGROUP
WHERE SGROUP.Year = 5);
строки не выбраны
Этот запрос допустим, но имеет смысл только тогда, когда рейтинги всех групп пятого курса совпадают. Попробуем выразить запрос без, оператора ALL:
SELECT Num FROM SGROUP
WHERE Rating = (SELECT DISTINCT Rating FROM SGROUP
WHERE SGROUP.Year = 5);
WHERE Rating = (SELECT DISTINCT Rating FROM SGROUP *
ошибка в строке 2:
ORA-01427: подзапрос одиночной строки возвращает более одной строки
Если в варианте с оператором ALL запрос просто не возвращает строк, в последнем случае он возвращает их несколько, что приводит к ошибке. С подобной ошибкой мы уже сталкивались (см. урок 7).
СОВЕТ Не используйте запросы, которые выполняются правильно только для некоторых наборов данных.
С неравенством в операторе ALL подобных проблем не возникает. Предикат <> ALL соответствует утверждению «не равно ни одному возвращенному подзапросом значению». В качестве примера приведем запрос, противоположный по смыслу предыдущему.
Запрос. Вывести номера групп, рейтинг которых не равен рейтингу любой группы пятого курса.
SELECT Num FROM SGROUP
WHERE Rating <> ALL (SELECT Rating FROM SGROUP
WHERE SGROUP.Year - 5):
NUM
307
408
201
Взаимозаменяемость предикатов NOTIN и <> ALL
Предикаты <> ALL и NOT IN полностью взаимозаменяемы, причем независимо от того, является подзапрос простым или связанным. Кроме того, они одинаково реагируют на пустое множество и неопределенные значения.
Запрос. Вывести фамилии преподавателей, дата приема которых на работу не совпадает с датами приема преподавателей кафедры программирования.
SELECT Name
FROM TEACHER
WHERE Hiredate <> ALL (SELECT t.Hi reDate
FROM TEACHER t, DEPARTMENT d
WHERE t.DepFK = d.DepPK AND
LOWER(d.Name)='программирование *);
SELECT Name
FROM TEACHER
WHERE Hiredate NOT IN (SELECT t.Hi reDate
FROM TEACHER t, DEPARTMENT d
WHERE t.DepFK ^ d.DepPK AND
LOWER(d.Name)=* программирование *);
NAME
Ахромеев Наумов Дараганов
Запрос. Вывести названия факультетов, фонд финансирования которых не совпадает с фондом финансирования любой их кафедры.
SELECT WHERE
Name Fund
FROM FACULTY о ALL (SELECT WHERE
Fund FROM DEPARTMENT
FACULTY.FacPK - DEPARTMENT.FacFK);
SELECT WHERE
Name Fund
FROM FACULTY
NOT IN (SELECT
Fund FROM DEPARTMENT
WHERE FACULTY.FacPK = DEPARTMENT.FacFK):
NAME
информатика математика
Взаимозаменяемость операторов ALL и SOME
Взаимозаменяемыми являются также операторы ALL и SOME. Правило следующее: нужно заменить ALL на SOME (или SOME на ALL), заменить указанный оператор сравнения на противоположный и поставить перед левым операндом оператор NOT. Приведем схему такой замены:
столбец 6 ALL (запрос) <=> NOT столбец -.0 SOME (запрос)
столбец в SOME (запрос) а> NOT столбец -.0 ALL (запрос)
где 0 — любой из операторов сравнения, -10 — оператор сравнения, противоположный 0, <=> — знак эквивалентности. Приведем примеры.
Запрос. Вывести названия факультетов, фонд финансирования которых больше фондов финансирования любых их кафедр.
SELECT f.Name FROM FACULTY f
WHERE f.Fund > ALL (SELECT d.Fund FROM DEPARTMENT d WHERE f.FacPK - d.FacFK);
SELECT f.Name FROM FACULTY f
WHERE NOT f.Fund <» SOME (SELECT d.Fund FROM DEPARTMENT d
WHERE f.FacPK - d.FacFK);
NAME
математика
В обоих случаях выводится только факультет математики, и то только потому, что у него вообще нет кафедр.
Запрос. Вывести названия факультетов, фонд финансирования которых не совпадает с фондом финансирования любых их кафедр.
SELECT f.Name FROM FACULTY f>
WHERE f.Fund <> ALL (SELECT d.Fund FROM DEPARTMENT d
WHERE f.FacPK = d.FacFK);
SELECT f.Name FROM FACULTY f
WHERE NOT f.Fund = SOME (SELECT d.Fund FROM DEPARTMENT d
WHERE f.FacPK = d.FacFK);
NAME
информатика-
математика
На факультете кибернетики имеется такое совпадение, на факультете информатики — нет, факультет математики снова выведен потому, что на нем кафедр нет.
Замена оператора ALL агрегатной функцией
Условие < ALL равносильно утверждению «меньшее значение, чем наименьшее из существующих», а > ALL — «большее значение, чем наибольшее из существующих».
С учетом сказанного становится очевидной возможность замены таких условий функциями МАХ и MIN. Покажем на примерах, как это делается.
Запрос. Вывести названия кафедр, фонд финансирования которых меньше фонда финансирования любого факультета.
SELECT Name FROM DEPARTMENT
WHERE Fund < ALL (SELECT Fund FROM FACULTY):
SELECT Name FROM DEPARTMENT
WHERE Fund < (SELECT MIN(Fund) FROM FACULTY);
NAME
программирование
интернет
теория языков
лингвистика
Запрос. Вывести названия кафедр, фонд финансирования которых не меньше фонда финансирования любого факультета.
SELECT Name FROM DEPARTMENT
WHERE Fund >= ALL (SELECT Fund FROM FACULTY);
SELECT Name FROM DEPARTMENT
WHERE Fund >= (SELECT MAX(Fund) FROM FACULTY);
NAME
базы данных
Операторы SOME и ALL при отсутствии данных
Когда подзапрос не возвращает значений, результат операторов ALL и SOME противоположен — оператор ALL принимает значение TRUE, оператор SOME — FALSE. Это означает, что следующий запрос не будет выводить строки (фонд финансирования не может быть отрицательным):
SELECT Name FROM FACULTY
WHERE Fund = SOME (SELECT Fund FROM DEPARTMENT WHERE Fund < 0);
строки не выбраны
В то же время следующий запрос выводит названия всех факультетов:
SELECT Name FROM FACULTY
WHERE Fund = ALL (SELECT Fund FROM DEPARTMENT
WHERE Fund < 0);
NAME
информатика кибернетика математика
выражения и функции выбора вариантов
В стандарте SQL определены средства для выбора вариантов действий в зависимости от значений данных. Одно из них — функция COALESCE — уже использовалось ранее, но подробно рассматривается в этом разделе.
Выражение CASE
Это выражение позволяет организовать ветвления при вычислении предложений SQL. Его можно использовать во фразах SELECT и WHERE. Имеются две формы выражения CASE: простая и с условием. Простая форма CASE имеет следующий синтаксис:
CASE выражение
{WHEN значение THEN результат}..,
[ELSE результат] END
В этой форме последовательно сравниваются значения при фразах WHEN со значением заданного выражения. При первом же совпадении возвращается значение при соответствующей фразе THEN. Если совпадений нет, возвращается результат при фразе ELSE.
Синтаксис выражения CASE с условием следующий:
CASE
{WHEN условие THEN результат}...
[ELSE результат] END
В этом случае последовательно проверяются все условия при фразах WHEN. Если условие истинно, возвращается значение соответствующей фразы THEN. Если ни одно условие при фразах WHEN не оказалось истинным, возвращается значение при фразе ELSE.
В обоих вариантах фраза ELSE может отсутствовать — тогда при отсутствии совпадения или истинного условия выражение CASE возвращает NULL. Также в обоих вариантах в качестве возвращаемого результата может быть указано значение NULL. Рассмотрим использование выражения CASE во фразе SELECT.
Запрос. Вывести полные названия дней недели, в которые проходят занятия.
SELECT DISTINCT CASE Day
WHEN
'пнд*
THEN
'понедельник*
WHEN
*втр*
THEN
'вторник*
WHEN
'срд'
THEN
'среда'
WHEN
*чтв*
THEN
'четверг*
WHEN
* птн *
THEN
'пятница*
WHEN
'суб'
THEN
'суббота*
ELSE
'воскресенье*
'END AS "Дни недели"
FROM LECTURE;
Дни недели
вторник понедельник пятница
среда
четверг
Ранее для достижения такого же результата мы использовали функцию DECODE, но следующий запрос уже нельзя выразить с ее помощью.
Запрос. Вывести фамилии доцентов и ассистентов. Если принят на работу до 01.01.1996, вывести строку 'Очень давно', если между 01.01.1996 и 01.01.2001 - строку 'Давно', и если после 01.01.2001 — строку 'Недавно*.
SELECT Name AS "Фамилия".
(CASE WHEN Hi reDate < DATE '1996-01*01' THEN 'Очень давно*
WHEN Hi reDate BETWEEN DATE '1996-01-0Г AND
DATE '2001-01-0Г THEN 'Давно'
ELSE 'Недавно*
END) AS "Принят на работу"
FROM TEACHER
WHERE LOWER(Post) IN ('ассистент', 'доцент'):
Фамилия Принят на работу
Рамишевский Давно
Вибровский Недавно
Воропаев Недавно
Завратинский Давно
Козлутин Недавно
Лекарь Очень давно
Мартынов Недавно Наумов Очень давно
Выражение CASE можно использовать даже в аргументе агрегатной функции.
Запрос. Установим следующие оценочные баллы величины зарплаты: 0-500 — 1 балл; 501-1000 — 2 балла, 1001-1500 — 3 балла, 1501-2000 — 4 балла, более 2000 — 5 баллов. Подсчитать среднюю зарплату преподавателей в баллах.
SELECT AVG(CASE WHEN Salary + Rise BETWEEN 0 AND 500 THEN 1
WHEN Salary + Rise BETWEEN 501 AND 1000 THEN 2
WHEN Salary + Rise BETWEEN 1001 AND 1500 THEN 3
WHEN Salary + Rise BETWEEN 1501 AND 2000 THEN 4
WHEN Salary + Rise > 2000 THEN 5
ELSE 0
END) AS "Средняя зарплата в баллах"
FROM TEACHER:
Средняя зарплата в баллах
2.66666667
Покажем, как выражение CASE может использоваться во фразе WHERE.
Запрос. Для каждой должности подсчитать количество преподавателей на ней и кафедр, на которых работают преподаватели в этой должности. Если кафедра не указана, считать, что профессора работают на кафедре лингвистики, доценты — на кафедре теории языков, остальные — на кафедре «Интернет».
SELECTt.PostAS"Должность",
COUNT(*)AS"К-вопреподавателей".
COUNT(UNIQUEd.DepPK)AS"К-вокафедр"
FROMTEACHER t.DEPARTMENTd
WHERE d.DepPK - (CASE WHEN t.DepFK IS NOT NULL THEN t.DepFK
ELSE (CASEELSE (CASEEND)END)GROUP BY t.Post;END)END)GROUP BY t.Post;WHEN t.Post - 'профессор'
ELSE (CASE
ELSE (CASE
END)
END)
GROUP BY t.Post;
END)
END)
GROUP BY t.Post;
THEN (SELECT DepPK "
FROM DEPARTMENT
WHERE Name = 'лингвистика')
WHEN t.Post = 'доцент'
THEN (SELECT DepPK
FROM DEPARTMENT
WHERE Name ='теория языков’) ELSE (SELECT DepPK
FROM DEPARTMENT
WHERE Name = 'интернет')
ассистент доцент преподаватель профессорассистент доцент преподаватель профессор4142423241424232ДолжностьК-во преподавателей К-во кафедр
ассистент доцент преподаватель профессор
ассистент доцент преподаватель профессор
41
42
42
32
41
42
42
32
Функция COALESCE
Эта функция используется для замены неопределенного значения на любое другое. Функция COALESCE возвращает значение своего первого аргумента, отличного от NULL, а если NULL равны все аргументы, возвращает NULL. Ее синтаксис следующий:
COALESCE(apryMeHT[, аргумент]...)
Функция COALESCE может быть представлена выражением CASE. Например, выражению COALESCE(apryMeHT_l. аргумент_2) эквивалентно такое:
CASE WHEN аргумент-1 IS NOT NULL
THEN аргумент_1
ELSE аргумент_2
END
Аналогичным образом конструкции
COALESCE(аргумент_1, аргумент_2аргументу)
эквивалентна следующая:
CASE WHEN аргументу IS NOT NULL
THEN аргумент^!
ELSE СОАЕЕ5СЕ(аргумент_2аргументу) END
где каждую вложенную функцию COALESCE также можно развернуть в выражение CASE по указанному принципу.
Запрос. Вывести фамилии преподавателей, занимающих должности преподавателя или профессора, а также первое существующее значение из следующего списка: Chief, DepFK (если оба значения отсутствуют, вывести 0).
SELECT Name. COALESCE(Chief, DepFK, 0)
FROM TEACHER
WHERE LOWER(Post) IN ('преподаватель', 'профессор'):
NAME COALESCE(CHIЕЕ,DEPFK.О)
Сидоров2
Хоренко4
Кузинцев4
Резван16
Недеведеев7
АхромеевО
ДарагановО
Обратите внимание, что для Сидорова выведено значение столбца DepFK, так как для него отсутствует значение в столбце Chi ef, для Ахромеева и Дараганова выведен 0, так как для них отсутствуют оба значения, а у всех остальных указано значение столбца Chief.
Функция NULUF
Функция NULL IF производит замену заданного значения на NULL. Синтаксис функции следующий:
NULLIFCвыражение. значение)
Если первый аргумент (обычно это имя столбца или выражение над столбцами) совпадает с указанным значением, функция возвращает NULL, иначе возвращается значение выражения. Обычно функция NULL IF используется в том случае, когда в базе данных неопределенные по сути значения кодируются конкретным определенным значением. Например, для отсутствующих числовых значений используется их замена на 0 — это облегчает составление выражений. При этом функцию NULLIF можно использовать для восстановления неопределенного значения. Запрос. Вывести общее количество преподавателей, количество преподавателей, имеющих телефон, общее количество номеров телефонов и действительное их количество, считая, что номер 1234567 обозначает отсутствие номера.
SELECT COUNTC*) AS "К-во прел.".
COUNT(Tel) AS "К-во прел, с тел.", COUNT(DISTINCT Tel) AS "К-во номеров тел.". COUNTCDISTINCT NULLIF(Tel. '1234567')) AS "1 номер NULL" FROM TEACHER;
К-во прел. К-во прел, с тел. К-во номеров тел. 1 номер NULL
151043
Выражение предикатов над множествами
В стандарте SQL не определены предикаты, проверяющие вхождение одного множества в другое (типа «содержит» и «содержится»). К сожалению, поскольку с их помощью можно было бы легко выражать в запросах такие полезные операции, как деление из реляционной алгебры или квантор общности из реляционного исчисления. Однако такое деление и соответствующий ему ограниченный квантор общности могут быть заменены другими операциями и выражениями, существующими в стандарте SQL.
Как известно, квантор общности можно выразить через отрицание и квантор существования — высказывание «для всех х имеет место А» может быть заменено на высказывание «не существует таких х, для которых не имеет места А». Именно таким образом следует поступить для выражения квантора общности средствами SQL. Рассмотрим пример.
Запрос. Вывести фамилии преподавателей, ведущих занятия всех типов.
Для начала переформулируем этот запрос следующим образом: «Вывести фамилии преподавателей, для которых не существует типов занятий, которые они не проводят». Первая часть переформулированного запроса («Вывести фамилии преподавателей, для которых не существует типов занятий, которые...») выражается следующим образом:
SELECT t.Name
FROM TEACHER t
WHERE NOT EXISTS (SELECT l.Type
FROM LECTURE 1
WHERE ...):
Теперь добавим выражение, устанавливающее условие на тип занятия. Для этого сначала выразим следующий вспомогательный запрос: «Вывести типы занятий, которые не читает преподаватель Иванов».
SELECT 1.Туре
FROM LECTURE 1
WHERE NOT EXISTS (SELECT 12.TchFK
FROM LECTURE 12, TEACHER t2
WHERE t2.TchPK = 12.TchFK AND t2.Name = 'Иванов' AND 12.Type = l.Type);
Теперь два запроса необходимо объединить:
О фразу WHERE подзапроса первого запроса заменить внешней фразой WHERE второго запроса;
О во фразе WHERE подзапроса второго запроса литерал конкретной фамилии заменить фамилией из текущей строки, отобранной в первом запросе (столбец t. Name).
В результате полный запрос примет следующий вид:
SELECT t.Name
FROM TEACHER t
WHERE NOT EXISTS (SELECT l.Type
FROM LECTURE 1
WHERE NOT EXISTS (SELECT 12.TchFK
FROM LECTURE 12, TEACHER t2
WHERE t2.TchPK = 12.TchFK AND t2.Name = t.Name AND 12.Type = 1.Type));
строки не выбраны
Как видим, таких преподавателей в учебной базе данных не оказалось. Ослабим условие на типы занятий.
Запрос. Вывести фамилии преподавателей, ведущих занятия всех тех типов, которые ведет Хоренко.
Сначала опять переформулируем запрос: «Вывести фамилии преподавателей, для которых среди типов занятий, проводимых Хоренко, не существует таких, которые не проводят они». Далее, как и в предыдущем случае, выразим промежуточный запрос: «Среди типов занятий, которые ведет преподаватель Хорецко, вывести такие, которые не ведет преподаватель Иванов». Запрос имеет следующий вид:
SELECT 1.Туре
FROM LECTURE 1. TEACHER t
WHERE l.TchFK = t.TchPK AND
t.Name = 'Хоренко* AND
NOT EXISTS (SELECT 12.TchFK
FROM LECTURE 12. TEACHER t2
WHERE t2.TchPK = 12.TchFK AND
t2.Name = 'Иванов* AND 12.Type = l.Type);
По сравнению с первым примером здесь во фразе WHERE внешнего запроса добавлено условие, отбирающее типы занятий преподавателя Хоренко. Объединяя запросы как и в предыдущем примере, получаем следующий полный запрос:
SELECT tch.Name
FROM TEACHER tch
WHERE NOT EXISTS (SELECT DISTINCT l.Type
FROM LECTURE 1, TEACHER t
WHERE l.TchFK = t.TchPK AND
t.Name = 'Хоренко* AND
NOT EXISTS (SELECT DISTINCT 12.TchFK
FROM LECTURE 12.TEACHER t2
WHERE t2.TchPK = 12.TchFK AND
t2.Name = tch.Name AND 12.Type - l.Type)):
NAME
Рамишевский
Хоренко
Кузинцев
Завратинский
Лекарь
Резван
Дараганов
Хоренко проводит только лекционные занятия, поэтому выведены фамилии всех тех преподавателей, которые проводят лекционные занятия. Если в запросе заменить Хоренко на Воропаева, который проводит лабораторные занятия, получим список всех преподавателей, которые проводят лабораторные занятия.
Самостоятельная работа
Вывести номера аудиторий, в которых проводит занятия Кузинцев.
Вывести фамилии ассистентов, ведущих занятия в группе 505 пятого курса.
Вывести дисциплины, которые читает преподаватель Хоренко для группы 505 пятого курса.
Подведениеитогов 167
Вывести фамилии преподавателей, которые не ведут занятий в понедельник первой недели.
Вывести номера аудиторий с указанием их корпусов, в которых нет занятий в среду второй недели на третьей паре.
g Вывести фамилии преподавателей факультета информатики, которые не курируют группы кафедры программирования.
Вывести номера групп, у которых по расписанию нет занятий. Составьте три варианта этого запроса: с оператором NOT EXISTS, с функцией COUNT и с соединением таблиц.
Вывести фамилии доцентов факультета информатики, принятых на работу раньше любого профессора кафедры программирования.
Вывести фамилии доцентов факультета информатики, принятых на работу в том же году, в котором на кафедру программирования был принят профессор. Составьте три варианта этого запроса: с операторами SOME, IN и EXISTS.
Вывести список профессоров факультета информатики, принятых на работу позже любого доцента кафедры программирования. Составьте два варианта этого запроса: с операторами ALL и EXISTS.
И. Вывести список типов занятий, имеющихся в расписании. При выводе используйте замену строк: 'лаб1 — «лабораторная», *лекц* — «лекция», 'практ* — «практическая».
Вывести фамилии преподавателей и номера их телефонов. При отсутствии номера вывести строку 'нет телефона*.
Подведение итогов
Усвоив материал этого урока, вы научились:
0 использовать оператор EXISTS с простыми подзапросами;
0 использовать оператор EXISTS со связанными подзапросами;
0 использовать оператор NOT EXISTS с простыми и связанными подзапросами;
0 заменять операторы EXISTS и NOT EXISTS на другие операторы;
0 использовать операторы EXISTS и NOT EXISTS во фразе HAVING;
0 создавать запросы с использованием операторов ANY и SOME;
0 создавать запросы с использованием оператора ALL;
0 заменять операторы ANY, SOME и ALL на другие операторы.;
0 использовать выражение CASE для указания вариантов выбора;
0 применять функции COALESCE и NULL IF для работы с неопределенными значениями;
0 выражать теоретико-множественные предикаты.
i УРОКi УРОКМножественные операции над таблицами
i УРОК
i УРОК
Рассмотренные ранее варианты предложения SELECT соответствуют некоторым операциям реляционной алгебры, а именно — проекции, селекции (отбору) и соединению. Кроме того, для достижения необходимой теоретико-множественной полноты в SQL введены три дополнительные операции — объединение (UNION), пересечение (INTERSECT) и разность (EXCEPT). Все они выполняются над таблицами, полученными в результате запросов, и, в свою очередь, возвращают таблицу.
Множественные операции в стандарте SQL
В стандарте SQL множественные операции имеют следующий синтаксис:
запрос {UNION | INTERSECT | EXCEPT } [DISTINCT | ALL] запрос
где запрос является предложением SELECT. Отличаются эти операции тем, какие строки возвращенных запросами таблиц отбираются в новую результирующую таблицу:
О UNION — все строки таблиц, возвращенных обоими запросами;
О INTERSECT — только те строки, которые имеются в таблицах обоих запросов;
О EXCEPT — только те строки таблицы первого запроса, которых нет среди строк . таблицы второго запроса.
Запросы, содержащие множественные операторы, называются составными.
Следует отметить, что стандарт SQL непоследователен в отношении повторяющихся строк в таблицах. Это проявляется в следующем:
О базовые таблицы не могут содержать повторяющихся строк (это принципиальное требование реляционной модели данных);
О результирующие таблицы запросов могут содержать повторяющиеся строки, если это не запрещено ключевым словом DISTINCT во фразе SELECT;
О результирующие таблицы множественных операций не могут содержать повторяющихся строк, если это не разрешено ключевым словом ALL.
Таким образом, именно ключевые слова ALL и DISTINCT указывают, допускаются ди в результирующей таблице повторяющиеся строки. В запросах при отсутствии явного указания предполагается использование ключевого слова ALL, а во множественных операциях — DISTINCT.
Если смысл ключевого слова ALL для операции UNION интуитивно понятен (все экземпляры строк результирующих таблиц запросов, в том числе одинаковые, включаются в результирующую таблицу множественной операции), то для операций INTERSECT и EXCEPT он не очевиден. В стандарте SQL для них принята следующая трактовка. Пусть, например, обе исходные таблицы Т1 и Т2 содержат строку t, причем первая из них содержит п дубликатов t, а вторая - т дубликатов. Тогда результирующая таблица множественной операции будет содержать следующее количество дубликатов стоки t:
Т1 UNION ALL Т2 п + т
Т1 INTERSECT ALL Т2 min(n, m)
Т1 EXCEPT ALL T2 max((n - т\ 0)
Такая изощренная трактовка поддерживается не во всех СУБД. Дублирование строк в результате операции объединения, как правило, допускается, но для операций пересечения и разности — запрещается. В частности, именно так работает Oracle.
Таблицы, используемые в качестве операндов множественной операции, должны быть совместимы. Под этим подразумевается следующее:
О обе таблицы должны иметь одинаковое количество столбцов;
О соответствующие пары столбцов должны быть одинаковых или совместимых типов.
Далее в этом уроке мы рассмотрим использование множественных операций на примере Oracle. Соответствие множественных операций стандарта SQL и Oracle указано в табл. 9.1.
Таблица 9.1. Множественные операции Oracle
OracleSQL
UNION
UINION DISTINCT
UNION ALL
UNION ALL
INTERSECT
INTERSECT DISTINCT
MINUS
EXCEPT DISTINCT
Все эти операторы имеют одинаковое старшинство и вычисляются слева направо. Для изменения порядка вычисления нужно использовать круглые скобки.
Объединение таблиц
Оператор UNION объединяет строки двух таблиц в одну с удалением дубликатов, при использовании оператора UNION ALL дубликаты не удаляются.
Простое объединение
В простейшем варианте оператор UNION позволяет объединить столбцы, имеющие в результирующих таблицах запросов одинаковые названия.
Запрос. Вывести номера всех корпусов, в которых расположены и факультеты, и кафедры.
SELECT Building FROM FACULTY
UNION
SELECT Building FROM DEPARTMENT:
BUILDING
3
5
6
ВНИМАНИЕ Символ конца запроса (;) ставится в конце второго запроса.
Кроме того, столбцы могут иметь и различные имена, но их типы должны быть одинаковыми или совместимыми.
Запрос. Вывести названия факультетов и кафедр, расположенных в корпусе 6, а также фамилии их деканов или заведующих.
SELECT Name. Dean
FROM FACULTY
WHERE Building = '6'
UNION
SELECT Name. Head
FROM DEPARTMENT
WHERE Building = '6';
NAMEDEAN
базы данных Соколов информатика Сидоров программирование Федоров
Если попытаться объединить (а также пересечь или получить разность) столбцы несовместимых типов, возникнет ошибка. Oracle при это выдает сообщение:
SELECT Fund from FACULTY
UNION
SELECT Head FROM DEPARTMENT:
SELECT Fund from FACULTY *
Ошибка в строке 1:
0RA-01790: выражение должно иметь тот же тип данных, что и соответствующее выражение
Идентификация строк
При объединении (а также пересечении и разности) данных из различных таблиц иногда желательно вывести сведения о том, из какой таблицы эти данные получены. Этого можно легко добиться — нужно только добавить в список при фразе SELECT столбец, значениями которого будут строковые литералы, указывающие источник.
Запрос. Вывести названия факультетов и кафедр, имеющих фонд финансирования больше 25 000.
SELECT 'Факультет:' "Структура”, Name "Название", Fund "Фонд"
FROM FACULTY
WHERE Fund > 25000
UNION
SELECT 'Кафедра:' "Структура", Name "Название", Fund "Фонд"
FROM DEPARTMENT
WHERE Fund > 25000:
Структура Название Фонд
Кафедра:базы данных 26000
Кафедра:базы данных 27000
Факультет: кибернетика 27000
Запрос. Вывести фамилии преподавателей с указанием категории их зарплаты (0-500 — низкая, 500-1000 — средняя, 1000-1500 — высокая, 1500 и более — очень высокая).
SELECT Name "Фамилия", 'низкая* "Категория зарплаты"
FROM TEACHER WHERE Salary + UNION
SELECT Name, 'средняя'
FROM TEACHER WHERE Salary +
UNION
SELECT Name, 'высокая'
FROM TEACHER WHERE Salary + UNION
SELECT Name, 'очень высокая*
FROM TEACHER WHERE Salary +
Rise <= 500
Rise > 500 AND Salary + Rise <= 1000
Rise > 1000 AND Salary + Rise <» 1500
Rise > 1500;
Фамилия Категория зарплаты
Ахромеев очень высокая
Вибровский средняя
Воропаев средняя
Дараганов средняя
Завратинский высокая
Козлутин средняя
Кузинцев средняя
Лекарь высокая
Мартынов средняя
Наумов высокая
Недеведеев средняя
Рамишевский высокая
Резван очень высокая
Сидоров очень высокая
Хоренко средняя
Внешнее объединение
Как вы уже знаете, внешнее соединение позволяет включать в результат все строки одной или обеих соединяемых таблиц, даже если для этих строк не выполняется условие соединения. Такой же результат можно получить и с помощью операции объединения.
Часто бывает полезным такое объединение двух и более запросов, в котором второй запрос (и возможные последующие запросы) добавляет в результат строки, которые не были отобраны из базовых таблиц первым запросом. Такое объединение называется внешним. Отметим, что объединение можно назвать внешним, только если оно возвращает все значения одного из столбцов. Подробно рассмотрим пример.
Запрос. Показать фамилии кураторов групп.
SELECT SGROUP.Num Труппа", TEACHER.Name "Куратор" FROM SGROUP, TEACHER
WHERE SGROUP.CurFK = TEACHER.TchPK;
Группа Куратор
307 Кузинцев
408 Кузинцев
504 Завратинский
505 Лекарь
Теперь предположим, что некоторые из групп кураторов не имеют, а также что не все преподаватели являются кураторами. В результирующей таблице такие группы (в столбце Num) и преподаватели (в столбце Name) не представлены. Однако нам хотелось бы, чтобы были перечислены все группы, независимо от того, есть ли у них куратор, и все преподаватели, независимо от того, являются ли они кураторами. Для этого можно использовать или полное внешнее соединение, рассмотренное в уроке 4, или сочетание внутреннего соединения и объединения. Во втором случае необходимый результат достигается с помощью трех запросов, возвращающих соответствующие наборы строк, и их последующего объединения. Покажем внешнее объединение, возвращающее номера всех групп:
SELECT SGROUP.Num 'Труппа". TEACHER.Name "Куратор" FROM SGROUP, TEACHER
WHERE SGROUP.CurFK - TEACHER.TchPK
UNION
SELECT SGROUP.Num. NULL
FROM SGROUP
WHERE SGROUP.CurFK IS NULL OR
NOT SGROUP.CurFK =ANY (SELECT TchPK FROM TEACHER);
Группа Куратор
201
307 Кузинцев
408 Кузинцев
504 Завратинский
505 Лекарь
Теперь результат содержит группу 201, не имеющую куратора, — эта строка добавлена вторым запросом. Группа добавляется в двух случаях:
О в группе номер куратора равен NULL (CurFK IS NULL) - то есть куратора нет;
О в группе номер куратора не равен NULL, но для указанного номера куратора отсутствует соответствующий номер преподавателя в таблице TEACHER (для правильно спроектированной базы данных такого не может быть — например, в учебной базе данных CurFK является внешним ключом).
Обратите внимание, что здесь мы впервые использовали константу NULL для указания значения. Такое редко встречается в языке запросов, но довольно часто используется в языке манипулирования, о котором пойдет речь в уроке 11. В нашем случае вместо константы NULL можно было бы использовать любую строковую константу, например 'Отсутствует'.
Для построения внешнего объединения, которое выводило бы список всех преподавателей, следует записать:
SELECT SGROUP.Num Труппа", TEACHER.Name "Куратор"
FROM SGROUP, TEACHER
WHERE SGROUP.CurFK = TEACHER.TchPK
UNION
SELECT CASTCNULL AS INTEGER), TEACHER.Name
FROM TEACHER
WHERE TEACHER.TchPK IS NULL OR
NOT TEACHER.TchPK =ANY (SELECT CurFK FROM SGROUP):
Группа Куратор
307 Кузинцев
408 Кузинцев
504 Завратинский
505 Лекарь
Сидоров
Рамишевский
Хоренко
Вибровский
Воропаев
Козлутин
Мартынов
Резван
Недеведеев
Ахромеев
Наумов
Дараганов
Здесь второй запрос представляет собой симметричную замену таблиц SGROUP на TEACHER по сравнению с предыдущим примером. Обратите внимание, что в нашем случае условие TEACHER.TchPK IS NULL является излишним, так как первичный ключ не может принимать неопределенного значения. Однако если соединение производится не по столбцам первичный/внешний ключ, это условие необходимо.
Чтобы получить полные списки - и групп и преподавателей, нужно объединить оба примера. В этом случае говорят, что произведено полное внешнее объединение.
Объединение с сохранением дублирования
Для вывода дублированных строк результата объединения следует воспользоваться оператором UNION ALL.
Запрос. Вывести названия кафедр факультетов информатики и кибернетики с учетом возможного повторения их названий.
SELECT d.Name
FROM DEPARTMENT d, FACULTY f
WHERE d.FacFK = f.FacPK AND LOWER(f.Name) = 'информатика*
UNION ALL
SELECT d.Name
FROM DEPARTMENT d, FACULTY f
WHERE d.FacFK - f.FacPK AND LOWERCf.Name) - 'кибернетика*:
NAME
базы данных
программирование
интернет
теория языков лингвистика базы данных
Обратите внимание, что в списке присутствуют две кафедры баз данных. Если бы мы воспользовались оператором UNION, то потеряли бы важную информацию о том, что имеются кафедры с одинаковыми названиями.
Отметим, что если запрос должен содержать несколько операторов UNION (или UNION ALL), то не нужно следить за порядком объединения запросов, так как этот оператор обладает коммутативным и ассоциативным свойствами, то есть:
запрос_1 UNION запрос_2 - запрос_2 UNION запрос_1
(запрос_1 UNION запрос_2) UNION запрос_3 = запрос_1 UNION (запрос_2 UNION запрос_3)
Однако при совместном использовании операторов UNION и UNION ALL за порядком вычисления нужно следить, так как они не обладают взаимной ассоциативностью. То есть выражение:■
(запрос_1 UNION ALL запрос_2) UNION запрос_3
не обязательно приведет к тем же результатам, что и запрос:
запрос_1 UNION ALL (запрос^ UNION запрос_3)
Замена оператора UNION оператором OR
Если необходимо объединить две или более таблиц, полученных в результате выполнения запросов над одними и теми же таблицами с выбором одних и тех же столбцов, но с разными условиями отбора строк, это можно выразить в виде одного запроса, в котором условие выбора строк равно объединению условий исходных запросов логической связкой OR. Приводимые далее два примера запроса являются эквивалентными.
Запрос. Вывести названия кафедр факультетов информатики и кибернетики, которые располагаются в корпусе 3.
SELECT d.Name
FROM DEPARTMENT d. FACULTY f-
WHERE d.FacFK = f.FacPK AND LOWERCf.Name) = 'информатика' AND d.Building = *3'
UNION ALL
SELECT d.Name
FROM DEPARTMENT d, FACULTY f
WHERE d.FacFK = f.FacPK AND LOWERCf.Name) = 'кибернетика' AND d.Building = '3';
SELECT d.Name
FROM DEPARTMENT d. FACULTY f
WHERE d.FacFK = f.FacPK AND
((LOWER(f.Name) - 'информатика* AND d.Building = *3') OR (LOWER(f.Name) - 'кибернетика* AND d.Building - '3')):
NAME
интернет теория языков лингвистика
Пересечение таблиц
В результирующей таблице оператора INTERSECT содержатся только те строки, которые имеются в обеих исходных таблицах. Исходные таблицы задаются запросами, выступающими в качестве операндов этого оператора.
Запрос. Вывести факультеты, которые имеют кафедры с фондами финансирования больше 26 000 и меньше 15 000.
SELECT f.Name
FROM FACULTY f, DEPARTMENT d
WHERE f.FacPK = d.FacFK AND d.Fund < 15000
INTERSECT
SELECT f.Name
FROM FACULTY f, DEPARTMENT d
WHERE f.FacPK = d.FacFK AND d.Fund > 26000;
NAME
кибернетика
Запрос. Вывести названия кафедр, на которых работают профессора и доценты.
SELECT d.Name
FROM DEPARTMENT d. TEACHER t
WHERE d.DepPK - t.DepFK AND LOWER(t.Post) = ’профессор’
INTERSECT
SELECT d.Name
FROM DEPARTMENT d. TEACHER t
WHERE d.DepPK = t.DepFK AND LOWER(t.Post) = ’доцент’;
NAME
программирование
Замена оператора INTERSECT оператором IN
Как вы уже смогли заметить, SQL является избыточным в том смысле, что одни и те же запросы могут выражаться с использованием различных операторов. В частности, оператор INTERSECT может быть выражен через сочетание операторов AND и IN. Далее приводятся несколько вариантов формулировки одного запроса — один с использованием оператора INTERSECT и три с использованием оператора IN.
Запрос. Вывести номера групп, которым читают лекции как Хоренко, так и Лекарь.
SELECT g.Num
FROM SGROUP g, LECTURE 1. TEACHER t
WHERE g.GrpPK = l.GrpFK AND l.TchFK = t.TchPK AND UPPER(t.Name) = 'XOPEHKO'
INTERSECT
SELECT g.Num
FROM SGROUP g. LECTURE 1, TEACHER t
WHERE g.GrpPK = l.GrpFK AND l.TchFK = t.TchPK AND UPPER(t.Name) = 'ЛЕКАРЬ':
SELECT DISTINCT g.Num
FROM SGROUP g. LECTURE 1, TEACHER t
WHERE g.GrpPK = l.GrpFK AND l.TchFK - t.TchPK AND UPPER(t.Name) - 'XOPEHKO' AND g.Num IN (SELECT g.Num
FROM SGROUP g. LECTURE 1, TEACHER t
WHERE g.GrpPK = l.GrpFK AND l.TchFK = t.TchPK AND UPPER(t.Name) = 'ЛЕКАРЬ*):
SELECT DISTINCT Num
FROM SGROUP
WHERE Num IN (SELECT g.Num
FROM SGROUP g. LECTURE 1, TEACHER t
WHERE g.GrpPK = l.GrpFK AND l.TchFK = t.TchPK AND
UPPER(t.Name) = 'XOPEHKO' AND
Num IN (SELECT g.Num
FROM SGROUP g, LECTURE 1, TEACHER t
WHERE g.GrpPK = l.GrpFK AND l.TchFK = t.TchPK AND UPPER(t.Name) = 'ЛЕКАРЬ')):
SELECT Num
FROM SGROUP
WHERE Num IN (SELECT g.Num
FROM SGROUP g. LECTURE 1. TEACHER t
WHERE g.GrpPK = 1.GrpFK AND 1.TchFK = t.TchPK AND
(UPPER(t.Name) = 'XOPEHKO' OR UPPER(t.Name) = 'ЛЕКАРЬ')); NUM
505
Разность таблиц
Результирующая таблица оператора MINUS содержит только те строки, которые имеются в первой из исходных таблиц, но не имеются во второй. Исходные таблицы задаются запросами, выступающими в качестве операндов этого оператора. Запрос. Вывести фамилии преподавателей, читающих лекции по дисциплине «базы данных», но не читающих лекции по дисциплине «операционные системы».
SELECT t.Name
FROM TEACHER t, LECTURE 1, SUBJECT s
WHERE t.TchPK = 1.TchFK AND 1.SbjFK = s.SbjPK AND LOWER(s.Name) = 'базы данных'
MINUS
SELECT t.Name
FROM TEACHER t. LECTURE 1, SUBJECT s
WHERE t.TchPK - 1.TchFK AND 1.SbjFK = s.SbjPK AND LOWER(s.Name) = 'операционные системы':
NAME
Кузинцев
Мартынов
Запрос. Вывести факультеты, на которых есть кафедра баз данных, но нет кафедры программирования.
SELECT F.Name
FROM FACULTY f, DEPARTMENT d
WHERE f.FacPK = d.FacFK AND LOWER(d.Name) = 'базы данных'
MINUS
SELECT F.Name
FROM FACULTY f, DEPARTMENT d
WHERE f.FacPK = d.FacFK AND LOWER(d.Name) = 'программирование':
NAME
кибернетика
Замена оператора MINUS оператором NOT IN
Оператор MINUS может быть выражен сочетанием предикатов NOT IN и AND. Далее приводятся два эквивалентных варианта одного запроса.
Запрос. Вывести фамилии деканов факультетов, которые не являются заведующими кафедрами.
SELECT Dean
FROM FACULTY
MINUS
SELECT Head
FROM DEPARTMENT:
SELECT Dean
FROM FACULTY
WHERE Dean NOT IN (SELECT Head FROM DEPARTMENT):
DEAN
Сидоров'
Петров
Игнатов
Дополнительные аспекты использования множественных операций
Есть ряд вопросов, которые касаются всех множественных операций в целом. Это, в частности, применение к ним группировки, использование вместе с ними сортировки, порядок выполнения множественных операций и, наконец, критерии использования множественной операции. Эти вопросы и рассматриваются далее.
Множественные операции и группировка
К запросам, выступающим в качестве операндов множественных операторов, может применяться группировка. При этом никакие ограничения не накладываются.
Запрос. Вывести названия кафедр, у которых либо фонд финансирования больше 25 000, либо зарплата преподавателей больше 10 000.
SELECT d.Name AS ’’Кафедра”, 'Зарплата кафедры > 10000’ AS ’’Условие выбора”
FROM DEPARTMENT d, TEACHER t
WHERE d.DepPK = t.DepFK
GROUP BY d.Name
HAVING SUMCSalary + Rise ) > 10000
UNION ALL
SELECT d.Name, 'Фонд кафедры > 25000'
FROM DEPARTMENT d
WHERE d.Fund > 25000:
КафедраУсловие выбора
программирование Зарплата кафедры > 10000
базы данныхФонд кафедры > 25000
базы данныхФонд кафедры > 25000
Множественные операции и сортировка
Результаты выполнения подзапросов, выступающих в качестве операндов множественных операций, упорядочивать запрещено. Да и нет смысла это делать, так как они представляют лишь промежуточные результаты, которые пользователь не увидит. Однако результат выполнения множественной операции можно отсортировать, расположив в конце запроса фразу ORDER BY. Так как не понятно, какие имена получают столбцы результирующей таблицы, следует ссылаться на них по порядковым номерам.
Запрос. Указать количество принятых на работу преподавателей за 1995-2000 и 2000-2005 годы по различным факультетам.
SELECT f.Name» 'в 1995-2000 г. *, COUNTC*),'принято на работу'
FROM FACULTY f, DEPARTMENT d, TEACHER t
WHERE f.FacPK = d.FacFK AND d.DepPK = t.DepFK AND
Hiredate BETWEEN DATE '1995-01-01' AND DATE '2000-12-31*
GROUP BY f.Name
UNION ALL
SELECT f.Name, 'в 2000-2005 г. ', COUNTC*),'принято на работу'
FROM FACULTY f, DEPARTMENT d, TEACHER t
WHERE f.FacPK = d.FacFK AND d.DepPK = t.DepFK AND
Hiredate BETWEEN DATE '2000-01-0Г AND DATE '2005-12-31'
GROUP BY f.Name
ORDER BY 1;
NAME'В1995-2000Г.' COUNTC*) 'ПРИНЯТОНАРАБОТУ'
6 принято на работу4 принято на работу6 принято на работу4 принято на работуинформатика в 2000-2005 г.
6 принято на работу
4 принято на работу
6 принято на работу
4 принято на работу
информатика в 1995-2000 г.
Обратите внимание, что стоящая в конце фраза ORDER BY относится не ко второму подзапросу, а ко всему запросу. Точно так же применяется фраза ORDER BY и с другими множественными операторами.
Запрос. Вывести фамилии преподавателей, ведущих занятия и на 1-й, и на 2-й неделях. Результат упорядочить по фамилиям.
SELECT t.Name
FROM TEACHER t. LECTURE 1
WHERE t.TchPK - l.TchFK AND l.Week = 1
INTERSECT
SELECT t.Name
FROM TEACHER t. LECTURE 1
WHERE t.TchPK = l.TchFK AND l.Week = 2
ORDER BY 1;
NAME
Вибровский
Воропаев
Кузинцев
Лекарь
Мартынов
Недеведеев
Рамишевский
Резван
Хоренко
Порядок выполнения множественных операций
Можно строить запрос, содержащий несколько одинаковых или различных множественных операций. В этом случае множественные операторы выполняются последовательно слева направо. Если необходимо определить порядок выполнения, следует воспользоваться скобками.
Мы уже обращали внимание на то, что операторы UNION и UNION ALL не обладают взаимной ассоциативностью. То же самое имеет место для пар операторов INERSECT и INTERSECT ALL, EXCEPT и EXCEPT ALL. Каждый из них является ассоциативным, но не между собой. Поэтому будьте внимательными и при необходимости расставляйте скобки.
Критерии использования множественных операций
Наиболее часто встречающаяся ошибка — использование оператора AND вместо INTERSECT и оператора AND NOT вместо MINUS. Это объясняется прежде всего тем, что в русском языке логическая связка «и» употребляется для обозначения действия как оператора AND, так и оператора INTERSECT. Аналогичная ситуация существует по отношению к связкам «и не» («но не») и операторов AND NOT и MINUS. Чтобы различать употребление этих логических связок и операторов, обращайте внимание на следующее. Если при содержательной формулировке запроса в его условии используется связка «или» (и связка «и» в значении «или») — это выражается с помощью операторов OR или UNION. Если же используется связка «и», следует различать, к чему она применяется. Если к различным столбцам — нужно
использовать оператор AND, а если к одному — оператор INTERSECT (за исключением случая, когда связка «и» означает «между» или «в интервале»). Рассмотрим примеры.
О «Должность профессор и зарплата больше 1000» — используется оператор AND, так как условие задается на разных столбцах:
post = 'профессор' AND Salary + Rise > 1000
О «Ставка больше 500 и меньше 1000» — несмотря на то, что условия задаются на одном и том же столбце, используется оператор AND, так как условия определяют интервал значений:
Salary > 500 AND Salary < 1000
О «Ставка больше 1500 и меньше 1000» — используется оператор INTERSECT:
SELECT... FROM... WHERE Salary > 1500 INTERSECT
SELECT... FROM... WHERE Salary < 1000
О «Иванов и Петров» — так как условие задано на одном и том же столбце и не в смысле интервала значений используется оператор INTERSECT.-
SELECT... FROM... WHERE Name = 'Иванов'
INTERSECT
SELECT... FROM... WHERE Name = 'Петров'
Если при содержательной формулировке запроса в его условии используется связка «и не» («но не»), то, как и в предыдущем случае, следует различать две ситуации. Если она применяется к различным столбцам, нужно использовать предикат AND NOT, а если к одному — оператор MINUS (за исключением случая, когда «и не» («но не») имеет смысл «между» или «в интервале»). Рассмотрим примеры. О «Должность профессор и зарплата не больше 1000» — используется оператор
AND NOT, так как условия заданы на различных столбцах:
post = 'профессор' AND NOT Salary + Rise > 1000
О «Ставка меньше 500 и не меньше 400» — несмотря на то, что условия заданы на одном столбце, используется оператор AND NOT, так как условия определяют интервал:
Salary < 500 AND NOT Salary < 400
О «Иванов, но не Петров» — так как условие задано на одном столбце и не в смысле интервала значений используется оператор MINUS:
SELECT... FROM... WHERE Name = 'Иванов'
MINUS
SELECT... FROM... WHERE Name = 'Петров'
Самостоятельная работа
Вывести список номеров всех корпусов, которые имеются в таблицах факультетов, кафедр и аудиторий.
Вывести список фамилий всех преподавателей, учитывая, что деканы факультетов и заведующие кафедрами также являются преподавателями.
Вывести номера групп со следующим указанием оценки их рейтинга в отдельном столбце: 0-30 — «низкий», 31-50 - «средний», 51-80 — «высокий», 81-100 - «очень высокий».
Произведите полное внешнее объединение таблиц кафедр и преподавателей с выводом в результирующей таблице названий кафедр и фамилий преподавателей.
Вывести дни недели (с повторяющимися значениями), в которые имеются занятия в аудиториях 311 и 104 корпуса 6.
Вывести фамилии профессоров или доцентов. Сделать это двумя способами: через оператор UNION и с использованием логической связки 0R.
Вывести фамилии преподавателей, которые ведут занятия как в аудитории 311, так и в аудитории 104 корпуса 6. Сделайте это двумя способами: с помощью оператора INTERSECT и с помощью предиката IN.
Вывести фамилии преподавателей, которые проводят занятия во вторник, но не проводят в пятницу. Сделайте это двумя способами: с помощью оператора MINUS и с помощью предиката NOT IN. Чтобы убедиться в правильности полученного результата, сначала выведите два отдельных списка — фамилий преподавателей, ведущих занятия во вторник, и фамилий преподавателей, ведущих занятия в пятницу.
Выведите в одном столбце суммарную зарплату преподавателей всех факультетов и суммарную зарплату преподавателей всех кафедр.
Вывести фамилии и должности преподавателей, имеющих занятия на 3-й и 4-й парах. Результат упорядочить по убыванию должности и по возрастанию фамилий.
Подведение итогов
Усвоив материал этого урока, вы научились:
0 формулировать запросы с объединением таблиц;
0 идентифицировать строки объединяемых таблиц;
0 производить внешнее объединение;
0 сохранять дублирование при объединении;
0 формулировать запросы с пересечением таблиц;
0 формулировать запросы, выражающие разность таблиц;
0 выражать множественные операции через другие операции и предикаты;
0 сортировать результаты множественных операций;
0 определять ситуации, когда следует применять множественные операции.
ЩУРОКЩУРОКРазвитые возможности SQLРазвитые возможности SQL
ЩУРОК
ЩУРОК
Развитые возможности SQL
Развитые возможности SQL
Наличие значений NULL выводит логику баз данных за пределы обычно двузначной математической логики. Здесь уже нужна трехзначная логика, которая оперирует еще одним истинностным значением, позволяющим адекватно оперировать неопределенными значениями типа NULL. Первый раздел этого урока как раз посвящен объяснению трехзначной логики в базах данных, поддерживающих SQL, а также в нем подытоживается интерпретация неопределенных значений в языке. Следующий раздел посвящен очень важному расширению языка, которое появилось в стандарте SQL3 (SQL-1999), а именно — возможности строить рекурсивные запросы, которая охватывает целый класс задач, не решаемых иным путем. Наконец, в третьем разделе описываются возможности* языка по аналитической обработке данных, а именно по многомерному анализу данных.
Использование неопределенных значений
В данном разделе мы подытоживаем использование неопределенных значений в SQL. Если столбец в строке не имеет значения, говорят, что его значение равно NULL или значение содержит NULL. Значение NULL может содержаться в столбцах любых типов, если, конечно, при определении таблицы не было указано, что такой столбец должен быть NOT NULL или что он является PRIMARY KEY. Используйте значение NULL, когда фактическое значение столбца не известно или когда значение, которое следует ввести, является бессмысленным.
Далее мы опишем использование NULL в стандарте SQL. Большинство развитых СУБД поддерживают NULL согласно этому стандарту.
NULL в арифметических выражениях
Любые арифметические выражения, содержащие NULL, всегда дают в результате NULL. Например, NULL + 10 дает NULL. По сути, все операторы (за исключением конкатенации строк) возвращают значение NULL, если один из операндов равен NULL.
NULL в операторах сравнения
Для проверки на наличие неопределенного значения используйте только операторы сравнения IS NULL или IS NOT NULL. При использовании любого другого оператора сравнения, если любой из его аргументов принимает значение NULL, результатом будет логическое значение UNKNOWN (о трехзначной логике см. далее).
Так как NULL означает отсутствие данных, NULL не может быть равным или неравным любому другому значению и даже самому значению NULL. Приведем несколько примеров:
если А равното условие
10А = NULL
дает значение
UNKNOWN
10А <> NULL
UNKNOWN
NULLА = NULL
UNKNOWN
NULLА <> NULL
UNKNOWN
NULLА = 10
UNKNOWN
NULLА <> 10
UNKNOWN
Такая логическая трактовка неопределенных значений не совсем корректна, потому что она может приводить к неожиданным результатам. Например, можно было бы ожидать, что условие А = 10 OR А <> 10 приводит к выводу всех строк соответствующей таблицы. Однако это не так — на тех строках, где значение столбца А равно NULL (то есть оно не определено), выражение сравнения А = 10 дает UNKNOWN, выражение А <> 10 также дает UNKNOWN, наконец, выражение А = 10 OR А <> 10 также дает UNKNOWN (см. таблицы истинности для логических связок далее). В связи с этим строки с неопределенными значениями столбца А не будут выбраны (вспомним, что выбираются только те строки, на которых логическое выражение равно TRUE).
Логическое значение UNKNOWN иногда действуют как FALSE, например, когда принимается решение о выборе строки в результирующую таблицу. Однако логическое значение UNKNOWN, отличается от FALSE, когда к ним применяются логические связки AND, OR, NOT. Например, NOT FALSE дает TRUE, a NOT UNKNOWN дает UNKNOWN. Если необходимо в условии явно учитывать неопределенные значения, следует использовать операторы IS NULL и IS NOT NULL. Приведем примеры использования этих функций:
если А равно
то условие
дает значение
10
A IS NULL
FALSE
10
A IS NOT NULL
TRUE
NULL
A IS NULL
TRUE
NULL
A IS NOT NULL
FALSE
Таким образом, если вы не хотите, чтобы строки с неопределенными значениями участвовали в условии фразы WHERE (или любом другом месте, где язык допускает использование условия), то формулируйте так, как если бы в таблицах такие неопределенные значения отсутствовали. Однако если такие строки следует учитывать, применяйте операторы IS NULL и IS NOT NULL. Например, для выбора строк, у которых значение столбца А равно 10, следует записать А = 10. Если же требуется выбрать строки с А равным 10, включая и те, у которых значение этого столбца не
определено, следует записать А = 10 OR A IS NULL. Наконец, если требуется выбрать только строки с неопределенными значениями столбца А, следует записать A IS NULL.
NULL в логических связках
В связи с введением логического значения UNKNOWN логика становится трехзначной (в дополнение к логическим значениям TRUE и FALSE). Поэтому расширяются таблицы истинности для логических связок AND, OR и NOT. Они приведены ниже.
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
NOT
TRUE
FALSE
UNKNOWN
FALSE
TRUE
UNKNOWN
NULL в функциях
Скалярные функции, за исключением специальных, возвращают NULL, если аргумент равен NULL. Агрегатные функции MIN, MAX, AVG, SUM игнорируют NULL. Например, если столбец Salary имеет следующие пять значений: 1000, NULL, NULL, NULL, 2000, то функция AVG(Salary) вернет (1000 + 2000) / 2 = 1500. Если запрос с агрегатной функцией не возвращает строк или все строки имеют значения NULL для аргумента агрегатной функции, агрегатная функция возвращает значение NULL.
Функция COUNT по-разному воспринимает неопределенное значение в зависимости от аргумента. Если аргумент имеет вид *, функция подсчитывает все строки, полученные в результате вычисления запроса, включая повторяющиеся и с неопределенными значениями. Если в качестве аргумента задано выражение (в простейшем случае это имя столбца), то подсчитываются строки, в которых выражение аргумента не равно NULL.
Когда значения NULL рассматриваются равными
Итак, общий механизм трактовки значений NULL таков: два значения NULL не рассматриваются равными, то есть значением выражения NULL = NULL будет UNKNOWN, а не TRUE. Однако в некоторых случаях в тех или иных СУБД два NULL рассматриваются как равные. Опишем такие случаи для Oracle:
О в составных ключах (то есть ключах, состоящих из нескольких столбцов); это означает, что Oracle рассматривает идентичными два составных ключа с неопределенными значениями некоторых столбцов, если все компоненты этих ключей, которые не равны NULL, совпадают;
О при исключении дубликатов; фраза SELECT DISTINCT даст в результате не более одного значения NULL.
Вывод значений NULL на экран и печать
Как правило, при выводе строк таблицы, удовлетворяющих запросу, неопределенные значения выводятся в виде пробелов независимо от типа данных. В некоторых СУБД имеются установки параметров, которые позволяют указать способ воспроизведения неопределенных значений при выводе на экран или печать.
Функции работы с NULL
Стандарт SQL предлагает две функции для оперирования неопределенными значениями: COALESCE и NULL IF, которые описаны в предыдущем уроке. Первая из них позволяет преобразовать NULL в значение определенного типа, а вторая, наоборот, преобразовать значение в NULL.
NULL при сортировке
При сортировке значений по умолчанию предполагается, что NULL больше любого значения. Это один из немногих случаев, когда предполагается, что NULL сравним с обычным значением.
Рекурсивное вычисление запросов
Рекурсивными называются запросы, когда для получения необходимого значения (или даже целой таблицы) следует многократно использовать одну и ту же таблицу, причем количество обращений к такой таблице, как правило, заранее не известно. В этом разделе мы сначала дадим основные понятия о специальной структуре данных, деревьях, которые используются в рекурсивных вычислениях, затем приведем примеры содержательных запросов, которые требуют рекурсивных вычислений, покажем, как можно выразить некоторые из рекурсивных запросов с помощью обычных средств SQL, и наконец, представим специальные расширения языка для описания вычислений, не имеющих заранее заданной глубины рекурсивной вложенности.
Древовидные структуры
Графы — структуры данных, состоящие из вершин (узлов), связанных дугами. Дерево — специальный вид направленного графа, у которого дуги показывают однонаправленную связь между двумя вершинами (то есть дуги направленные; как правило, на схемах это представляется в виде дуг со стрелкой в конце дуги), причем никакая вершина не может иметь двух входящих в нее дуг. Древовидные структуры широко распространены. Например, в диаграмме организационной структуры подчинения вершины представляют сотрудников, а каждая дуга описывает подчиненность нижестоящего сотрудника (того, к которому ведет стрелка дуги) вышестоящему. В перечне компоновки агрегатов из других агрега- тов/деталей вершинами являются агрегаты/детали, а дуги описывают отношение
«состоит из». В дереве родословной вершины представляют людей, а дуги — связь «является ребенком».
Вершина дерева называется корнем. В организационной диаграмме это главный руководитель, а в компоновке агрегатов это собранный агрегат, который имеет непосредственное применение. Дуга связывает две вершины, причем первая из них (из которой исходит дуга) называется непосредственным предком (родительская вершина), а вторая — непосредственным потомком (дочерняя вершина). Вершина дерева называется конечной (листьевой), если у нее нет вершины-потомка. В организационной структуре листьями являются те сотрудники, которые не имеют подчиненных, а в компоновке агрегатов - детали, которые не имеют внутренней компоновки. Относительно любой вершины можно говорить о множестве всех ее предков (если эта вершина не корневая) и о множестве всех ее потомков, если она не конечная. Две вершины называются подобными, если у них один и тот же непосредственный предок. В организационной структуре подобными являются сотрудники одного начальника.
Если выбирается некоторая некорневая вершина дерева вместе со всеми ее потомками, такое дерево называется поддеревом. Говорят, что вершина, определяющая поддерево, является корнем поддерева. Двоичное дерево — это дерево, в котором вершина может иметь не более двух потомков. В общем случае п-мерное дерево - то, в котором вершина может иметь не больше чем п вершин-потомков.
Деревья часто изображают в виде диаграмм, как это показано на рис. 10.1 и 10.2. Древовидная структура распределяет вершины по уровням. Корневая вершина представляет первый уровень. Все вершины, дочерние корневой, представляют второй уровень и т. д.
Рис. 10.2. Представление древовидной структуры в виде вложенных множеств
Представление деревьев и манипулирование ими
В SQL любые связи явно описываются данными. Типичный способ представления деревьев состоит в том, чтобы поместить дуги между вершинами в таблицу.
То есть один столбец — родительский узел, другой столбец в той же самой строке — дочерний узел (пара представляет собой дугу в графе). Например, в нашей учебной базе данных таблица TEACHER помимо первичного ключа TchPK, который уникально идентифицирует строки таблицы (то есть преподавателей), имеется внешний ключ Chief, который является ссылкой на руководителя данного преподавателя.
Чтобы для каждого руководителя получить фамилии его непосредственных подчиненных, следует использовать самосоединяющийся запрос типа:
SELECT mgr.Name AS "Руководитель". tch.Name AS "Подчиненный"
FROM TEACHER tch. TEACHER mgr
WHERE tch.Chief = mgr.TchPK
ORDER BY mgr.Name;
Руководитель Подчиненный
ЗавратинскийКозлутин
КузинцевМартынов
ЛекарьНедеведеев
РамишевскийХоренко
РамишевскийВоропаев
РамишевскийКузинцев
СидоровРамишевский
СидоровЗавратинский
СидоровЛекарь
СидоровРезван
ХоренкоВибровский
Этот запрос выдает фамилии только непосредственных подчиненных. Однако подчиненные ваших подчиненных также подчинены вам и так далее вниз по дереву. Чтобы вывести сведения по вершинам через уровень в дереве, необходимо написать более сложный запрос с троекратным объединением таблицы, как это продемонстрировано ниже.
SELECT mgr.Name AS "Руководитель", tch.Name AS "Подчиненный 2 уровня"
FROM TEACHER tch, TEACHER mid, TEACHER mgr
WHERE tch.Chief = mid.TchPK AND mid.Chief = mgr.TchPK
ORDER BY mgr.Name;
Руководитель
Подчиненный 2 уровня
Рамишевский Рамишевский Сидоров Сидоров Сидоров Сидоров Сидоров
Вибровский Мартынов Хоренко Воропаев Недеведеев Кузинцев Козлутин
К сожалению, вы не можете знать, насколько глубоко дерево, так что для получения полной структуры подчинения необходимо продолжать расширять этот запрос аналогичным образом, пока не получите в результате пустое множество. Понятно, такое решение по нахождению дочерних вершин любого уровня в древовидной структуре не является удовлетворительным. Тем не менее, некоторые из элементов дерева могут эффективно отыскиваться. Так, например, можно легко
находить вершины-листья, то есть такие, которые не имеют потомков. В нашем случае это преподаватели, не имеющие подчиненных. Вот как они находятся:
SELECT tl.Name AS "Вершины-листья"
FROM TEACHER tl
WHERE NOT EXISTS (SELECT *
FROM TEACHER t2
WHERE t2.Chief = tl.TchPK);
Вершины-листья
Вибровский
Воропаев
Козлутин
Мартынов
Резван
Недеведеев
Ахромеев
Наумов
Дараганов
А как найти корень дерева, то есть главного руководителя? Ответ на этот запрос зависит от того, какое значение столбца Chief хранится для корня дерева, то есть для того сотрудника, у которого нет руководителя. Возможны два варианта: хранить в этом столбце значение столбца TchPK (что, как мы увидим далее, не самый лучший вариант), то есть тем самым указать, что этот сотрудник является сам своим руководителем, и второй - хранить в этом столбце значение NULL. В первом случае для получения корня дерева следует записать:
SELECT Name FROM TEACHER WHERE TchPK = Chief;
а во втором:
SELECT Name FROM TEACHER WHERE Chief IS NULL;
Итак, можно констатировать, что теми средствами SQL, которые мы до сих пор изучили, невозможно выразить запросы, производящие поиск и вычисления в деревьях на произвольную глубину вложенности.
Рекурсивные запросы в Oracle
В Oracle существует свой собственный механизм рекурсивного вычисления запросов, который мы опишем в этом разделе. В следующем разделе мы представим подход рекурсивного вычисления запросов, принятый в стандарте SQL.
Если таблица имеет древовидную структуру, то рекурсивное вычисление с произвольной глубиной вложенности поддерживается с помощью следующих трех фраз предложения SELECT:
О START WITH — указывает ту вершину или вершины дерева, которые являются начальными для организации рекурсивного вычисления;
О CONNECT BY - указывает, каким образом связаны между собой родительские и дочерние вершины (строки); в простейшем случае указывает, какие именно столбцы используются для установления этих связей;
О WHERE — стандартная фраза предложения SELECT, которая ограничивает выводимые строки таблицы без какого-либо воздействия на древовидную структуру строк в таблице.
Эта информация используется для организации следующей процедуры рекурсивного вычисления запроса.
Если во фразе WHERE присутствует предикат соединения двух или нескольких таблиц, такое соединение производится в первую очередь.
Производится отбор тех строк таблицы, которые удовлетворяют условию фразы START WITH. Эти строки рассматриваются как корневые для последующего рекурсивного вычисления.
По каждой таким образом определенной корневой строке производится поиск ее дочерних строк. Дочерние вершины определяются согласно условию, заданному во фразе CONNECT BY.
Затем производится поиск последующих поколений дочерних строк. Для этого выбираются дочерние строки тех строк, которые были найдены на шаге 2, затем дочерние строки этих дочерних строк и так далее до трех пор, пока не будут достигнуты строки-листья. При этом на каждом шаге поиск следующих дочерних строк производится согласно условию фразы CONNECT BY и текущая строка рассматривается, как если бы она была корневая.
Если запрос содержит фразу WHERE, в которой имеются предикаты отбора строк, то устраняются строки, не удовлетворяющие условию этой фразы. При этом условие вычисляется для каждой строки индивидуально. Это означает, что не производится удаление дочерних строк той строки, которая не удовлетворяет условию этой фразы.
Полученные в результате рекурсивного вычисления строки выдаются в порядке, приведенном на рис. 10.3. На этой диаграмме дочерние вершины расположены под своими родительскими вершинами. Таким образом, упорядоченность определяется правилом обхода дерева сверху-вниз и слева-направо. Эта упорядоченность вывода строк может меняться фразой ORDER BY.
Рис. 10.3. Стандартный порядок вывода строк таблицы при рекурсивном вычислении запроса
Рассмотрим вкратце фразы, которые используются в рекурсивных запросах.
Фраза START WITH
Фраза START WITH позволяет указать то поддерево всего иерархического дерева, которое будет участвовать в рекурсивном запросе. Это определяется заданием условия, которому должны удовлетворять строки таблицы, выступающие в качестве корня поддерева. Если эта фраза отсутствует, все строки таблицы рассматриваются в качестве корневых. Условие фразы START WITH может содержать подзапрос.
Фраза CONNECT BY
Фраза CONNECT BY позволяет специфицировать связь между столбцами, формирующую иерархическое дерево. Она содержит условие, которое определяет древовидную связь. Условие может быть любым допустимым условием SQL, однако левая или правая часть условия должна содержать оператор PRIOR, который указывает, какая из строк выступает в качестве родительской. То есть условие в этой фразе должно иметь один из следующих видов:
PRIOR выражение оператор_сравнения выражение
выражение оператор_сравнения PRIOR выражение
Для нахождения всех дочерних строк родительской строки сначала вычисляется выражение, находящееся со стороны оператора PRIOR, а затем вычисляется второе выражение для всех строк таблицы. Те строки, для которых второе выражение оказывается истинным, рассматриваются как дочерние для текущей родительской строки. Фраза CONNECT BY может содержать другое условие для дальнейшей фильтрации выбираемых строк. Фраза CONNECT BY не может содержать подзапрос. Если вычисление дерева приводит к зацикливанию, это рассматривается как ошибочная ситуация. Зацикливание происходит в том случае, когда строка оказывается одновременно родительской (непосредственно или через несколько уровней) и дочерней (непосредственно или через несколько уровней) другой строки. В приводимом ниже примере фраза CONNECT BY определяет древовидную связь, в которой значение столбца TchPK родительской строки должно быть равно значению столбца Chief дочерней строки:
CONNECT BY PRIOR TchPK = Chief
В следующем примере фразы CONNECT BY оператор PRIOR применяется только к значению столбца TchPK. В связи с этим значение TchPK вычисляется для родительской строки, а значения Chief и Salary для дочерних:
CONNECT BY PRIOR TchPK = Chief AND Salary > 1000
Содержательно это следует трактовать следующим образом: соединять строки таким образом, чтобы TchPK родительской строки был равен Chief дочерней строки и у дочерней строки значение зарплаты было бы больше 1000.
Псевдостолбец LEVEL
В Oracle существует такое понятие как псевдостолбец. Это означает следующее: всякий раз, когда вы создаете таблицу базы данных и/или когда формируется таблица в результате вычисления запроса, Oracle автоматически приписывает к такой таблице дополнительные столбцы, значения которых ведутся самой системой. Что именно записывается в такие столбцы — зависит от их семантики.
Пользователь не может записать в такой столбец свое значение, но в любой момент может обратиться к его значению.
При выполнении рекурсивного предложения SELECT становится доступным псевдостолбец под именем LEVEL. Для каждой строки, формируемой рекурсивным запросом, псевдостолбец LEVEL возвращает значение 1 для корневой вершины, значение 2 для всех дочерних вершин корневой вершины и т. д. На рис. 10.4 показана древовидная структура таблицы с ее значениями столбца LEVEL.
Уровень 1Уровень 1Уровень 2Уровень 2Уровень 3Уровень 3Уровень 4Уровень 4Рис. 10.4. Древовидная структура таблицы с указанием уровнейРис. 10.4. Древовидная структура таблицы с указанием уровней
Уровень 1
Уровень 1
Уровень 2
Уровень 2
Уровень 3
Уровень 3
Уровень 4
Уровень 4
Рис. 10.4. Древовидная структура таблицы с указанием уровней
Рис. 10.4. Древовидная структура таблицы с указанием уровней
Рассмотрим пример вычисления рекурсивного запроса с использованием уровней. В приводимом ниже запросе производится поиск по каждому преподавателю его подчиненных, причем результат выдается согласно иерархической упорядоченности подчинения. Корневой является строка, соответствующая преподавателю, у которого столбец Chi ef равен NULL. Дочерние строки определяются таким образом, что их значения столбца Chi ef равны значению столбца TchPK родительской строки.
SELECT LPADC '. 2 * (LEVEL - 1)) || Name AS "Фамилия".
TchPK AS "Номер прел.".
Chief AS "Номер руков.", Post AS "Должность преп." FROM TEACHER
START WITH Chief IS NULL
CONNECT BY PRIOR TchPK = Chief;
Фамилия
Номер преп.
Номер руков.
Должность преп.
Сидоров
16
профессор
Рамишевский
4
16
доцент
Хоренко
2
4
преподаватель
Вибровский
1
2
ассистент
Воропаев
3
4
ассистент
Кузинцев
5
4
преподаватель
Мартынов
9
5
ассистент
Завратинский
6
16
доцент
Козлутин
8
6
ассистент
Лекарь
7
16
доцент
Недеведеев
И
7
преподаватель
Резван
10
16
профессор
131415131415профессор доцент преподавательпрофессор доцент преподавательАхромеев Наумов Дараганов
13
14
15
13
14
15
профессор доцент преподаватель
профессор доцент преподаватель
Функция LPAD приводит к формированию пробелов, кратных уровню, на котором расположена строка. Такие пробелы, сцепленные с помощью оператора конкатенации (11) с фамилиями преподавателей, приводят к появлению отступов согласно подчинению преподавателей.
Обратите внимание, что корневой сегмент имеет значение NULL для Chief. Если бы для указания этого корня было принято решение указать 16 в качестве значения столбца Chief (таким образом мы как бы указали, что он является руководителем над самим собой), рекурсивный запрос не был бы отработан, поскольку представленная таким образом иерархическая структура имела бы цикл. Как видим из ответа, у нас четыре преподавателя на верхнем уровне.
Условие отбора
Следующий запрос подобен предыдущему за исключением того, что в нем не выбираются фамилии доцентов.
SELECT LPADC *, 2 * (LEVEL - D) || Name AS "Фамилия", TchPK AS "Номер преп.". Chief AS "Номер руков.". Post AS "Должность преп."
FROM TEACHER
WHERE LOWER(Post) о 'доцент'
START WITH Chief IS NULL
CONNECT BY PRIOR TchPK = Chief;
Фамилия
Номер преп.
Номер руков.
Должность преп
Сидоров
16
профессор
Хоренко
2
4
преподаватель
Вибровский
1
2
ассистент
Воропаев
3
4
ассистент
Кузинцев
5
4
преподаватель
Мартынов
9
5
ассистент
Козлутин
8
6
ассистент
Недеведеев
11
7
преподаватель
Резван
10
16
профессор
Ахромеев
13
профессор
Дараганов
15
преподаватель
Обратите внимание, что доценты не включены в результат, но их подчиненные в списке присутствуют, причем с сохранением третьего уровня вложенности. Это видно по отступу расположения их фамилий, несмотря на то, что согласно полученному результату они вроде бы непосредственно подчинены Сидорову, который находится на первом уровне.
Условие на глубину иерархии
Следующее предложение подобно первому за исключением того, что в нем используется псевдостолбец LEVEL для вывода сведений о служащих первых двух уровней иерархической структуры.
SELECT LPADC '. 2 * (LEVEL - D) || Name AS "Фамилия".
TchPK AS “Номер прел.".
Chief AS "Номер руков.".
Post AS "Должность прел."
FROM TEACHER
START WITH Chief IS NULL
CONNECT BY PRIOR TchPK = Chief AND LEVEL <= 2;
Фамилия
Номер прел. Номер руков.
Должность прел
Сидоров
16
профессор
Рамишевский
416
доцент
Завратинский
616
доцент
Лекарь
716
доцент
Резван
1016
профессор
Ахромеев
13
профессор
Наумов
14.
доцент
Дараганов
15
преподаватель
Наконец, если нужно выбрать иерархическое поддерево, начиная с преподавателя Рамишевского, соответствующее условие следует ввести во фразу START WITH, как это показано в следующем примере.
SELECT LPADU *, 2 * (LEVEL - 1)) || Name AS "Фамилия".
TchPK AS "Номер прел.".
Chief AS "Номер руков.".
Post AS "Должность прел."
FROM TEACHER
START WITH UPPER(Name) = 'РАМИШЕВСКИЙ'
CONNECT BY PRIOR TchPK = Chief;
Фамилия Номер прел. Номер руков. Должность прел.
Рамишевский4
Хоренко2
Вибровский1
Воропаев3
Кузинцев5
Мартынов9
16 доцент
4 преподаватель
2 ассистент
4 ассистент
преподаватель
ассистент
Упорядочение строк
Как мы уже отмечали, порядок обхода строк иерархического дерева сверху-вниз, слева-направо. Именно в этом порядке строки и выводятся. Если необходимо изменить порядок вывода, следует прибегнуть к фразе ORDER BY. Вот как выглядит предыдущий пример, дополненный этой фразой.
SELECT LPADC '. 2 * (LEVEL - 1)) || Name AS "Фамилия", TchPK AS "Номер прел.".
Chief AS "Номер руков.".
Post AS "Должность прел."
FROM TEACHER.
START WITH UPPER(Name) = 'РАМИШЕВСКИЙ'
CONNECT BY PRIOR TchPK = Chief
ORDER BY Name:
Фамилия Номер преп. Номер руков. Должность прел.
Вибровский1
Воропаев3
Кузинцев5
Мартынов9
Рамишевский4
Хоренко2
2 ассистент
4 ассистент
4 преподаватель
5 ассистент
16 доцент
4 преподаватель
Результат упорядочен по фамилиям, но не совсем понятно, кто кому подчинен. Чтобы решить эту проблему, существует разновидность упорядочения, которая выражается фразой ORDER SIBLINGS BY. Она действует только в иерархических запросах (то есть имеющих фразу CONNECT BY) и означает следующее: иерархическая упорядоченность сохраняется за исключением того, что производится сортировка вершин, непосредственно принадлежащих одной родительской вершине. Приведем пример такого упорядочения.
SELECT LPADC ', 2 * (LEVEL - 1)) || Name AS "Фамилия",
TchPK AS "Номер преп.".
Chief AS "Номер руков.".
Post AS "Должность преп."
FROM TEACHER
START WITH UPPER(Name) = 'РАМИШЕВСКИЙ'
CONNECT BY PRIOR TchPK = Chief
ORDER SIBLINGS BY Name;
Фамилия Номер преп. Номер руков. Должность преп.
Рамишевский
4
16 доцент
Воропаев
3
4 ассистент
Кузинцев
5
4 преподаватель
Мартынов
9
5 ассистент
Хоренко
2
4 преподаватель
Вибровский
1
2 ассистент
Как видим, иерархическая вложенность сохранена и все преподаватели, подчиненные Рамишевскому, отсортированы. Во фразе ORDER SIBLINGS BY параметры точно такие же, как и в ORDER BY.
Подзапрос во фразе START WITH
Фраза START WITH может содержать подзапрос, который выступает одним из операндов оператора сравнения. Например, в следующем запросе отбор в иерархической структуре начинается с руководителя преподавателя Недеведеева.
SELECT LPAD(* '. 2 * (LEVEL - D) || Name AS "Фамилия",
TchPK AS "Номер преп.",
Chief AS "Номер руков.". Post AS "Должность преп."
FROM TEACHER
START WITH TchPK = (SELECT Chief
•FROM TEACHER
WHERE UPPER(name) = 'НЕДЕВЕДЕЕВ*)
CONNECT BY PRIOR TchPK » Chief;
Фамилия Номер преп. Номер руков. Должность преп.*
Лекарь716 доцент
Недеведеев117 преподаватель
рекурсивные запросы в стандарте SQL
В стандарте SQL-99 было расширено определение запроса. Его синтаксис принял следующий вид:
[фраза_Н1ТН] запрос
Здесь под запрос подразумевается стандартное понимание запроса, как мы его изучали до сих пор. В свою очередь, фраза WITH, которая может располагаться в начале запроса, используется для достижения следующих целей:
О описания подзапросов, которые многократно используются в самом запросе, с тем, чтобы к ним (подзапросам) можно было обращаться в запросе по имени;
О описания рекурсивного выполнения запроса.
Эта фраза имеет такой синтаксис (в несколько упрощенном варианте):
WITH [RECURSIVE] имя_подзапроса (список_имен_столбцов) AS (подзапрос)[, имя_подзапроса (список_имен_столбцов) AS (подзапрос)]...
Если ключевое слово RECURSIVE присутствует, это указывает на определение рекурсивного запроса, в противном случае определяются подзапросы. Рассмотрим кратко эти два варианта использования фразы WITH.
Определение повторяющихся подзапросов
Рассмотрим следующий запрос.
Запрос. Если средняя зарплата всех профессоров превышает среднюю зарплату доцентов более чем на 400, то вывести средние зарплаты профессоров и доцентов.
SELECT Post AS "Должность".
AVG(Salary * Rise) AS "Средн.зарплата", (SELECT AVG(Salary + Rise)
FROM TEACHER t, DEPARTMENT d. FACULTY f
WHERE t.DepFK = d.DepPK AND d.FacFK = f.FacPK AND
LOWER(f.Name) = 'информатика') AS "Средн.зарпл. в CS"
FROM TEACHER
GROUP BY TEACHER.Post
HAVING AVG(Salary + Rise) > (SELECT AVG(Salary + Rise)
FROM TEACHER t, DEPARTMENT d. FACULTY f
WHERE t.DepFK = d.DepPK AND d.FacFK = f.FacPK AND LOWER(f.Name) = 'информатика');
Должность Средн.зарплата Средн.зарпл. в CS
доцент1190,251025.91667
профессор 1553.333331025.91667
В приведенном выше запросе дважды повторяется подзапрос — во фразах SELECT и HAVING. С помощью фразы WITH этот подзапрос можно определить один раз и затем использовать его в самом запросе, как это показано ниже.
WITH FAC_AVG AS
(SELECT AVG(Salary + Rise) AS AVG SAL
FROM TEACHER t. DEPARTMENT d, FACULTY f
WHERE t.DepFK = d.DepPK AND d.FacFK = f.FacPK AND
. LOWER(f.Name) = 'информатика')
SELECT Post AS "Должность",
AVG(Salary + Rise) AS "Средн.зарплатa"..
(SELECT AVG_SAL FROM FAC_AVG) AS "Средн.зарпл. в CS"
FROM TEACHER
GROUP BY TEACHER.Post
HAVING AVGCSalary + Rise) > (SELECT AVG_SAL FROM FAC_AVG);
Рекурсивное выполнение запросов
Пусть имеется следующий рекурсивный запрос в Oracle:
SELECT TchPK, Name, Chief
FROM TEACHER
START WITH TchPK IS NULL
CONNECT BY Chief = PRIOR TchPK;
В стандарте SQL с использованием фразы WITH он выражается следующим образом:
WITH RECURSIVEJEACHER (TchPK, Name, Chief) AS -- 1
(SELECT parent.TchPK. parent.Name, parent.Chief -- 2
FROM TEACHER parent
WHERE parent.TchPK IS NULL
UNION ALL
SELECT child.TchPK, child.Name, child.Chief-- 3
FROM RECURSIVEJEACHER parent, TEACHER child
WHERE chi 1d.Chi ef = parent.TchPK)
SELECT TchPK, Chief, Name-- 4
FROM RECURS I VEJEACHER;
Опишем кратко составляющие этого запроса.
Определяется запрос с именем RECURS I VE_TEACHER и с синонимами столбцов той таблицы, которая получается в результате вычисления запроса. Они нужны для дальнейшей ссылки на эти столбцы.
Первая часть запроса. Запрос состоит из двух подзапросов, соединенных через UNION ALL. Этот подзапрос определяет стартовую позицию вычисления рекурсии. Он равносилен фразе START WITH TchPK IS NULL в запросе на Oracle.
Вторая часть запроса. В этом подзапросе реализуется рекурсия. В нем происходит соединение таблицы TEACHER с таблицей рекурсивного запроса фразы WITH. По сути, он выполняет функцию фразы CONNECT BY Oracle.
Собственно сам запрос, по которому выполняется рекурсивное вычисление. По сути, он ничего не делает, кроме как обращается к рекурсивному запросу и выводит его результат.
Многомерный анализ данных
Одним из ключевых моментов в системах поддержки принятия решений является многомерный анализ данных, который предполагает анализ предметной области с точки зрения всех необходимых комбинаций измерений. Мы подразумеваем под
измерением категорию, которая используется при многомерном анализе. В качестве примеров измерений можно привести время, географические характеристики, товар, структурные подразделения и т. д. Потенциальными измерениями могут быть все возможные виды деятельности организации. События или сущности предметной области, которые ассоциируются с конкретными значениями измерений, обычно называются фактами. Фактами могут быть продажа товаров в количественном измерении или стоимостном, объемы производства, количественные или качественные характеристики заказчиков и т. д.
Примерами многомерных запросов могут быть следующие:
О представить суммарные значения продаж по всем типам товаров с различными уровнями агрегации (от района к области и по стране в целом) за период 2000-2005 годы;
О провести анализ затрат по всем статьям расходов по месяцам, кварталам и по 2005 году в целом по всем структурным подразделениям организации;
О вывести десять лучших торговых представителей фирмы в Азии, занимающихся холодильным оборудованием, и упорядочить их согласно объемам продаж в расчете на одного работающего.
Многомерные запросы, как правило, требуют выдачи агрегированных данных. Для визуализации многомерных данных аналитики часто используют аналогию с кубом данных, то есть кубом, у которого факты хранятся в точке пересечения значений измерений. На рис. 10.5 приведен куб данных и показано, как его срезы могут использоваться различными категориями лиц. Куб хранит данные о продажах в измерениях времени, регионов и товара.
С точки зрения менеджера по товаруС точки зрения менеджера по товаруРис. 10.5. Куб данных и взгляды на него различных лицРис. 10.5. Куб данных и взгляды на него различных лицС точки зрения регионального менеджераС точки зрения регионального менеджера
С точки зрения менеджера по товару
С точки зрения менеджера по товару
Рис. 10.5. Куб данных и взгляды на него различных лиц
Рис. 10.5. Куб данных и взгляды на него различных лиц
С точки зрения регионального менеджера
С точки зрения регионального менеджера
Мы можем отыскивать данные в различных разрезах куба. Ответы на многомерные запросы обычно включают огромное количество данных. В связи с тем, что данные таких объемов тяжело осмыслить, обычно требуется некоторое агрегированное представление такой информации. Как правило, в многомерном анализе требуются итоговые значения по различным измерениям или комбинациям измерений.
Упорядоченная группировка
Упорядоченная группировка позволяет формировать многоуровневые промежуточные итоговые значения по указанной совокупности измерений, а также суммарное итоговое значение. Такая группировка синтаксически представляет собой следующее расширение фразы GROUP BY:
GROUP BY ROLLUP (список_столбцов_группировки)
Семантика такой группировки следующая:
О создаются группы по уникальным наборам значений всех столбцов списка (это стандартная группировка, задаваемая фразой GROUP BY);
О затем — группы по уникальным наборам значений всех столбцов списка, кроме последнего;
О затем — группы по уникальным наборам значений всех столбцов списка, кроме двух последних (и т. д.);
О затем — группы по уникальным значениям первого столбца списка;
О и наконец — вся таблица в целом.
По каждой созданной таким образом группе формируется отдельная строка с агрегированными данными согласно используемым во фразе SELECT агрегатным функциям. То есть фраза ROLLUP создает группы и, следовательно, позволяет формировать итоговые значения по п + 1 уровням, где п — количество столбцов группировки. Например, фраза ROLLUP (d.Name, g.Year) дает три уровня групп и позволяет создавать три уровня итоговых значений:
SELECT UPPER(d.Name) AS "Кафедра",
g.Year AS "Курс",
COUNTC*) AS "К-во групп", SUM(Quantity) AS "К-во студентов"
FROM DEPARTMENT d, SGROUP g
WHERE d.DepPK = g.DepFK
GROUP BY ROLLUP (d.Name, g.Year):
Кафедра
Курс К-во групп К-во студентов
БАЗЫ ДАННЫХ
3
1
33
БАЗЫ ДАННЫХ
4
1
27
БАЗЫ ДАННЫХ
2
60
ИНТЕРНЕТ
2
1
35
ИНТЕРНЕТ
1
35
ПРОГРАММИРОВАНИЕ
5
2
58
ПРОГРАММИРОВАНИЕ
2
58
5
153
Как видим, запрос возвращает следующие группы строк:
О обычные строки агрегирования, которые получаются с помощью GROUP BY без ROLLUP (строки, у которых заданы значения первых двух столбцов): агрегирование по кафедрам и курсам;
О строки агрегирования второго уровня: агрегирование по кафедрам (строки, у которых заданы значения кафедры и отсутствуют значения курсов);
О строка агрегирования третьего уровня: строка с итоговыми данными по всей таблице.
Значения NULL, возвращаемые фразами GROUP BY ROLLUP и GROUP BY CUBE, не имеют стандартного смысла «значение не определено». В этом случае NULL означает, что это строка промежуточного итогового значения.
Замена фразы ROLLUP оператором UNION
Результат, аналогичный приведенному выше запросу, может быть достигнут с помощью оператора UNION:
SELECT d.Name. g.Year. COUNT(*), SUM(Quantity)
FROM DEPARTMENT d. SGROUP g
WHERE d.DepPK = g.DepFK
GROUP BY d.Name, g.Year
UNION ALL
SELECT d.Name. NULL. COUNT(*), SUM(Quantlty)
FROM DEPARTMENT d, SGROUP g
WHERE d.DepPK = g.DepFK
GROUP BY d.Name
UNION ALL
SELECT NULL, NULL, COUNT(*). SUM(Quantity)
FROM DEPARTMENT d. SGROUP g
WHERE d.DepPK = g.DepFK
NAMEYEAR COUNT(*) SUM(QUANTITY)
базы данных
3
1
33
базы данных
4
1
27
интернет
2
1
35
программирование
5
2
58
базы данных
2
60
интернет
1
35
программирование
2
58
5
153
Здесь нам потребовалось объединить три запроса. В общем случае, если ROLLUP содержит п столбцов, то без ROLLUP необходимо будет объединить и + 1 запросов. Использование ROLLUP уменьшает размеры запроса и во много раз уменьшает время вычисления запроса по сравнению с эквивалентом запроса без ROLLUP.
Фразу ROLLUP следует использовать тогда, когда требования на создание промежуточных итоговых значений носят иерархический характер, например, в территориальном разрезе (регион, государство, область, район) или в разрезе времени (год, полугодие, квартал, месяц, неделя).
Группировка по всем комбинациям измерений
Обратите внимание, что ROLLUP дает только часть возможных комбинаций труп- пировки. Например, нельзя получить количество групп и количество студентов в группах по курсам при использовании фразы ROLLUP (d.Name. g. Year), так как для этого необходимо другое упорядочение измерений, а именно ROLLUP (g. Year. d.Name). Фраза GROUP BY CUBE предложения SELECT формирует группы по всем комбинациям указываемых измерений и тем самым позволяет по всем ним формировать агрегированные значения, включая и по таблице в целом. Синтаксис использования фразы CUBE следующий:
GROUP BY CUBE (списокстолбцовгруппировки)
Таким образом, фраза CUBE позволяет формировать все допустимые промежуточные агрегированные значения, которые могут быть вычислены на кубе данных с указанными измерениями. Итак, если куб имеет п измерений, формируется 2” групп и, следовательно, можно вычислить такое же количество итогов. Приведем пример:
SELECT UPPER(d.Name) AS "Кафедра".
g.Year "Курс".
COUNT(*) AS "К-во групп".
SUM(Quantity) AS "К-во студентов"
FROM DEPARTMENT d. SGROUP g
WHERE d.DepPK = g.DepFK
GROUP BY CUBE (d.Name, g.Year);
КафедраКурс К-во групп К-во студентов
БАЗЫ ДАННЫХ
3
1
33
БАЗЫ ДАННЫХ
4
1
27
БАЗЫ ДАННЫХ
2
60
ИНТЕРНЕТ
2
1
35
ИНТЕРНЕТ
1
35
ПРОГРАММИРОВАНИЕ
5
2
58
ПРОГРАММИРОВАНИЕ
2
58
2
1
35
3
1
33
4
1
27
5
2
5
58
153
Как и в ROLLUP,
вместо
CUBE можно использовать множество предложений SELECT,
объединяемых через UNION. Однако для этого требуется 2” предложений SELECT для
n-мерного куба. Так, в нашем примере необходимо четыре предложения SELECT, связываемых через UNION ALL. При добавлении еще одного измерения число предложений удваивается и становится равным восьми. Фраза CUBE оказывается особенно полезной в запросах, требующих агрегированные данные в произвольных разрезах куба данных, который имеет независимые измерения.
Использование функций с фразами ROLLUP и CUBE
Для демонстрации ROLLUP и CUBE мы использовали агрегатные функции SUM и COUNT. Хотя они и являются наиболее часто используемыми функциями в ROLLUP и CUBE, тем не менее, можно привлекать и другие агрегатные функции. Кроме того, для ROLLUP и CUBE, и только для них, можно применить еще одну функцию — GROUPING. Она использует в качестве аргумента один столбец группировки и возвращает значение 1, когда фраза ROLLUP или CUBE порождает значение NULL для этого столбца. Во всех остальных случаях она возвращает 0. Функция может использоваться только во фразе SELECT или HAVING, и только при наличии группировки по ROLLUP или CUBE. В следующем примере мы используем функцию GROUPING для замены в итоговых строках значений NULL на соответствующие строковые константы.
SELECT DECODE(GROUPING(d.Name). 1, 'Все кафедры'. UPPER(d.Name)) AS "Кафедра".
DECODE(GROUPING(g.Year). 1. 'Все курсы'. UPPER(g.Year)) AS "Курс".
COUNT(*) AS "К-во групп".
SUM(Quantity) AS "К-во студентов"
FROM DEPARTMENT d. SGROUP g
WHERE d.DepPK = g.DepFK
GROUP BY CUBE (d.Name. g.Year):
Кафедра
КурсК-во групп К-во студентов
БАЗЫ ДАННЫХ
3
1
33
БАЗЫ ДАННЫХ
4
1
27
БАЗЫ ДАННЫХ
Все курсы
2
60
ИНТЕРНЕТ
2
1
35
ИНТЕРНЕТ
Все курсы
1
35
ПРОГРАММИРОВАНИЕ
5
2
58
ПРОГРАММИРОВАНИЕ
Все курсы
2
58
Все кафедры
2
1
35
Все кафедры
3
1
33
Все кафедры
4
1
27
Все кафедры
5
2
58
Все кафедры
Все курсы
5
153
Мы использовали функцию DECODE для преобразования значения 1, возвращаемого функцией GROUPING, в соответствующую строковую константу.
Группировка по наборам измерений
Еще одним расширением традиционной группировки является вариант GROUP BY GROUPING SETS, в котором можно указать множество наборов группировки. Синтаксис этого варианта группировки следующий:
GROUP BY GROUPING SETS (набор_группировки[, набор_группировки]...)
Набор группировки представляет собой один из следующих трех вариантов:
(список_столбцов_группировки)
CUBE (список_столбцов_группировки)
ROLLUP (список_столбцов_группировки)
Итак, в качестве элемента набора могут вместе или по отдельности выступать:
О обычная группировка;
О упорядоченная группировка;
О группировка по всем комбинациям измерений.
При этом происходит самостоятельное вычисление всех указанных наборов группировки и затем полученные таблицы объединяются с помощью оператора UNION ALL. Это приводит к тому, что результирующая таблица может иметь повторяющиеся строки:
SELECT DECODE(GROUPING(d.Name), 1. 'Все кафедры', UPPER(d.Name)) AS "Кафедра".
DECODE(GROUPING(g.Year). 1, 'Все курсы', UPPER(g.Year)) AS "Курс", COUNT(*) AS "К-во групп".
SUM(Quantity) AS "К-во студ."
FROM DEPARTMENT d. SGROUP g
WHERE d.DepPK = g.DepFK'
GROUP BY GROUPING SETS ((d.Name, g.Year), (d.Name), (g.Year)):
Кафедра
Курс
К-во групп К-во студ.
БАЗЫ ДАННЫХ
3
1
33
БАЗЫ ДАННЫХ
4
1
27
ИНТЕРНЕТ
2
1
35
ПРОГРАММИРОВАНИЕ
5
2
58
БАЗЫ ДАННЫХ
Все
курсы
2
60
ИНТЕРНЕТ
Все
курсы
1
35
ПРОГРАММИРОВАНИЕ
Все
курсы
2
58
Все кафедры
2
1
35
Все кафедры
3
1
33
Все кафедры
4
1
27
Все кафедры
5
2
58
При использовании фраз ROLLUP и CUBE в списке наборов запрос выглядит таким образом:
SELECT DECODE(GROUPING(d.Name), 1, 'Все кафедры', UPPER(d.Name)) AS "Кафедра". DECODE(GROUPING(g.Year), 1, 'Все курсы*, UPPER(g.Year)) AS "Курс", COUNTC*) AS "К-во групп", SUM(Quantity) AS "К-во студ."
FROM DEPARTMENT d. SGROUP g
WHERE d.DepPK = g.DepFK
GROUP BY GROUPING SETS ((d.Name, g.Year), ROLLUP (d.Name). CUBE (g.Year));
Кафедра
КурсК-во групп К-во студ.
БАЗЫ ДАННЫХ
3
1
33
БАЗЫ ДАННЫХ
4
1
27
ИНТЕРНЕТ
2
1
35
ПРОГРАММИРОВАНИЕ
5
2
58
БАЗЫ ДАННЫХ
Все курсы
2
60
ИНТЕРНЕТ
Все курсы
1
35
ПРОГРАММИРОВАНИЕ
Все курсы
2
58
Все кафедры
2
1
35
Все кафедры
3
1
33
Все кафедры
4
1
27
Все кафедры
5
2
58
Все кафедры
Все курсы
5
153
Все кафедры
Все курсы
5
153
Анализ «ТОР М»
Запросы типа «ТОР N» позволяют вывести п строк с наибольшими или наименьшими значениями столбца, например: «Вывести 10 компаний с наибольшими прибылями в 2005 году». Запросы этого вида обычно используют структуру вложенного запроса со следующими элементами.
О Подзапрос создает упорядоченный список строк. Он использует фразу ORDER BY для получения необходимого упорядочения.
О Внешний запрос ограничивает строки конечного результата требуемым условием. Ограничение может использовать:
псевдостолбец ROWNUM, который присваивает последовательные номера строкам результирующей таблицы;
фразу WHERE для указания условия на результирующие строки (как правило, это условие на столбец ROWNUM, ограничивающее количество выдаваемых строк).
^^ПРИМЕЧАНИе" Псевдостолбец — это понятие Oracle, а не стандарта SQL.*
В следующем запросе выводятся фамилии первых пяти принятых на работу преподавателей.
SELECT ROWNUM AS "№ п/п".
Name AS "Фамилия",
T0_CHAR(H1reDate, 1DD-MONTH-YYYY*) AS "Дата приема" FROM (SELECT Name, Hi reDate FROM TEACHER ORDER BY Hi reDate) WHERE ROWNUM < 6;
№ п/п Фамилия Дата приема
1 Кузинцев01-ЯНВАРЬ -1991
2 Лекарь03-ИЮНЬ -1991
3 Сидоров01-СЕНТЯБРЬ-1992
4 Наумов01-СЕНТЯБРЬ-1994
5 Завратинский 01-ФЕВРАЛЬ -1996
Для выражения запросов этого вида обязательно следует использовать вложенный во фразу FROM запрос. Дело в том, что в таблицах базы данных строки запоминаются в порядке их ввода в базу данных и в этом же порядке им присваиваются номера строк (ROWNUM). После выполнения подзапроса получается временная таблица. Если эту таблицу упорядочить в подзапросе, строкам будут присвоены ROWNUM согласно их упорядочению.
Рассмотрим еще одни пример, когда дополнительно к предыдущему запросу необходимо провести ранжирование преподавателей по их зарплате (ранжирование по зарплате производится по всем преподавателям, а не только по тем, которые выводятся согласно первому ранжированию).
SELECT ROWNUM AS "№ п/п", Name AS "Фамилия", TO_CHAR(HireDate. 'DD-MONTH-YYYY') AS "Дата приема", SalaryRange AS "Ранг зарплаты"
FROM (SELECT Name, Hi reDate, SalaryRange
FROM (SELECT Name, Hi reDate, ROWNUM AS SalaryRange FROM TEACHER
ORDER BY Salary + Rise)
ORDER BY Hi reDate)
WHERE ROWNUM <6;
№ п/п Фамилия
Дата приемаРанг
зарплаты
1 Кузинцев
01-ЯНВАРЬ -1991
6
2 Лекарь
03-ИЮНЬ -1991
9
3 Сидоров
01-СЕНТЯБРБ-1992
1
4 Наумов
01-СЕНТЯБРЬ-1994
14
5 Завратинский
01-ФЕВРАЛЬ -1996
7
Отличие этого запроса от предыдущего заключается в том, что внутренний подзапрос во фразе FROM вместо имени таблицы преподавателей содержит подзапрос. В этом подзапросе мы упорядочиваем таблицу TEACHER по значению выражения Salary + Rise и здесь же формируем дополнительный столбец со значением ROWNUM — это номер упорядочения по зарплате.
Самостоятельная работа
Вывести фамилии профессоров, которые не приписаны ни к какой кафедре.
Вывести фамилию руководителя руководителя Мартынова.
Сколько преподавателей не имеют руководителей?
Вывести информацию обо всех подчиненных Кузинцева, включая и подчиненных его подчиненных и т. д.
Вывести список всех преподавателей с указанием уровня подчинения (уровня, на котором он находится в древовидной структуре подчинения).
Вывести фамилии руководителей тех преподавателей, которые сами не руководят другими преподавателями.
Вывести сведения о преподавателе Рамишевском и всех его подчиненных до 3-го уровня вложенности.
Произвести упорядоченную группировку преподавателей по кафедре и должности. По каждой упорядоченной группе вывести количество преподавателей и суммарную зарплату. Сделайте это с использованием ROLLUP и с UNION ALL.
Произведите группировку преподавателей по всем комбинациям следующих трех измерений: кафедра, должность, телефон. Для каждой такой комбинации выведите количество преподавателей и суммарное количество зарплаты. Значения NULL, которые появляются в измерениях в результате группировки, заменить соответственно на строки Все кафедры, Все преподаватели, Все телефоны.
Приведите пример группировки по наборам измерений.
Выведите номера трех групп с самыми большими рейтингами. Укажите также ранг количества студентов в группе. Ранг количества студентов в группе вычисляется в порядке убывания количества студентов. Группе с самым большим количеством студентов присваивается ранг 1, следующей по убыванию количества студентов группе присваивается ранг 2, следующей группе — 3 и т. д.
Подведение итогов
Усвоив материал этого урока, вы научились:
0 использовать неопределенные значения в SQL;
0 формулировать рекурсивные запросы, используя стандартные средства SQL;
0 формулировать рекурсивные запросы, используя расширенные возможности SQL;
0 производить упорядоченную группировку данных;
0 осуществлять группировку по всем комбинациям измерений;
0 производить группировку по наборам измерений;
0 производить ранжирование данных.
) УРОК Определение таблиц
Для создания и изменения объектов базы данных используется язык определения данных — ЯОД (Data Definition language - DDL). Ядро ЯОД образуют следующие три команды:
О CREATE —создает объект базы данных;
О ALTER — изменяет определение существующего объекта;
О DROP — удаляет ранее созданный объект.
В реляционной базе данных таблица является основной структурной составляющей. В этом уроке мы рассмотрим создание, изменение и удаление таблиц. Все это относится к самим таблицам, а не к данным, которые в них содержатся. Создание и работа с другими объектами базы данных будут рассмотрены в следующих уроках.
Создание таблицы
Таблицы базы данных создаются в SQL с помощью предложения CREATE TABLE, которое позволяет определить имя таблицы, столбцы таблицы и ограничения целостности. В этом уроке мы рассмотрим определение столбцов, а в следующем — ограничения целостности.
Определение столбцов
В минимальном варианте при создании таблицы определяется имя таблицы и набор имен столбцов, указанных в определенном порядке и имеющих указанный тип. Каждая таблица должна иметь, по крайней мере, один стблбец. Синтаксис предложения CREATE TABLE поддерживает следующую минимальную форму:
CREATE TABLE имя_таблицы ( имя_столбца тип_данных[. имя_столбца тип_данных]...);
где тип_данных должен принадлежать к одному из типов, поддерживаемых СУБД. Типы данных могут значительно отличаться в различных СУБД. Однако для
совместимости они должны поддерживать стандарт ANSI/ISO. Так, описание таблицы FACULTY может быть представлено в следующем виде:
CREATE TABLE FACULTY (
FacPK INTEGER.
Name VARCHAR(30),
Dean VARCHAR(20),
Building CHAR(5).
Fund NUMBER(7, 2));
В результате создается пустая таблица FACULTY. Важно помнить следующее.
О Требуется именование самих таблиц и их столбцов. Каждая конкретная СУБД может применять свои отличительные правила именования.
О В таблице не мохут существовать два столбца с одинаковыми именами. Разные таблицы могут использовать одинаковые имена столбцов.
О В менее мощных СУБД в базе данных не могут существовать таблицы с одинаковыми именами. В мощных профессиональных СУБД все создаваемые объекты базы данных закрепляются за пользователем, который их создал. Так, в Oracle множество созданных одним пользователем объектов базы данных называется схемой базы данных. Схеме автоматически приписывается имя пользователя. Внутри схемы не могут повторяться имена таблиц, однако в различных схемах могут присутствовать таблицы с одинаковыми именами.
О Там, где есть понятие, подобное схеме в Oracle, имя таблицы дополняется именем пользователя (схемы), который ее создал. Если пользователь зарегистрирован в системе под именем Drew, в СУБД регистрируется таблица Drew. FACULTY и этот пользователь может обращаться к ней по имени Drew. FACULTY или по сокращенному имени FACULTY. Если другой пользователь получил право обращаться к таблицам пользователя Drew, он должен будет использовать имена таблиц, обязательно уточняя их именем пользователя-владельца, например Drew.FACULTY.
Определение и использование доменов
В стандарте SQL при определении столбца разрешается вместо типа данных указывать домен. Домен представляет собой именованное описание множества допустимых значений столбца. В основе определения домена лежит один из типов данных, на значения которого наложены дополнительные ограничения, проверяющиеся при внесении данных в соответствующий столбец. Домен создается с помощью предложения CREATE DOMAIN, которое имеет следующий синтаксис:
CREATE DOMAIN имя_домена [AS] тип_данных [DEFAULT значение] ограничение_домена
где ограничение_домена имеет такой синтаксис:
[[CONSTRAINT имя] CHECK (ограничение) [свойства]]
Подробно об ограничениях и, в частности, ограничении целостности CHECK будет идти речь в уроке 12. Приведем примеры определения доменов:
CREATE DOMAIN Bld_Domain AS CHAR(5) DEFAULT *
CONSTRAINT FacBldConstr CHECK (VALUE >=')
CREATE DOMAIN Fund_Doma1n AS NUMERIC (7,2) CHECK (VALUE BETWEEN 0 AND 2000000)
Используемое в этих ограничениях ключевое слово VALUE заменяется на имя конкретного столбца, в определении которого будет использоваться соответствующий домен. На основе этих определений столбцы BUILDING и FUND из предыдущего примера могут иметь следующие определения:
Building Bld_Doma1n
Fund Fund_Doma1n
Преимущество использования домена заключается в том, что его можно использовать при определении различных столбцов в различных таблицах. Изменение определения домена автоматически приводит к изменению определения всех использующих их столбцов. Оно производится с помощью предложения ALTER DOMAIN, имеющего следующий синтаксис:
ALTER DOMAIN имя_домена действие
Действия могут быть такими:
О SET DEFAULT значение - установка значения по умолчанию;
О DROP DEFAULT — удаление значения по умолчанию;
О ADD ограничение_домена — добавление ограничения;
О DROP CONSTRAINT имя — удаление ограничения.
Удаление домена производится предложением DROP DOMAIN, имеющим следующий синтаксис:
DROP DOMAIN имя_домена [CASCADE | RESTRICT)
Ключевое слово CASCADE указывает, что при удалении домена будут автоматически удалены все столбцы, ссылающиеся на него. Ключевое слово RESTRICT запрещает удалять домен, если он используется в определении хотя бы одного столбца. Отметим, что не все СУБД поддерживают определение домена.
Значения по умолчанию
Когда вы вставляете строку в таблицу без указания в ней значений для столбца, SQL должен знать, что именно необходимо вставить вместо отсутствующего значения. Это так называемое значение по умолчанию. Общепринятым значением по умолчанию является NULL. Это — значение по умолчанию для любого столбца, которому не было дано ограничение NOT NULL (см. следующий урок) или который не имеет явно заданного значения по умолчанию. Как стандарт SQL, так и большинство реляционных СУБД поддерживают явное задание для столбцов значений по умолчанию, которые указываются при определении столбца. Значение по умолчанию указывается фразой DEFAULT с использованием следующего синтаксиса: имя_столбца тип_данных DEFAULT значение_пО-Умолчанию
где значение по умолчанию представляет собой константу, соответствующую типу данных определяемого столбца. Например, если мы хотим, чтобы значение по умолчанию при задании фонда факультета было равно 0, тогда определение этого столбца с учетом использования домена будет иметь следующий вид:
Fund Fund Domain DEFAULT 0
Другой способ воспользоваться значением по умолчанию — это использовать его как альтернативу для NULL. Так как значение NULL не дает TRUE при сравнении практически со всеми предикатами, оно не включается в проверки большинством предикатов, что, как мы покажем в последующих уроках, может приводить к выводу неправильных результатов вычисления запросов. С другой стороны, указанное значение по умолчанию будет приниматься в расчет всеми предикатами, имеющими отношение к соответствующему типу данных. Наконец, если вы используете значение по умолчанию, чтобы избежать значений NULL, это может предотвратить возможные ошибки (например, связанные с тем, что при вводе данных значение столбца оказывается случайно нс заданным).
Определение временной таблицы
Выше описывалось определение постоянной таблицы. Она характеризуется тем, что ее определение и содержимое существуют в базе данных до тех пор, пока они не будут удалены явно с помощью соответствующих команд. Определение временной таблицы также может быть удалено только явно, однако ее содержимое может удаляться или становиться невидимым (недостижимым) автоматически при достижении определенных условий. Временная таблица определяется следующим образом:
CREATE {GLOBAL | LOCAL} TEMPORARY TABLE имя_таблицы определение_таблицы
ON COMMIT {PRESERVE | DELETE} ROWS
Мы не будем вдаваться в подробности, касающиеся различий между глобальной и локальной временными таблицами. Главным для понимания временной таблицы является следующее. Хотя определение временной таблицы является постоянным, однако ее содержимое сохраняется только на период не больше, чем текущий сеанс работы. Более того, можно определить, должны ли данные такой таблицы сохраняться на период всего сеанса или только на протяжении выполнения транзакции. Вариант ON COMMIT DELETE указывает, что данные должны храниться на протяжении выполнения транзакции и по ее завершении они должны быть удалены. Вариант использования ключевого слова PRESERVE предполагает сохранение данных на период всего сеанса работы.
Определение таблицы на основе существующей
Общепринятым способом создания таблицы является использование предложения CREATE TABLE. Однако стандарт SQL позволяет определять таблицу на основании существующей с возможностью одновременной загрузки строк данных из существующей таблицы. Делается это с использованием следующего синтаксиса:
CREATE TABLE имя_таблицы
[(список_имен_столбцов)] AS (подзапрос)
WITH [NO] DATA
В качестве подзапроса можно использовать любое допустимое предложение SELECT. Если список имен столбцов отсутствует, формируемая таблица наследует имена столбцов подзапроса. Этим списком можно воспользоваться для указания других имен столбцов создаваемой таблицы. Типы столбцов наследуются из подзапроса.
Вновь созданная таблица будет содержать только имена столбцов с их типами без возможных ограничений целостности и значений по умолчанию. Их можно будет добавить впоследствии с помощью предложения ALTER TABLE.
С помощью фразы WITH [NO] DATA указывается, будет ли создаваться только определение таблицы на основании подзапроса или во вновь созданную таблицу будут автоматически загружены строки таблицы подзапроса. Не все СУБД поддерживают полностью или частично такую возможность. Например, в Oracle отсутствует фраза WITH [NO] DATA. Таблица по умолчанию создается со строками, сформированными подзапросом. В приводимом ниже примере создается таблица расписания занятий преподавателей на первой неделе.
CREATE TABLE TEACHERJTMETABLE
(TchName, GrpNum, Week, Day, Lesson, Type, RomNum, Bld) AS
(SELECT t.Name, g.Num, l.Week, l.Day. 1.Lesson, l.Type, r.Num, r.Building
FROM TEACHER t, SGROUP g, LECTURE 1, ROOM r
WHERE l.TchFK - t.TchPK AND l.GrpFK = g.GrpPK AND l.RomFK = r.RomPK AND l.Week=l);
Таблица создана.
SELECT * FROM TEACHER_TIMETABLE;
TCHNAME
GRPNUM WEEK DAY LESSON TYPE
ROMNUM BLD
Воропаев
505
1
втр
3 лаб
311
6
Вибровский
505
1
пнд
1
лаб
311
6
Мартынов
505
1
НТВ
4
лаб
311
6
Рамишевский
505
1
втр
4
лекц
201
6
Хоренко
505
1
пнд
2
лекц
201
6
Резван
505
1
птн
1
лекц
201
6
Кузинцев
505
1
срд
3
лекц
201
6
Завратинский
505
1
срд
4
лекц
201
5
Лекарь
505
1
чтв
2
лекц
202 4
Козлутин
505
1
НТВ
3
практ
225 7
Недеведеев
505
1
птн
4
лаб
104 6
Изменение определения таблицы
SQL предоставляет возможность изменить определение таблицы. Это делается командой ALTER TABLE. Стандарт SQL позволяет производить следующие изменения в определении таблицы (об изменениях, связанных с описанием ограничений целостности см. следующий урок):
О добавлять в таблицу определение нового столбца;
О изменять значение по умолчанию;
О удалять столбец из таблицы.
Стандарт SQL требует, чтобы предложение ALTER TABLE применялось для единичного изменения таблицы. Многие СУБД снимают это ограничение. Более того, они расширяют функции этого предложения, вводя, например, следующие возможности:
О изменение имени таблицы;
О изменение типа столбца.
СОВЕТСОВЕТВы должны разрабатывать вашу базу данных по возможности так, чтобы не слишком часто эту команду использовать. Изменение структуры таблицы, когда она уже используется, — опасно! По этой причине вы должны разрабатывать ваши таблицы так, чтобы использовать ALTER TABLE только в крайнем случае. Если ваша система не поддерживает ALTER TABLE или если вы хотите избежать ее использования, вы можете просто создать новую таблицу с необходимыми изменениями в ее структуре и использовать команду INSERT с запросом SELECT, чтобы переписать в нее данные из старой таблицы.
СОВЕТ
СОВЕТ
Далее рассмотрим синтаксис и семантику предложения ALTER TABLE согласно Oracle.
Добавление столбца
Обычно команда ALTER TABLE используется для добавления столбцов. Для этого используется следующий синтаксис:
ALTER TABLE имя_таблицы ADD (
определение_столбца[.
определение_столбца]...):
где определение столбца задается точно так же, как и при создании таблицы. Новый столбец станет последним по порядку столбцом таблицы. В следующем примере добавляются два новых столбца к таблице FACULTY для хранения сведений о заместителе декана (Deputy Dean) и этаже (Floor), на котором расположен деканат:
ALTER TABLE FACULTY ADD
(Deputy_Dean varchar(20), Floor char(2)DEFAULT 'XX'):
Таблица изменена.
Если таблица, в определение которой добавляются новые столбцы, уже содержит строки, обычно СУБД поступает следующим образом. Если в определении добавляемого столбца указано значение по умолчанию, он во всех существующих строках принимает значение по умолчанию. В противном случае он принимает значение NULL. Помните, если таблица уже содержит строки, нельзя добавлять новый столбец с ограничением NOT NULL. В этом случае будет выдано сообщение об ошибке и столбец не будет добавлен:
ALTER TABLE FACULTY ADD
Deputy_Dean varchar(20) NOT NULL:
ALTER TABLE FACULTY ADD *
ошибка в строке 1:
ORA-01758: при добавлении обязательного (NOT NULL) столбца таблица должна быть пуста
Изменение определения столбца
Стандарт SQL позволяет добавлять и удалять значения столбцов по умолчанию.
Это делается с использованием следующих предложений ALTER:
ALTER TABLE имя_таблицы ALTER [COLUMN] SET DEFAULT значение
ALTER TABLE имя_таблицы ALTER [COLUMN] DROP DEFAULT
Многие СУБД расширяют возможности по изменению определения столбцов, допуская дополнительно изменение их типов и/или размеров. Как правило, если таблица пустая, СУБД позволяет производить любые переопределения столбцов таблицы. Однако имеются существенные ограничения на изменения описания столбцов, например, если это относится к замене типов данных в том случае, когда таблица уже содержит строки данных. Каждая СУБД поддерживает свои правила допустимости преобразований типов данных, и они используются в том случае, когда такие изменения предполагаются командой ALTER TABLE по отношению к непустой таблице. В Oracle синтаксис предложения для изменения определения столбцов следующий:
ALTER TABLE имя_таблицы MODIFY (
имя_столбца [тип_данных] [DEFAULT значение][,
имя_столбца [тип_данных] [DEFAULT значение]]...):
Приведем пример переопределения столбцов, в котором для столбца Deputy Dean изменяется максимально допустимый его размер и вводится значение по умолчанию, а для столбца Floor меняется тип, длина и значение по умолчанию.
ALTER TABLE FACULTY MODIFY
(Deputy_Dean varchar(30) DEFAULT 'ЗНАЧЕНИЕ ОТСУТСТВУЕТ'.
Floor varchar(3)DEFAULT '000'):
Таблица изменена.
Удаление столбца
С помощью предложения ALTER TABLE можно удалить один или несколько столбцов, если в них больше нет необходимости. Синтаксис этого варианта ALTER TABLE в стандарте SQL следующий:
ALTER TABLE имя_таблицы DROP имя_столбца [CASCADE | RESTRICT}
Обратим ваше внимание на следующий факт. Удаляемый столбец может использоваться в описаниях ограничений целостности (о них см. следующий урок). Что делать с такими описаниями при удалении столбца? Наличие фразы CASCADE указывает, что такие ограничения также должны быть удалены. Фраза RESTRICT запрещает удалять столбец до тех пор, пока не будут удалены все ссылающиеся на него ограничения. В Oracle удаление столбца производится командой, имеющей следующий синтаксис:
ALTER TABLE имя_таблицы DROP
(имя_столбца[. имя_столбца]...) [CASCADE CONSTRAINTS]:
где наличие фразы CASCADE CONSTRAINTS соответствует фразе CASCADE в стандарте SQL, а ее отсутствие — фразе RESTRICT в стандарте SQL. Например, столбцы Depu- ty_Dean и Floor из FACULTY удаляются следующим образом:
ALTER TABLE FACULTY DROP (DEPUTY_DEAN, FLOOR);
Таблица изменена.
В случае использования фразы CASCADE CONSTRAINTS удаление столбца Deputy_Dean может выглядеть следующим образом:
ALTER TABLE FACULTY DROP (Deputy_Dean) CASCADE CONSTRAINTS:
ПРИМЕЧАНИЕПРИМЕЧАНИЕИспользование фразы CASCADE CONSTRAINTS может вызвать целую лавину изменений. Поэтому применять такую возможность следует с осторожностью.
ПРИМЕЧАНИЕ
ПРИМЕЧАНИЕ
Удаление столбца предполагает его физическое удаление из таблицы. При больших размерах таблиц эта процедура может оказаться довольно продолжительной. В этом случае некоторые СУБД предоставляют возможность выполнить этот процесс в два этапа. Сначала выполняется логическое удаление столбца, при котором он физически не удаляется из таблицы, но становится невидимым и недоступным для использования. Затем в более удобное время можно произвести его физическое удаление.
Переименование таблицы
Стандарт SQL не допускает изменения имени таблицы, но во многих СУБД такая возможность предусматривается. Например, в Oracle имя таблицы изменяется предложением ALTER TABLE, имеющим следующий синтаксис:
ALTER TABLE имя_таблицы RENAME ТО новое_имя_таблицы;
Например, можно следующим образом переименовать таблицу FACULTY:
ALTER TABLE FACULTY RENAME TO NEW_FACULTY;
Таблица изменена.
Будьте внимательными, чтобы новое имя не совпало с именем одной из существующих таблиц базы данных. Иначе вы получите сообщение об ошибке.
Удаление таблицы
С течением времени структура базы данных изменяется. Могут появляться новые таблицы и удаляться существующие. Удаление таблицы подразумевает удаление ее описания и всех содержащихся строк. Удаление таблиц базы данных производится командой DROP TABLE, которая имеет следующий синтаксис:
DROP TABLE имя_таблицы {CASCADE | RESTRICT}:
Фразы CASCADE и RESTRICT имеют тот же смысл, что и при удалении столбца. Если какой-нибудь из столбцов удаляемой таблицы используется для описания целостности в другой таблице, попытка удаления будет отклонена при наличии фразы RESTRICT. При использовании фразы CASCADE таблица удаляется вместе со всеми ограничениями, определенными в других таблицах и ссылающимися на столбцы удаляемой таблицы. Например, для удаления таблицы LECTURE следует выполнить следующую команду:
DROP TABLE LECTURE;
Таблица удалена.
ПРИМЕЧАНИЕ База данных состоит из многих объектов. Некоторые из объектов являются производными от других. К ним, например, относятся триггеры и представления (см. уроки 17 и 14). В связи с этим переименование или удаление объекта базы данных, например таблицы, может вызвать побочные эффекты. Вы должны помнить об этом и перед выполнением таких операций обратиться к документации, используемой СУБД для ознакомления, каким образом она поступает в таких случаях.
В Oracle вместо CASCADE или RESTRICT используется факультативная фраза CASCADE CONSTRAINTS с тем же смыслом, что и при удалении столбцов.
Определение и использование индексов
Индекс — это специальная таблица, построенная по значениям заданного столбца или группы столбцов заданной таблицы. В ней размещается перечень уникальных значений указанного столбца таблицы со ссылками на те строки основной таблицы, где встречаются эти значения. Структура индекса напоминает предметный указатель книги. Например, индекс может иметь вид, показанный в табл. 11.1.
Таблица 11.1. Пример структуры индекса
Значение столбца Содержащие его строки
132,33
220,21
37, 8, 12, 18, 22, 24, 28, 31
42, 6, 9, 13, 14
51, 3, 17, 23, 15
64,5,10,11
725, 26, 27, 29, 30
8 16, 19
Решение о том, использовать или не использовать какой-либо индекс при обработке некоторого конкретного запроса, принимается оптимизатором СУБД, который учитывает множество факторов — размер таблиц, тип используемых структур хранения данных, статистическое распределение данных в таблицах и индексах и т. д. Однако, чтобы оптимизатор смог использовать индексы, их нужно определить. Индексы используются для следующих целей:
О поддержка фраз UNIQUE и PRIMARY KEY;
О поддержка логической упорядоченности данных согласно значениям одного или нескольких столбцов;
О оптимизация выполнения запросов.
С точки зрения пользователя, индекс — это перечень столбцов таблицы, по которым записи этой таблицы логически упорядочиваются. С точки зрения СУБД, индекс — это механизм, позволяющий существенно увеличить скорость доступа
к записям по индексируемым столбцам, а также обеспечивающий эффективную проверку уникальности значений индексируемых столбцов.
Естественно, что поиск какого-либо значения путем последовательного перебора неупорядоченных данных будет во много раз медленнее, чем поиск с использованием упорядоченного списка (индекса). В одном индексе таблицу можно упорядочить по данным одного или нескольких столбцов. Таблица может иметь несколько индексов. Поэтому, несмотря на то, что индексы увеличивают объем базы данных, их следует использовать как для отдельных столбцов таблицы, так и для комбинации нескольких ее столбцов.
ПРИМЕЧАНИЕВ стандарте SQL ничего не говорится об индексах и о том, как их соз
давать. Они относятся к деталям реализации, выходящим за пределы стандарта..
Определение и удаление индекса
На практике большинство СУБД предоставляют возможность создавать индекс. Формы описания индексов отличаются, но их суть в различных СУБД одна и та же. Для построения индекса в Oracle существует предложение CREATE INDEX, имеющее следующий синтаксис:
CREATE [UNIQUE] INDEX имя_индекса ON имя_таблицы ( имя_столбца [ASC | DESC][, имя_столбца [ASC | DESC]...);
Например, отдельные индексы для столбцов Building и Name таблицы DEPARTMENT создаются следующим образом:
CREATE INDEX dep_1dx_bld ON DEPARTMENT (Building);
CREATE INDEX dep_idx_nam ON DEPARTMENT (Name);
Можно строить составной индекс, содержащий несколько столбцов. Например, предложение:
CREATE INDEX grp_idx_year_num ON SGROUP (Year. Num);
создает индекс в таблице SGROUP по столбцам Year и Num.
^) СС ВЕТ В составных индексах старайтесь сначала указывать наиболее часто используемые столбцы. Прибегайте к составным индексам, если указанные в них столбцы часто используются одновременно для указания условия выборки данных.
Индекс 'уникальный, если никакие две строки в индексируемой таблице не могут принимать одинаковое значение для индексируемого столбца (или комбинации столбцов) в одно и то же время. Для указания этого используется факультативная фраза UNIQUE. При ее отсутствии допускается повторение индексируемых значений. Например, предложение:
CREATE UNIQUE INDEX tch_idx_dep_nam ON TEACHER (DepFK, Name);
указывает, что в таблице TEACHER пары значений столбцов DepFK и Name должны быть неповторяющимися (уникальными). Отметим, что если определяется уни-
кальным составной индекс, составляющие его столбцы могут иметь повторяющиеся значения.
2> )ПРИМЕЧАНИЕ Невозможно создать уникальный индекс, если таблица уже имеет стро- —ки с повторяющимися значениями индексируемого столбца (столбцов). Лучший способ иметь дело с уникальными индексами состоит в том, чтобы создавать их сразу после определения таблицы и прежде, чем в нее введены какие-либо строки.
С помощью фраз ASC и DESC указывается порядок сортировки индексируемых столбцов: ASC — по возрастанию, DESC - по убыванию. Например, предложение:
CREATE INDEX fac_idx_nam_den ON FACULTY (Name DESC, Dean ASC);
указывает на необходимость индексирования таблицы FACULTY по столбцу Name в убывающем порядке, а по столбцу Dean — в возрастающем. По умолчанию всегда порядок сортировки в индексе предполагается возрастающим.
Если необходимость в ранее созданном индексе отпала, его можно удалить командой DROP INDEX, которая имеет следующий синтаксис:
DROP INDEX имя_индекса;
Удаление индекса не оказывает воздействия на содержимое столбцов. Далее приводятся команды для удаления всех созданных в этом разделе индексов:
DROP INDEX dep_1dx_bld:
DROP INDEX dep_1dx_nam;
DROP INDEX grpjdx_year_num;
DROP INDEX tch_idx_dep_nam;
DROP INDEX facjdx_nam_den:
Правила использования индексов
При использовании индексов следует руководствоваться следующими правилами.
О Для небольших таблиц индексы практически не приводят к повышению производительности.
О Индексы существенно повышают производительность, когда столбцы содержат в основном неповторяющиеся данные или много значений NULL.
О Индексы существенно оптимизируют выполнение запросов, которые выдают небольшое количество строк.
О Индексы повышают скорость поиска данных, однако замедляют процесс их обновления. Помните об этом, когда необходимо произвести одновременно обновление большого количества строк с индексами. В этом случае можно рассмотреть вариант, когда перед таким обновлением индекс уничтожается, а по завершении обновлений он опять восстанавливается.
О Помните, что индексы занимают определенное место в базе данных. Если СУБД позволяет управлять памятью, отводимой для базы данных, выделите часть памяти под индексы.
О Всегда индексируйте столбцы, которые используются для соединения таблиц. Это существенно увеличивает скорость соединения таблиц.
О Не индексируйте столбцы, которые регулярно подвергаются интенсивному обновлению.
О Если это возможно, не храните индексы и таблицы на одном и том же физическом устройстве. Разделение этих объектов снижает нагрузку на носители и приводит к более быстрому выполнению запросов.
О В больших таблицах поиск индексированных значений выполняется на порядок быстрее, чем поиск неиндексированных, а в очень больших таблицах — на два-три порядка.
Последовательности
В SQL существует очень важный с точки зрения практического использования баз данных механизм порождения уникальных значений, которые могут использоваться, например, для уникальной идентификации строк как одной, так и многих таблиц. Изучению этого механизма посвящен данный раздел.
Генератор последовательности
Генератор последовательности — это механизм порождения последовательных значений целого числового типа. Генератор последовательности является объектом базы данных. Генератор последовательности обязательно имеет имя и может иметь тип данных, который должен быть целым числом, то есть с масштабом О, минимальное значение, максимальное значение, начальное значение, значение приращения и признак, указывающий на возможность циклического генерирования значений.
Если приращение отрицательное, генератор последовательности является убывающим, в противном случае он возрастающий. Генератор последовательности имеет цикл, который представляет собой множество допустимых значений между минимальным и максимальным значениями. Генератор последовательности имеет текущее значение, которое при создании генератора устанавливается равным начальному значению. Характер завершения выполнения транзакций не влияет не текущее значение генератора. В схеме базы данных может быть определено много генераторов последовательностей. Описание генератора последовательности имеет следующий синтаксис:
CREATE SEQUENCE имя [AS тип]
[START WITH начало] [INCREMENT BY приращение]
[MAXVALUE максимум | NO MAXVALUE] [MINVALUE минимум | NO MINVALUE]
[CYCLE | NOCYCLE]
Значение его элементов описано ниже.
О имя — уникальное в базе данных имя генератора последовательности.
О тип — тип принимаемых последовательностью значений. Должен быть точным числовым типом с масштабом 0. В некоторых СУБД этот параметр отсутствует и по умолчанию предполагается, что генерируются целые числа.
О начало — начальное значение, принимаемое генератором последовательности. Должно быть между минимальным и максимальным значениями.
О приращение — величина приращения при генерировании следующего значения. Может быть положительным или отрицательным числом.
О максисмум — максимально допустимое значение генератора последовательности.
О минимум — минимально допустимое значение генератора последовательности.
О CYCLE и NOCYCLE — указание на возможность циклического генерирования значений последовательности. Если цикличность предусматривается, после достижения максимального (минимального) значения следующим генерируемым значением будет минимальное (максимальное). Если цикличность не предусматривается, после достижения максимума (минимума) выдается сообщение об ошибке.
Приведем пример определения последовательности.
CREATE SEQUENCE Fac_PRK_Seq
START WITH 1 INCREMENT BY 1 NOCYCLE;
Последовательность создана.
Последовательности, как правило, используют для создания значений столбцам, имеющим ограничения целостности первичного или уникального ключа.
Использование последовательности
Стандарт SQL определяет единственную функцию, применимую к последовательности, а именно получение ее следующего значения. Ее формат таков:
NEXT VALUE FOR имя_генератора_последовательности
Oracle определяет оперирование последовательностями через понятие псевдостолбцов с именами NEXTVAL (следующее значение) и CURRVAL (текущее значение), обращение к которым производится с использованием следующего синтаксиса:
имя_генератора_последовательности.NEXTVAL
имя_генератора_последовательности.CURRVAL
При первом обращении к NEXTVAL выводится начальное значение последовательности. При последующих обращениях к NEXTVAL возвращается значение, увеличенное на величину приращения. Это значение становится текущим. Обращение к CURRVAL приводит к возврату текущего значения.
Обратим внимание на один существенный момент в использовании NEXTVAL. В пределах одного предложения SQL производится однократное приращение значения последовательности для каждой строки таблицы. Если предложение содержит несколько обращений к NEXTVAL, то для текущей строки приращение производится только один раз, и для всех последующих вхождений NEXTVAL будет возвращаться одно и то же значение.
Наиболее подходящими местами использования этих функций являются:
О список фразы SELECT предложения SELECT;
О предложения INSERT и UPDATE.
Приведем пример использования этих функций в предложении SELECT.
SELECT Fac_PRK_Seq.NEXTVAL FROM DUAL;
NEXTVAL
1
SELECT Fac_PRK_Seq.NEXTVAL FROM DUAL;
NEXTVAL
2
SELECT Fac_PRK_Seq.CURRVAL FROM DUAL;
CURRVAL
2
Примеры использования генератора последовательности в предложениях INSERT и UPDATE будут рассмотрены через урок при изучении этих предложений.
Изменение и удаление генератора последовательности
Предложение ALTER SEQUENCE позволяет изменить свойства генератора последовательности. Стандарт SQL допускает изменение всех свойств последовательности за исключением ее имени и типа. Синтаксис следующий:
ALTER SEQUENCE имя
[RESTART WITH начало] [INCREMENT BY приращение]
[MAXVALUE максимум | NO MAXVALUE] [MINVALUE минимум | NO MINVALUE]
[CYCLE | NOCYCLE]
В Oracle не разрешается изменять начальное значение. Предполагается, что для изменения текущего значения сначала следует удалить последовательность и затем воссоздать ее с новым начальным значением. Удаление генератора последовательности производится следующей командой:
DROP SEQUENCE имя
Самостоятельная работа
В используемой вами СУБД создайте следующую таблицу:
CREATE TABLE FACULTY
(FacPKINTEGER.
NameVARCHAR(30),
DeanVARCHARC20),
BuildingCHARC5),
FundNUMBERC7. 2) DEFAULT 0);
Если указанных здесь типов данных в вашей СУБД нет, используйте подходящие типы.
Добавьте новый столбец CreateDate типа DATE.
Измените тип столбца FacPK на NUMBERC10).
Добавьте к столбцу Building значение по умолчанию *00000'.
Удалите столбец Dean.
Переименуйте таблицу на MY_FAC.
С помощью запроса создайте таблицу MY_FAC2, которая является точной копией таблицы MY-FAC.
В таблице MY_FAC создайте уникальный индекс по столбцам FacPK и Name, причем по возрастанию значений FacPK и убыванию значений Name.
Удалите созданный индекс.
Удалите таблицы MY_FAC и MY_FAC2.
Создайте генератор последовательности с такими свойствами: минимальное значение — 1000, максимальное значение — 2000, начальное значение — 1500, приращение1, цикличность не допускается.
Удалите созданный генератор последовательности.
Подведение итогов
Усвоив материал этого урока, вы научились:
0 определять таблицы базы данных;
0 изменять определение таблицы;
0 удалять определение таблицы;
0 определять, переопределять и удалять домены;
0 определять и использовать домены;
0 определять, переопределять и удалять генераторы последовательностей.
Определение УРОК ограничений
целостности
Этот урок посвящен ограничениям целостности - составной части определения таблицы. С их помощыЬ можно ограничить допустимые значения столбцов, совокупности столбцов, всей таблицы в целом или значений между таблицами. СУБД будет запрещать вводить или обновлять любые значения столбцов таблицы, нарушающие заданные ограничения целостности.
Виды ограничений целостности
Ограничения целостности используются для описания и поддержки действующих в предметной области ограничений на возможные значения данных. После определения ограничения целостности все данные в таблице должны соответствовать тем правилам, которые представлены в этом определении. При последующем выполнении команд SQL по модификации данных в таблице СУБД должна гарантировать, что результирующие данные удовлетворяют указанным ограничениям. Без использования ограничений целостности соответствующие правила, действующие в предметной области, пришлось бы поддерживать с помощью программных средств вашего приложения.
В предыдущем уроке уже были рассмотрены два вида ограничений на допустимые значения столбцов — типы данных и домены. Однако, хотя и тип данных, и домен выполняют функции ограничения на допустимые значения, формально они не относится к ограничениям целостности. Стандарт SQL допускает при определении таблиц базы данных специфицировать ограничения целостности следующих типов:
О [NOT] NULL — допускает или запрещает вставлять строки, которые содержат в столбце неопределенные значения;
О UNIQUE — разрешает вставлять в таблицу только такие строки, которые содержат уникальные значения столбца (столбцов);
О PRIMARY KEY — ограничение первичного ключа указывает, что все строки таблицы уникально идентифицируются значениями столбца (столбцов);
О FOREIGN KEY — ограничение внешнего ключа (или ссылочное) устанавливает, что значения столбца (столбцов) должны соответствовать значениям столбца (столбцов) другой таблицы;
О CHECK — позволяет задавать для столбца (столбцов) сложные условия на значение, которые должны соблюдаться при манипулировании строками таблицы.
Кроме того, стандарт SQL предоставляет возможность специфицировать самостоятельные, независимые от определения таблиц ограничения целостности, получившие название утверждений.
Ограничения целостности можно задавать для:
О столбца — это ограничение, которое специфицируется относительно значений конкретного столбца и указывается после определения типа данных столбца (но перед запятой);
О таблицы — это ограничение рассматривается как единое для группы столбцов и помещается в конец определения таблицы (после последнего имени столбца, но перед заключительной круглой скобкой).
ПРИМЕЧАНИЕ Ограничение столбца также может быть указано после определения столбцов, ведь по сути оно является и ограничением таблицы. Но в этом случае снижается наглядность, не говоря уже об эффективности.
Упрощенный вариант синтаксиса команды CREATE TABLE с указанием ограничений выглядит так:
CREATE TABLE имя_таблицы (
имя_столбца тип_данных ограничения_столбца[, имя_столбца тип_данных ограничения_столбца]... [. ограничение_таблицы]...);
Ограничение целостности как столбца, так и таблицы может предваряться фразой CONSTRAINT:
CONSTRAINT имя_ограничения
Она позволяет приписать ограничению имя, по которому в дальнейшем можно ссылаться на это ограничение, например, чтобы его удалить. Эта фраза не является обязательной.
Далее в этом уроке мы опишем ограничения целостности в интерпретации Oracle и, при необходимости, будем приводить особенности ограничений целостности в стандарте SQL, если они имеются.
Ограничение на отсутствие значения
Ограничение на отсутствие значения задается с помощью фразы NOT NULL и запрещает использовать в качестве значения столбца неопределенное значение, то есть специальное значение, которое использует СУБД для представления неизвестного или неприменимого значения.
ВНИМАНИЕ Это ограничение нельзя использовать как ограничение таблицы.
Вспомним, что NULL — это специальное обозначение, которое отмечает значение столбца как отсутствующее. Если указать фразу NOT NULL сразу после типа данных столбца, любая попытка поместить значение NULL в этот столбец будет отклонена. Синтаксис ограничения такой:
имя_столбца тип_данных [CONSTRAINT имя_ограничения] NOT NULL
Если фразы NOT NULL в определении столбца нет, SQL предполагает, что значение NULL разрешено (вы можете указать это явно путем задания ограничения NULL). Важно помнить, что для любого столбца с ограничением NOT NULL должно быть установлено значение в каждом предложении INSERT или UPDATE, применяемом к таблице.
При добавлении с помощью инструкции ALTER TABLE новых столбцов с ограничением NOT NULL к уже существующей таблице может возникнуть противоречие. Если к моменту добавления новых столбцов таблица не содержала строк, проблемы не будет. Но если строки уже существуют, какое значение должна поместить СУБД в создаваемые столбцы? Ведь они, в соответствии с ограничением NOT NULL, должны содержать значение в каждой строке. Одно из возможных решений — определить для таких столбцов значение по умолчанию.
СОВЕТ Обратитесь к документации конкретной СУБД, чтобы выяснить предоставляемые возможности решения. Например, в Oracle запрещено добавлять к таблице столбцы с ограничением NOT NULL, если таблица уже имеет строки.
Еще одна проблема возникает при добавлении ограничения NOT NULL для уже существующего столбца (снова при помощи инструкции ALTER TABLE). Если в таблице уже имеются строки, этот столбец уже может содержать значения NULL и тогда устанавливаемое ограничение NOT NULL входит в противоречие с текущими данными. Приведем пример использования ограничения NOT NULL для столбцов таблицы ♦DEPARTMENT:
CREATE TABLE DEPARTMENT
(DepPK INTEGER.
FacFK INTEGER NOT NULL.
Name VARCHARC30) CONSTRAINT dep_nnl_nam NOT NULL.
Head VARCHAR(20));*
В первом случае ограничение NOT NULL задано без указания имени ограничения, во втором — с именем.
Ограничение уникальности
Уникальность значения столбца — это ограничение, указывающее, что данный столбец (или группа столбцов) не может принимать одинаковых значений в пределах таблицы. В некоторых СУБД уникальность значений столбов поддерживается с помощью создания уникальных индексов, в других она задается независимо
от объявления индекса (хотя для того чтобы поддерживать уникальность столбца, для него, как правило, автоматически создается индекс).
Столбец (совокупность столбцов), принимающий уникальные значения, часто называют уникальным ключом. Если уникальным является один столбец, он называется простым уникальным ключом, а если несколько — составным уникальным ключом. Простой уникальный ключ может задаваться и как ограничение столбца, и как ограничение таблицы. Составной уникальный ключ задается только как ограничение таблицы. Для одной таблицы может быть определено несколько уникальных ключей.
Уникальность как ограничение столбца
Указание уникальности значений столбца имеет следующий синтаксис:
имя_столбца тип_данных [CONSTRAINT имя_ограничения] UNIQUE
В этом случае СУБД будет отклонять любую попытку ввода в этот столбец значения, которое уже существует в другой строке таблицы. Приведем пример определения уникальности как ограничения столбца:
CREATE TABLE FACULTY
(FacPK INTEGER, Name VARCHARC30) NOT NULL CONSTRAINT fac unq_nam UNIQUE, Dean VARCHARC20) CONSTRAINT fac_unq_den UNIQUE. Building CHAR(5), Fund NUMBER(7, 2));
Обратите внимание, что столбец Name имеет два ограничения: NOT NULL и UNIQUE. При необходимости определения для столбца нескольких ограничений целостности они могут описываться в произвольном порядке.
Уникальность как ограничение таблицы
Объявление группы столбцов как уникальной отличается от объявления уникальными одного или нескольких отдельных столбцов - для группы столбцов уникальной должна быть комбинация их значений, а не индивидуальные значения. Если определяется уникальность группы столбцов, каждый из столбцов этой группы уникальным может и не быть. Указание уникальности значений группы столбцов помещается после описания столбцов и имеет следующий синтаксис:
[CONSTRAINT имя_ограничения] UNIQUE (список_столбцов)
Рассмотрим следующий пример описания уникальности значения совокупности столбцов в таблице SGROUP:
CREATE TABLE SGROUP
(GrpPK INTEGER, DepFK INTEGER. Num NUMBERC3) NOT NULL. Year NUMBER(l) NOT NULL. CONSTRAINT grp_unq_num_^ar_dep UNIQUE (Num. Year, DepFK));
Заданное ограничение уникальности указывает, что на одной и той же кафедре (DepFK) не могут быть группы с одинаковыми номерами (Num) в пределах одного
курса (Year), однако сами номера групп, курсов и факультетов в пределах таблицы могут повторяться. Более того, могут повторяться комбинации значений любых пар из этих трех столбцов.
ПРИМ ЕЧ АН И ЕЕсли бы в номере группы должно было содержаться указание на курс
(как это делается обычно, например, номер 307 указывает, что это 7-я группа 3-го курса), столбец Year в ограничении уникальности был бы излишним.
Всякий раз, когда в конкретной предметной области вы обнаруживаете, что значение некоторой совокупности столбцов должно быть уникальным, проанализируйте, не являются ли уникальными значения поднаборов (или отдельных) столбцов из этой совокупности. Дело в том, что если значение некоторого поднабора столбцов является уникальным, то уникальным будет также значение всего набора Так, например, если группы нумеруются уникальными значениями, из этого автоматически следует уникальность значения совокупности трех указанных выше столбцов. В этом случае указание уникальности значения группы столбцов приведет к потере свойства предметной области (уникальности номеров).
Уникальность и неопределенные значения
Вопрос о том, как относиться к значениям NULL в уникальном ключе, не является однозначным. Как рассматривать ситуацию, когда две или более строк таблицы содержат NULL в уникальном ключе? Является ли это нарушением объявленного ограничения целостности или нет?
В некоторых СУБД значения NULL для уникальных ключей не допускаются - это означает, что ограничение UNIQUE автоматически подразумевает наличие или обязательно требует указания ограничения NOT NULL. В Oracle же уникальный ключ может содержать неопределенные значения, причем их повторение не означает нарушения ограничения уникальности - ведь NULL не равен никакому значению, в том числе самому себе. Если уникальный ключ составной, неопределенными могут быть значения как всех столбцов ключа, так и любых составляющих его столбцов. Однако строки, в которых имеется значение NULL для некоторых столбцов составного уникального ключа и одинаковые значения для остальных столбцов, нарушают ограничение уникальности.
Ограничение первичного ключа
Первичный ключ — это столбец (или совокупность столбцов) таблицы, который уникально идентифицирует строку таблицы. Первичный ключ очень похож на уникальный ключ — он тоже уникальный, может быть простым и составным, указываться как в описании столбца, так и для всей таблицы. Однако есть два существенных различия. Во-первых, уникальный ключ может принимать значения NULL, первичный ключ — нет. Во-вторых, таблица может содержать только один первичный ключ.
СОВЕТ Не все СУБД автоматически приписывают первичному ключу ограничение NOT NULL. Проверьте, требует ли ваша СУБД его явного указания.
Простой первичный ключ
Синтаксис ограничения первичного ключа имеет следующий вид:
имя_столбца тип__данных [CONSTRAINT имя_ограничения] PRIMARY KEY
Вот как, например, выглядит определение первичного ключа в таблице ROOM:
CREATE TABLE ROOM
(RomPKINTEGERCONSTRAINT rom_prk PRIMARY KEY.
NumNUMBERC3)NOTNULL.
Building CHAR(5)NOTNULL,
SeatsNUMBERO).
CONSTRAINT rom_unq_num_bld UNIQUE (Num. Building)):
Составной первичный ключ
Составной первичный ключ указывается после определения столбцов. Его синтаксис совпадает с определением уникального ключа, за исключением названия ограничения:•
[CONSTRAINT имя_ограничения] PRIMARY KEY (список_столбцов)
Если бы в таблице ROOM первичным ключом являлась пара столбцов Num и Bui 1 di ng, это нужно было бы записать следующим образом:
CREATE TABLE ROOM
(RomPK INTEGER NOT NULL UNIQUE.
Num NUMBERO),
Building CHARO),
Seats NUMBERO).
CONSTRAINT rom_unq_num_bld PRIMARY KEY (Num. Building));
Обратите внимание на два момента в приведенном примере. Во-первых, столбцу RomPK приписаны ограничения NOT NULL и UNIQUE — этим сохраняются ограничения на значение, свойственные первичному ключу. Во-вторых, убрано ограничение NOT NULL для столбцов Num и Building — в нем нет необходимости, так как в Oracle ограничение первичного ключа автоматически приводит к приписыванию ограничения NOT NULL.
СОВЕТСОВЕТЕсли в таблице имеется несколько столбцов (или их групп), которые являются уникальными по сути (например, номер экзаменационной книжки, серия и номер паспорта, идентификационный код), назначьте один из них (или одну группу) первичным ключом, а остальным припишите ограничения UNIQUE и NOT NULL.
СОВЕТ
СОВЕТ
Ограничение ссылочной целостности
SQL дает возможность поддерживать связь между таблицами с помощью так называемых внешних ключей. Одновременно они обеспечивают ссылочное ограничение целостности, которому посвящен данный раздел.
Внешний ключ и ссылочная целостность
Внешний ключ — это столбец (или совокупность столбцов), с помощью которого между строками двух таблиц устанавливается связь. Например, для связи между кафедрами (таблица DEPARTMENT) и факультетами (таблицы FACULTY) в таблице DEPARTMENT помимо столбцов данных кафедры существует дополнительный столбец FacFK, с помощью значений которого указывается, какому именно факультету принадлежит кафедра. Столбец (группа столбцов), на который ссылается внешний ключ, обычно называется ссылочным ключом. Таблица, из которой делается ссылка, называется дочерней, а та, на которую делается ссылка, - родительской (это может быть и одна таблица). Одна и та же таблица может иметь множество внешних ключей для установления связей с несколькими таблицами. Так, таблица LECTURE учебной базы данных имеет внешние ключи для связи с таблицами ROOM (столбец RomFK), SUBJECT (столбец SbjFK), TEACHER (столбец TchFK) и SGROUP (столбец GrpFK).
Внешний ключ допускает значения NULL, но их можно запретить установлением ограничения NOT NULL. Это необязательно и в большинстве случаев нежелательно. Предположим, например, что вы вводите сведения о преподавателе, не зная заранее, на какой кафедре он будет работать. Лучший выход в этой ситуации — использовать в качестве внешнего ключа значение NULL, которое в дальнейшем может быть изменено на значение первичного ключа нужной кафедры. Существует, однако, так называемая зависимость по существованию, когда объекты одного класса не могут существовать без объектов другого класса. Например, нет смысла говорить о занятии в расписании, если не определены ведущий его преподаватель, дисциплина, аудитория и группа. При наличии такой зависимости для внешнего ключа стоит определить ограничение NOT NULL.
Внешний ключ и его ссылочный ключ должны иметь одинаковое количество столбцов и одинаковые или совместимые типы данных для соответствующих столбцов. Внешний ключ, состоящий из одного столбца, называется простым, а из нескольких — составным. Чаще всего используются простые внешние и соответствующие им ссылочные ключи (как, например, в учебной базе).
Что же представляет собой ссылочное ограничение целостности? Когда вы объявляете столбец таблицы внешним ключом, вы фактически говорите, что каждое значение в этом столбце соответствует значению в другом столбце (ссылочном ключе). При этом, если значения ссылочного ключа уникальны, и только эти значения содержатся во внешнем ключе, говорят, что в базе данных по отношению к внешнему ключу поддерживается ссылочная целостность.
Например, каждая строка таблицы DEPARTMENT посредством своего внешнего ключа (столбец FacPK) должна ссылаться на одну строку таблицы FACULTY для указания факультета, которому принадлежит кафедра. Какое значение для этого следует поместить в столбце FacPK? Очевидно, такое, которое уникально идентифицирует факультет. Как мы уже знаем, таким свойством обладает первичный или уникальный ключ. Поэтому в качестве ссылочных ключей используются только такие столбцы (наборы столбцов).
Связывание внешнего ключа со ссылочным позволяет устанавливать между таблицами отношения один-к-одному и один-ко-многим. В нашем случае имеет место отношение один-ко-многим — на одном факультете может быть несколько
кафедр, но каждая кафедра принадлежит только одному факультету. Связь мно- гие-ко-многим (как если бы кафедра подчинялась нескольким факультетам) не может быть непосредственно представлена с помощью конструкции ссылоч- ный/внешний ключ.
Ссылочная целостность задается фразой FOREIGN KEY, в которой нужно указывать внешний и соответствующий ему ссылочный ключи. В этой фразе можно также указать, каким образом следует поддерживать ссылочную целостность в случае изменения или удаления одного из значений ссылочного ключа. Ссылочное ограничение, как и любое другое, задается в предложении CREATE TABLE и может быть определено как ограничение столбца или как ограничение таблицы.
Простой внешний ключ
Определение столбца как внешнего ключа имеет следующий синтаксис:
имя_столбца тип_данных [CONSTRAINT имя_ограничения] REFERENCES имя_родительской_таблииы [столбец_родительской_таблицы]
В этом случае роль ссылочного ограничения исполняет фраза REFERENCES. Например, связь между таблицами FACULTY и DEPARTMENT указывается в таблице DEPARTMENT следующим внешним ключом:
FacFK INTEGER CONSTRAINT dep_frk_fac REFERENCES FACULTY(FacPK)
Столбец родительской таблицы можно не указывать, если ссылочный ключ является в ней первичным, то есть имеющим ограничение PRIMARY KEY. Например, так как столбец FacPK является первичным ключом в таблице FACULTY, предыдущий пример может быть записан следующим образом:
FacFK INTEGER REFERENCES FACULTY
2/^ПРИМЕЧАНИЕ Данная возможность поощряет использование в качестве ссылочных ^именно первичных ключей. Тем не менее, ссылаться можно и на уникальные ключи.
Составной внешний ключ
Составной внешний ключ указывается после определения столбцов таблицы и имеет следующий синтаксис:
[CONSTRAINT имя_ограничения] FOREIGN KEY (список_столбцов_дочерней_таблицы) REFERENCES имя^одительской_таблицы [(список_столбцов_родительской_таблицы)]
Учитывая, что в учебной базе данных таблица ROOM содержит простой первичный ключ RomPK и составной уникальный ключ (Num, Building), из таблицы LECTURE можно сослаться на таблицу ROOM следующими двумя способами:
CREATE TABLE LECTURE
RomFK INTEGER.
CONSTRAINT lec fkey rom FOREIGN KEY (RomFK) REFERENCES ROOM(RomPK);
CREATE TABLE LECTURE
RomNumFK NUMBERO),
RomBldFK CHAR(5),
CONSTRAINT 1 ec_fkey_rom FOREIGN KEY (RomNumFK, RomBldFK) REFERENCES ROOMCNum, Building);
Обратите внимание, что в учебной базе данных в качестве первичных ключей используются столбцы, не соответствующие каким-либо реальным свойствам сущностей предметной области. Это сделано по следующим двум причинам.
О Во-первых, строки таблицы могут идентифицироваться двумя и более столбцами — в таблице ROOM, например, такими столбцами являются Num и Building. Если мы определим их как составной первичный ключ, в расписании занятий для ссылки на аудитории необходимо будет тоже использовать два столбца (как это сделано во втором варианте предыдущего примера). А если таких столбцов будет пять, то и во внешнем ключе нужно будет использовать пять столбцов. Такой способ связывания таблиц крайне неэффективен.
О Во-вторых, значения свойств сущности, включая и те, которые используются в качестве первичного ключа, могут изменяться. А всякое изменение значения первичного ключа влечет за собой необходимость изменения значения во всех тех строках внешних ключей, которые на него ссылаются.
Поэтому для первичного ключа мы рекомендуем искусственно добавлять в таблицу столбец, не имеющий никакой семантики с точки зрения предметной области. Для всех остальных столбцов или их наборов, которые являются первичными ключами по сути, следует приписать ограничения UNIQUE и NOT NULL.
Значения NULL в составном внешнем ключе
Наличие в составном внешнем ключе значений NULL вызывает неопределенность в трактовке того, соответствует ли такой ключ ссылочной целостности или нет. Стандарт SQL для этого случая предоставляет возможность уточнить способ использования значения NULL с помощью фразы MATCH, указываемой в предложении CREATE TABLE при описании ссылочного ключа. Она имеет простой синтаксис:
MATCH {SIMPLE | PARTIAL | FULL}
Вариант SIMPLE указывает, что значения NULL во внешнем ключе соответствуют ссылочной целостности. Вариант PARTIAL также допускает наличие во внешнем ключе значений NULL, однако соответствие ссылочной целостности будет соблюдено только в том случае, если все значения остальных столбцов равны значениям соответствующих столбцов ссылочного ключа. При варианте FULL значения NULL во внешнем ключе не допускаются.
Рекурсивные и перекрестные ссылки
SQL допускает, чтобы внешний ключ ссылался на ту же самую таблицу — такая ссылка называется рекурсивной. В этом случае в пределах одной таблицы можно смоделировать иерархические структуры, примерами которых являются родословное дерево, иерархия подчинения или так называемая структура разузлова- ния, указывающая, из каких агрегатов состоят агрегаты более высокого уровня.
Например, в учебной базе данных внешний ключ Chi ef таблицы TEACHER ссылается на первичный ключ этой же таблицы - эта рекурсивная ссылка позволяет определить иерархическую структуру подчинения преподавателей.
ВНИМАНИЕВНИМАНИЕВ этом случае для внешнего ключа нельзя указывать ограничение NOT NULL — хотя бы потому, что для преподавателя самого высокого уровня руководитель не определен.
ВНИМАНИЕ
ВНИМАНИЕ
Представляет интерес ссылка двух таблиц друг на друга, что называется перекрестной ссылкой. Предположим, например, что помимо уже рассмотренной связи между факультетами и кафедрами существует еще одна: «кафедра такая-то обслуживает учебный процесс на факультете таком-то». Например, кафедра иностранных языков обслуживает учебный процесс на многих факультетах, и на любом факультете занятия по иностранному языку ведут преподаватели только этой кафедры. Это еще одна связь один-ко-многим между кафедрами и факультетами, но уже с другой стороны — она требует наличия в таблице факультетов внешнего ключа, ссылающегося на первичный ключ таблицы кафедр. В этом случае связи между таблицами кафедр и факультетов можно записать следующим образом:
CREATE TABLE FACULTY
(FacPK INTEGER CONSTRAINT fac_prk PRIMARY KEY.
DepFK INTEGER CONSTRAINT fac_frk_dep REFERENCES DEPARTMENT.
CREATE TABLE DEPARTMENT
(DepPK INTEGER CONSTRAINT dep_prk PRIMARY KEY.
FacFK INTEGER CONSTRAINT dep_frk_fac REFERENCES FACULTY.
Перекрестные ссылки SQL поддерживает, но их использование может представлять проблему. Во-первых, для перекрестных ссылок нельзя использовать ограничение NOT NULL, так как в этом случае ни в одной из таблиц невозможно было бы создать ни одной строки. Во-вторых, для определения внешнего ключа в таблице FACULTY необходимо, чтобы таблица DEPARTMENT уже существовала. Но и наоборот тоже! В этом случае нужно поступить следующим образом.
Определить одну таблицу со всеми столбцами и ограничениями, кроме указания перекрестной ссылки.
Определить вторую таблицу со всеми столбцами и ссылками.
С помощью предложения ALTER TABLE добавить в первую таблицу перекрестную ссылку.
Поддержка ссылочной целостности
Рассмотрим, какие имеются возможности по поддержке ссылочной целостности при манипулировании строками родительской и дочерней таблиц. При вставке или обновлении строк дочерней таблицы СУБД проверяет, нарушают ли эти действия ссылочную целостность. Если это так, вставка/обновление строки запрещается. Удаление строки дочерней таблицы вообще не может привести к нарушению ссылочной целостности (если, конечно, она одновременно не является родительской для другой ссылки).
Вставка строки родительской таблицы не вызывает проблем с поддержкой ссылочной целостности (если, конечно, она одновременно не является дочерней для другой ссылки). А удаление или обновление ее строк может нарушить ссылочную целостность. Например, если удаляемый факультет имеет в своем составе кафедры, они останутся без факультета — их внешние ключи будут ссылаться на отсутствующий факультет. Для этого случая стандарт SQL предлагает несколько вариантов поддержки целостности, указываемых при определении внешнего ключа с помощью следующих конструкций:
ON DELETE {RESTRICT | CASCADE | SET NULL | SET DEFAULT}
ON UPDATE {RESTRICT ] CASCADE | SET NULL | SET DEFAULT}
Смысл этих вариантов следующий.
О RESTRICT — запрещается удалять строку (или изменять значение ссылочного ключа строки) родительской таблицы, если на эту строку имеются ссылки из дочерней таблицы.
О CASCADE — удаление строки в родительской таблице приводит к удалению всех связанных с ними строк дочерней таблицы. Изменение значения ссылочного ключа родительской таблицы приводит к соответствующему изменению значений внешних ключей дочерней таблицы.
О SET NULL - удаление строки (или изменение значения ссылочного ключа) родительской таблицы приводит к установке в значение NULL всех внешних ключей дочерней таблицы, которые ссылаются на удаленные (или измененные) значения ссылочного ключа родительской таблицы.
О SET DEFAULT — удаление строки (или изменение значения ссылочного ключа) родительской таблицы приводит к установке в значение по умолчанию всех внешних ключей дочерней таблицы, которые ссылаются на удаленные (или измененные) значения ссылочного ключа родительской таблицы.
В Oracle возможности поддержки ссылочной целостности беднее. Для случая обновления ссылочная целостность вообще не поддерживается, а при удалении строки родительской таблицы можно выбрать один из трех вариантов:
[ON DELETE {SET NULL | CASCADE}]
Смысл фраз SET NULL и CASCADE соответствует одноименным фразам в SQL, а отсутствие конструкции ON DELETE при определении внешнего ключа соответствует варианту RESTRICT.
Ограничение на значение
Для установки на значения столбцов ограничений, которые выплывают из их семантики, SQL предлагает фразу CHECK. В ней после ключевого слова CHECK можно в круглых скобках задать условие, которому должны удовлетворять вводимые в столбец значения. Любая попытка ввести для столбца значение, при котором условие оказывается ложным, будет отклонена. Фраза CHECK может указываться в определении столбца как его ограничение. В примерах ниже показано определение ограничения ставки в пределах 0-1000, а надбавки — в пределах 0-500:
Salary NUMERIC(4. 2) CHECK (Salary BETWEEN 0 AND 1000)
Rise NUMERICC3. 2) CHECK (Rise BETWEEN 0 AND 500)
Определение множества допустимых значений
Ограничение CHECK можно также использовать для указания списка допустимых значений. Например, в таблице LECTURE столбец Day может в качестве значения принимать только сокращенные названия дней недели. Такое ограничение может иметь следующий вид:
Day CHAR(3) CONSTRAINT lec_chkJay
CHECK (Day IN ('пнд', 'втр*. ‘срд’, 'чтв'. 'птн*. ’суб’, ’вое')
С помощью ограничения CHECK и оператора LIKE можно легко добиться ввода данных в определенном формате. Например, пусть необходимо представлять номера телефонов в следующем формате Х(ХХХ) XXX-XX-XX, где X — цифра номера телефона, а остальные символы должны присутствовать в том виде, в котором указаны. Этот формат можно представить следующим образом:
Tel CHAR(16) CHECK (Tel LIKE 'J) -_-__')
Задание условия на нескольких столбцах
Ограничение CHECK также можно использовать в качестве табличного. Это полезно в тех случаях, когда условие необходимо задать на значениях нескольких столбцов. Предположим, что надбавка профессоров находится в диапазоне 0-50 % от ставки. Это охраничение можно представить в виде ограничения таблицы:
CONSTRAINT TchSalRise
CHECK (Post о 'профессор' OR Rise BETWEEN 0 AND 0.5 * Salary)
Как видно из примера, чтобы определить истинность предиката, необходимо проверить значения трех столбцов. Обратите внимание, что проверяются значения разных столбцов одной и той же строки — нельзя проверить значения более чем в одной строке. Вы не можете использовать ограничение CHECK для того, например, чтобы указать зависимость надбавки одного ассистента от надбавок остальных.
Отложенная проверка ограничений
По умолчанию любое ограничение целостности, определенное в базе данных, проверяется при каждой попытке изменения ее содержимого. Но в стандарте SQL существует возможность указания и отложенной проверки ограничений. Такая проверка производится только после завершения транзакции (транзакции рассматриваются в уроке 17). Когда поступает команда COMMIT, свидетельствующая о завершении транзакции, СУБД проверяет все отложенные ограничения. Если все ограничения выполнены, транзакция завершается успешно. В противном случае происходит откат транзакции, то есть база данных возвращается в то состояние, которое она имела до начала выполнения транзакции.
Для управления возможностью откладывания проверки ограничения стандарт SQL при определении любого ограничения целостности позволяет использовать следующие фразы:
О DEFFERABLE — проверка ограничения может быть отложена до завершения транзакции;
О NOT DEFERRABLE — проверка ограничения не может быть отложена (обычно к этой категории относятся ограничения первичного и уникального ключей); этот вариант используется по умолчанию.
Обратите внимание, что эти фразы указывают, может ли быть отложена проверка соответствующего ограничения. Будет ли она действительно отложена при выполнении очередной операции, определяет СУБД.
Вместе с указанными атрибутами откладывания проверки можно одновременно указать, какое именно состояние принимает ограничение целостности сразу же после его определения, а также в момент инициирования любой транзакции:
О INITIALLY IMMEDIATE — ограничение проверяется после выполнения любой из команд манипулирования, затрагивающих изменение состояния этого ограничения;
О INITIALLY DEFERRED - ограничение проверяется только после выполнения завершения транзакции.
Так, например, можно записать следующее ограничение:
CONSTRAINT tch_chk CHECK (2 * Rise <= Salary) DEFERRABLE INITIALLY IMMEDIATE
Оно свидетельствует, что ограничение tch chk можно откладывать, но при запуске любой транзакции устанавливается его проверка после выполнения каждой операции.
Наконец, для ограничений, проверку которых можно отложить, предоставляется возможность перед выполнением конкретной операции манипулирования явно указать, следует ли проводить проверку немедленно или можно отложить. Для этого используется следующее предложение:
SET CONSTRAINTS {ALL | список_имен_ограничений} (DEFERRED | IMMEDIATE}:
В нем указывается либо перечень имен ограничений, либо фраза ALL, если это указание относится ко всем откладываемым ограничениям.
Изменение ограничений целостности
С помощью предложения ALTER TABLE можно осуществлять следующие переопределения таблиц, которые затрагивают ограничения целостности:
О добавлять новые ограничения (столбца и таблицы);
О удалять существующие ограничения (столбца и таблицы).
Изменять существующие ограничения целостности нельзя. Их нужно удалить и затем определить новые.
Добавление новых ограничений
К существующему столбцу можно добавлять только значение по умолчанию и ограничение NOT NULL. Все другие ограничения добавляются к столбцу в синтаксисе ограничений таблицы. Используйте следующий формат этой команды для добавления ограничения:
ALTER TABLE имя_таблицы MODIFY
имя_столбца (ограниченнее. ограничение]...);
Например, предложение:
ALTER TABLE TEACHER MODIFY
(IDCode CONSTRAINT tchjdc NOT NULL DEFAULT 'ШШШГ);
приводит к добавлению ограничения целостности ограничения NOT NULL и значения по умолчанию. Добавление ограничений таблицы описывается точно так же, как и добавление столбца:
ALTER TABLE ADD ограничение_целостности;
Например, предложения:
ALTER TABLE TEACHER ADD
CONSTRAINT tch_chk_1dc CHECK (IDCode <> '0000000000'):
ALTER TABLE TEACHER ADD UNIQUE (IDCode);
приводят к добавлению новых ограничений целостности к таблице TEACHER.
Удаление существующих ограничений
Удаление ограничений производится командой ALTER TABLE DROP, которая имеет три варианта:
ALTER TABLE имя_таблицы DROP PRIMARY KEY [CASCADE];
ALTER TABLE имя_таблицы DROP UNIQUE (столбецЕ, столбец]...) ECASCADE];
ALTER TABLE имя_таблицы DROP CONSTRAINT имя_ограничения;
Фраза CASCADE указывает, что необходимо автоматически удалять ссылочные ограничения целостности, которые используют удаляемое ограничение первичного или уникального ключа. Обратите внимание, что для удаления остальных ограничений необходимо указать их имя. В связи с этим рекомендуем при определении ограничений целостности всегда задавать имена. Приведем примеры удаления ограничений.
ALTER TABLE TEACHER DROP CONSTRAINT tch_chk_sal_ris2;
ALTER TABLE TEACHER DROP UNIQUE (IDCode);
Утверждения
Утверждение — это конструкция SQL, с помощью которой можно сформулировать ограничение целостности типа CHECK, заданное для столбцов нескольких таблиц базы данных. Утверждения, как и все другие ограничения целостности, проверяются при вставке, удалений и изменении строк тех таблиц, которые используются в утверждении. Утверждение является самостоятельным объектом базы данных, определяется вне определения других объектов и может быть самостоятельно удалено. Синтаксис создания утверждения следующий:
CREATE ASSERTION имя_утверждения
CHECK (условие) [отложенная_проверка]
В базе данных можно определить много утверждений. Ссылка на каждое из них, например для удаления, производится по имени. Условием во фразе CHECK может быть любое правильно сформулированное условие с использованием любых определенных в базе данных таблиц. В качестве возможных вариантов отложенной
проверки могут использоваться те же, что были описаны ранее для случая отложенной проверки ограничений целостности таблицы или ее столбцов. Приведем примеры утверждений:
О фонд финансирования любого факультета должен быть больше суммы фондов финансирования всех его кафедр:
CREATE ASSERTION FacFundAssert
CHECK (FACULTY.Fund > (SELECT SUM(DEPARTMENT.Fund)
FROM DEPARTMENT
WHERE DEPARTMENT.FacFK = FACULTY.FacPK))
О все преподаватели должны быть кураторами:
CREATE ASSERTION TchPKInAssert
CHECK (TEACHER.TchPK IN (SELECT SGROUP.CurFK FROM SGROUP))
Как и любой другой объект базы данных, утверждение может быть удалено. Это делается с использованием следующего синтаксиса:
DROP ASSERTION имя утверждения
Самостоятельная работа
Пересоздайте таблицу FACULTY учебной базы данных.
Добавьте определение нового столбца FoundationDate типа DATE, который не должен быть равным NULL.
Удалите ограничение целостности fac prk, а затем столбец FacPK.
Добавьте ограничение целостности PRIMARY KEY к столбцу Name.
Замените ограничение целостности fac_chk_fnd на следующее: Fund BETWEEN О AND 1000000.
Добавьте к столбцу Building ограничение NOT NULL.
Удалите столбец Dean.
Удалите таблицу FACULTY.
Пользуясь описанием структуры учебной базы данных, приведенной в приложении А, создайте все таблицы этой базы данных.
Подведение итогов
Усвоив материал этого урока, вы научились:
0 определять ограничения целостности в синтаксисе ограничения столбца и синтаксисе ограничения таблицы;
0 откладывать проверку ограничений целостности;
0 изменять ограничения целостности;
0 определять утверждения.
О) УРОКО) УРОКМанипулирование даннымиМанипулирование данными
О) УРОК
О) УРОК
Манипулирование данными
Манипулирование данными
В предыдущих уроках мы изучили возможности SQL по описанию структур таблиц базы данных. В этом уроке мы рассмотрим, каким образом осуществляется ведение данных в базе. Под ведением, или манипулированием, подразумевается ввод данных в базу данных, их редактирование и удаление. В теории баз данных эта составляющая называется языком манипулирования данными — ЯМД. В SQL имеются четыре предложения манипулирования данными:
О INSERT — вставка данных;
О UPDATE - обновление существующих данных;
О MERGE - вставка или обновление данных таблицы на основе строк, отобранных из другой таблицы;
О DELETE — удаление строк из таблиц.
Использование этих предложений по отношению к базовым таблицам является предметом данного урока. Манипулирование данными представлений описывается в уроке 14.
Добавление новых строк
Предложение INSERT вставляет строки в таблицу базы данных. Есть три разновидности этой команды:
INSERT VALUES
INSERT SELECT
INSERT DEFAULT VALUES
Первая из них производит вставку в таблицу явно заданной строки, вторая разновидность — вставку группы строк, выбранных в результате выполнения запроса, а третья — вставку значений по умолчанию.
Вставка отдельных строк
Предложение INSERT... VALUES выполняет вставку в таблицу одной строки. Его удобно использовать для небольших операций, когда в таблицу нужно вставить несколько строк. Синтаксис этого предложения следующий:
INSERT INTO имя_таблицы [(имя_столбца[, имя_столбца]...)]
VALUES (значениеЕ, значение]...);
Указание вставляемых столбцов
Этот формат предполагает указания имени таблицы, в которую производится вставка, списка имен столбцов, в которые будут вставляться значения, и списка собственно вставляемых в строку значений. При этом следует придерживаться следующих правил:
О вставляемые данные должны согласовываться с типами данных указанных столбцов;
О размеры данных должны соответствовать размерам столбцов;
О порядок данных во фразе VALUES должен соответствовать порядку перечисления столбцов.
Ниже приводится пример вставки одной строки в таблицу FACULTY:
INSERT INTO FACULTY (FacPK. Name, Dean, Building, Fund)
VALUES (1, ‘информатика’, 'Сидоров*, '6', 25000);
строка создана.
В таблицу вставляется строка со значениями, указанными в списке фразы VALUES, причем расположение значений в списке соответствует расположению соответствующих столбцов в списке столбцов таблицы. В этом примере мы перечислили столбцы в том порядке, в каком они были определены при создании таблицы, однако это не обязательно. При желании порядок перечисления имен столбцов в команде INSERT можно изменить, как это показано ниже на примере ввода еще одной строки в таблицу FACULTY:
INSERT INTO FACULTY (FacPK, Dean, Name, Fund, Building)
VALUES (2, 'Петров*, 'кибернетика', 27000, '5');
строка создана.
Список имен столбцов может быть не полным. Можно указывать только те из них, значения которых известны для вставляемой строки, Столбцы, отсутствующие в списке, будут принимать значения NULL для вводимой строки. В следующем примере в водимой строке отсутствуют значения столбцов Floor и Seats. В базе данных они примут значение NULL.
INSERT INTO ROOM (RomPK, Num, Building)
VALUES (17, 213, '8/5A');
строка создана.
Вставка неопределенных значений
Другой способ вставить значение NULL — указать его явно в списке VALUES, как это показано ниже:
INSERT INTO ROOM (RomPK. Num. Floor. Building)
VALUES (18. 217, NULL, '8/5A');
строка создана.
Здесь NULL — ключевое слово для обозначения отсутствующего значения. Если значение какого-либо столбца не известно, а его имя присутствует в списке, следует воспользоваться значением NULL. Оно указывается в списке VALUES как обычное значение. Так как NULL — это специальный символ языка, а не строковая константа, он не заключается в одиночные кавычки.
СОВЕТ Если во вводимой строке отсутствует значение столбца, ни в коем случае не вводите вместо него, например, 0 для числового значения или пустую строку ('') для символьного значения. Используйте для этого только NULL.
Стандарт SQL запрещает не указывать значение в списке VALUES, если оно равно NULL. Так, например, при попытке выполнить следующую команду вместо указанной в предыдущем примере вы получите уведомление об отсутствии значения и команда будет отклонена:
INSERT INTO ROOM (RomPK. Num. Floor. Building)
VALUES (18. 217, . *8/5A');
VALUES (18. 217, . '8/5A') *
ошибка в строке 2:
ORA-00936: отсутствует выражение
Поддержка ограничений целостности
Помните, некоторые из столбцов или наборов столбцов могут иметь ограничения целостности PRIMARY KEY и NOT NULL. Такие столбцы не могут принимать значения NULL. Попытайтесь, например, ввести следующую строку, и вы получите отказ с указанием, что столбец Num не может принимать значения NULL:
INSERT INTO ROOM (RomPK. Num. Floor, Building)
VALUES (22. NULL, 5. ЧПКУ.
INSERT INTO ROOM (RomPK, Num, Floor, Building) *
ошибка в строке 1:
0RA-O14OO: невозможно вставить NULL в ("VALERY"."ROOM"."NUM")
Приведенные выше рассуждения относятся ко всем ограничениям целостности, определенным для таблиц. При попытке ввода данных (как, впрочем, и при обновлении и удалении) СУБД проверяет возможное нарушение объявленных ограничений целостности. И если это так, команда будет отклонена с выдачей соответствующего уведомления. Попробуйте, например, ввести следующую строку,
и вы получите уведомление, что в связи с нарушением ограничения целостности rom unq num bld вставка строки не производится:
INSERT INTO ROOM (RomPK, Num, Floor. Building)
VALUES (27. 217. 2. '8/5A');
INSERT INTO ROOM (RomPK. Num. Floor. Building) *
ошибка в строке 1:
ORA-00001: нарушено ограничение уникальности (VALERY.ROM_UNQ_NUM_BLD)
Напомним: это ограничение указывает на то, что пара значений столбцов Num, Building должна быть уникальной, а мы в одном из предыдущих примеров уже ввели строку с такими значениями этих столбцов (217, 18/5А*).
Использование выражений
В качестве вставляемых значений могут использоваться выражения. Например, можно ввести следующую строку в таблицу TEACHER:
INSERT INTO TEACHER (TchPK. DepFK. Name. Salary. Rise. HireDate)
VALUES (77. NULL. 'Коробов'. 1271, 1271 / 3. SYSDATE-1):
строка создана.
Здесь мы указали, что надбавка равна третьей части ставки (1271 / 3), а дата приема на работу на один день меньше текущей даты (SYSDATE-1).
Результат запроса в качестве вставляемого значения
Вместо вставляемого значения можно использовать запрос. Это оказывается очень удобным в том случае, когда вставляемое значение присутствует в базе данных. Например, в следующем предложении в качестве корпуса вновь вставляемой аудитории выбирается корпус факультета информатики. *
INSERT INTO ROOM (RomPK, Num, Floor, Building)
VALUES (23, 999, 5, (SELECT Building FROM FACULTY WHERE LOWER(Name) = 'информатика')):
строка создана.
В запросе вы можете сослаться на ту же таблицу, в которую производите вставку. Например, в следующем запросе номер корпуса вновь вставляемой аудитории 888 выбирается равным номеру корпуса ранее введенной аудитории 999.
INSERT INTO ROOM (RomPK, Num, Floor, Building)
VALUES (25, 888, 5, (SELECT Building FROM ROOM
WHERE Num = 999)):
строка создана.
При использовании запроса нужно следить, чтобы он возвращал одну строку (одно значение), так как в противном случае вы получите сообщение об ошибке, как это показано в следующем примере.
INSERT INTO ROOM (RomPK. Num, Floor, Building)
VALUES (24, 888, 5, (SELECT Building FROM FACULTY
WHERE Fund >1000)):
VALUES (24, 888. 5. (SELECT Building FROM FACULTY *
ошибка в строке 2:
0RA-O1427: подзапрос одиночной строки возвращает более одной строки
Использование генератора последовательности
В уроке 11 мы изучили назначение генератора последовательности. Покажем теперь, как его можно использовать. В таблице ROOM столбец RomPK является первичным ключом, значения которого должны быть уникальными и не NULL. Можно эти значения формировать вручную, но можно воспользоваться генератором последовательности. Сначала определим его.
CREATE SEQUENCE Room_Seq;
Последовательность создана.
А теперь воспользуемся им для создания очередной строки этой таблицы.
INSERT INTO ROOM (RomPK. Num, Floor, Building)
VALUES (Room_Seq.NEXTVAL, 222, 2, 'll');
INSERT INTO ROOM (RomPK. Num, Floor, Building) *
ошибка в строке 1:
ORA-00001: нарушено ограничение уникальности (VALERY.ROM_PRK)
Ошибка произошла в связи с тем, что по умолчанию генератор последовательности начинает генерировать числа с 1. А у нас такой первичный ключ уже существует. Если мы используем генератор не с самого начала создания строк таблицы, следует посмотреть, какое максимальное значение первичного ключа уже существует и присвоить в качестве начального значения генератора большее значение. И после этого все оставшиеся строки таблицы можно создавать с помощью этого генератора. Поступим именно так.
DROP SEQUENCE Room_Seq;
Последовательность удалена.
SELECT MAX(RomPK) FROM ROOM;
MAX(ROMPK)
25
CREATE SEQUENCE Room_Seq START WITH 26;
Последовательность создана.
INSERT INTO ROOM (RomPK, Num, Floor, Building)
VALUES (Room_Seq.NEXTVAL, 222, 2, ЧГ);
строка создана.
А теперь посмотрим, что собой представляет созданная строка.
SELECT * FROM ROOM WHERE Num = 222;
ROMPK NUM FLOOR BUILD SEATS
26 22226 2222 112 11
26 222
26 222
2 11
2 11
Как мы и предполагали, первичный ключ созданной строки равен 26. Следующая созданная таким образом строка будет иметь первичный ключ 27 (по умолчанию приращение равно 1) и т. д.
Вставка значений всех столбцов
Если в списке VALUES присутствуют значения всех столбцов таблицы и в том порядке, в котором они были определены, список имен столбцов может отсутствовать. Приведем пример:
INSERT INTO FACULTY
VALUES (33. 'Карпов1, 'лингвистика'. 27660. '3/7');
строка создана.
СОВЕТ В случае использования SQL в программном коде настоятельно рекомендуем не опускать список имен столбцов. Во-первых, при наличии этого списка программу легче понимать, во-вторых, программа остается работоспособной при некоторых видах изменений структуры таблицы, например при добавлении в определение таблицы новых столбцов или удалении тех, которые в программе не используются.
Использование запроса при вставке строк
Вы можете вставлять не только явно задаваемые значения, но и те, которые образуются в результате вычисления запроса к существующей базе данных. Запрос может формировать множество строк, и все они вставляются при выполнении одной команды INSERT. Синтаксис этого варианта предложения следующий:
INSERT INTO имя_таблицы [(имя_столбца[. имя_столбца]...)] (запрос);
Приведем пример использования такой вставки строк. Создадим новую таблицу, которая будет содержать информацию о дисциплинах, читаемых ассистентами. Сначала определим такую таблицу:
CREATE TABLE TEACHER_NEW (
Tch_NewPK INTEGER CONSTRAINT Tch_New_PKC PRIMARY KEY.
Tch_Name VARCHAR(30)..
Sbj_Name VARCHAR(30));
Таблица создана.
Теперь определим генератор последовательности для автоматического формирования значений первичного ключа:
CREATE SEQUENCE Tch_New_Seq;
Последовательность создана.
Теперь можно заполнить эту таблицу на основании существующей в базе данных информации:
INSERT INTO TEACHER_NEW (Tch_NewPK, Tch_Name. Sbj_Name)
(SELECT Tch_New_Seq.NEXTVAL, t.Name. s.Name
FROM TEACHER t. LECTURE 1, SUBJECT s
WHERE t.TchPK = l.TchFK AND l.SbjFK = s.SbjPK AND LOWER(t.Post) = 'ассистент'):
строк создано.
Если вы посмотрите на результат, обратите внимание, что имеются строки-дубликаты. Мы демонстрируем возможности SQL на примере Oracle, который, к сожалению, запрещает использовать DISTINCT в списке фразы SELECT, если в нем имеется генератор последовательности. Поэтому, чтобы решить эту проблему, предлагаем разместить запрос, который выбирает необходимые данные и удаляет повторяющиеся строки, во фразе FROM, а во внешнем запросе воспользуйтесь генератором последовательности, как это показано в следующем запросе (но сначала удалим ранее созданные строки):
DELETE FROM TEACHER_NEW;
строк удалено.
INSERT INTO TEACHER_NEW (Tch_NewPK, Tch_Name. Sbj_Name)
(SELECT Tch_New_Seq.NEXTVAL. inq.t_Name, inq.s_Name
FROM (SELECT DISTINCT t.Name AS t_Name, s.Name AS s_Name
FROM TEACHER t, LECTURE 1. SUBJECT s
WHERE t.TchPK = l.TchFK AND l.SbjFK - s.SbjPK AND
LOWER(t.Post) = 'ассистент') inq):
строк создано.
SELECT * FROM TEACHER_NEW;
TCH_NEWPK TCH_NAMESBJ_NAME
Вибровский операционные системы
Воропаевпроектирование компьютеров
Козлутинохрана труда
Мартыновбазы данных
Обратите внимание, что генератор последовательности создал числа, начиная с 8. Дело в том, что первые семь чисел с 1 до 7 он использовал при предыдущем создании семи строк этой таблицы.
Вставка значений по умолчанию
Стандарт SQL допускает вставку целой строки, содержащей только значения по умолчанию, определенные для столбцов таблицы. Делается это с использованием следующего формата команды INSERT:
INSERT INTO имя_таблицы DEFAULT VALUES
Мы не сможем продемонстрировать на примере эту возможность, так как Oracle ее поддерживает. Oracle позволяет в списке фразы VALUES использовать ключевое слово DEFAULT вместо соответствующего значения, чтобы указать на необходимость вставки значения по умолчанию. Если соответствующий столбец не имеет значения по умолчанию, вставляется значение NULL. Покажем эту возможность на
примере. Сначала изменим определение таблицы TEACHER_NEW, добавив значения по умолчанию двум столбцам:
ALTER TABLE TEACHER_NEW MODIFY
(Tch_Name DEFAULT 'ОТСУТСТВУЕТ'.
Sbj_Name DEFAULT 'ОТСУТСТВУЕТ');
Таблица изменена.
Теперь вставим строку со значениями по умолчанию:
INSERT INTO TEACHER_NEW
VALUES (Tch_New_Seq.NEXTVAL, DEFAULT. DEFAULT);
строка создана.
И наконец, посмотрим, что за строка была введена:
SELECT * FROM TEACHER_NEW;
TCH-NEWPK TCH_NAME SBJ_NAME
Вибровский операционные системы
Воропаевпроектирование компьютеров
Козлутинохрана труда
Мартыновбазы данных
ОТСУТСТВУЕТ ОТСУТСТВУЕТ
Обновление существующих данных
Целью предложения обновления является изменение значений отдельных столбцов всех или удовлетворяющих указанному условию строк таблицы. Упрощенный синтаксис предложения следующий:
UPDATE имя_таблицы [[AS] синоним]
SET имя_столбца = выражением имя_столбца = выражение]...
[WHERE условие];
Его элементы означают следующее:
О имя_таблицы — имя обновляемой таблицы;
О синоним — синоним обновляемой таблицы для ссылки на нее в подзапросе;
О имя_столбца - имя обновляемого столбца;
О выражение — допустимое в SQL выражение соответствующего типа, значение которого присваивается обновляемому столбцу;
О условие — допустимое в SQL выражение условия, которое используется для отбора обновляемых строк.
По одному предложению UPDATE обновлению подвергаются строки только одной базовой таблицы.
Обновление всех строк
Как видно из определения синтаксиса команды UPDATE, фраза WHERE является факультативной. При ее отсутствии все строки таблицы подвергаются обновлению
согласно фразе SET. Например, для установки всем группам рейтинга 0 следует записать следующее выражение:
UPDATE SGROUP
SET Rating = 0:
5 строк обновлено.
Во фразе SET можно одновременно изменять значения нескольких столбцов таблицы. Например, в следующем примере всем преподавателям увеличивается ставка на 12 % и надбавка на 7 %:
UPDATE TEACHER
SET Salary = Salary + Salary * 0.12, Rise = Rise + Rise * 0.08:
15 строк обновлено.
Во фразе SET в правой части оператора присваивания может использоваться любое допустимое в SQL выражение того же типа, что и столбец, имя которого приведено слева от оператора присваивания. Если в этом выражении используется имя столбца целевой таблицы, для вычисления выражения применяется значение этого столбца в текущей строке, которое было перед обновлением. Например, после выполнения следующего запроса у всех преподавателей ставка будет равна 1500, а надбавка — половине ставки до изменения:
UPDATE TEACHER
SET Salary = 1500, Rise = Salary / 2:
15 строк обновлено.
Это, в частности, означает, что порядок выполнения присваиваний во фразе SET, если обновляются несколько столбцов, не существенен. Если порядок был бы существенен, это означало бы, что при вычислении надбавки бралось бы в расчет обновленное значение ставки, полученное предыдущим выражением. То есть надбавка стала бы равной 750.
Обновление по условию
Данный вариант использует фразу WHERE. В этом случае обновляются столбцы только тех строк таблицы, на которых выполняется условие фразы WHERE. Рассмотрим несколько примеров.
Запрос. Увеличить всем ассистентам зарплату и надбавку на 10 %:
UPDATE TEACHER
SET Salary = Salary * 1.1, Rise = Rise * 1.1
WHERE LOWER(Post) = 'ассистент':
4 строк обновлено.
Запрос. Установить, что деканат факультета математики переместился в корпус 7.
UPDATE FACULTY
SET Building = '7'
WHERE LOWER(Name) = 'математика':
1 строка обновлена.
ПРИМЕЧАНИЕ Обратите внимание, что символ = используется как во фразе SET, так и во фразе WHERE. Только в первом случае он выполняет функцию оператора присваивания, а во втором — предиката равенства
Запрос. Установить фонд финансирования кафедры баз данных равным 20 000:
UPDATE DEPARTMENT
SET Fund = 20000
WHERE LOWER(Name) = 'базы данных*;
2 строк обновлено.
В запросе с увеличением зарплаты ассистентам было очевидно, что изменять ставку и зарплату необходимо во многих строках таблицы TEACHER. Приведенные выше два запроса на обновление сформулированы так, что они имеют дело только с одной строкой (одним факультетом и одной кафедрой). В противном случае, например, второй запрос звучал бы следующим образом: «Установить всем кафедрам баз данных...». Итак, всякий раз, когда из формулировки запроса следует, что нужно обновить только одну строку таблицы, убедитесь, что заданное в запросе условие действительно отбирает одну строку.
Что касается запроса по перемещению деканата математики в другой корпус, то сформулированное в нем условие действительно выбирает единственную строку, так как в таблице FACULTY столбец Name имеет ограничение целостности UNIQUE (имена факультетов не могут повторяться). Однако, что касается кафедр, то их названия могут повторяться, так как значения этого столбца не уникальны. Действительно, в таблице имеется две кафедры с именем ‘базы данных* и у обеих изменился фонд. Так какой из них действительно нужно было изменить фонд финансирования?
Чтобы ответить на этот вопрос, мы должны посмотреть, имеется ли в таблице TEACHER уникальный ключ. Да, таким является пара столбцов Name, FacFK, то есть каждая кафедра уникально идентифицируется своих именем и факультетом (другими словами на факультете не может быть кафедр с одинаковыми названиями). Осознав этот факт, вы должны уточнить, какому именно факультету принадлежит требуемая кафедра баз данных (например, факультету кибернетики). После этого из таблицы FACULTY следует определить значение столбца FakPK этого факультета (в нашем случае это 2) И наконец, сформулировать запрос следующим образом:
UPDATE DEPARTMENT
SET Fund = 20000
WHERE LOWER(Name) = 'базы данных' AND FacFK = 2;
строка обновлена.
Теперь мы действительно обновили фонд одной кафедры.
Подзапросы во фразе WHERE
Во фразе WHERE можно использовать подзапросы, как мы это делали в предложении SELECT. Это дает возможность отбирать строки для обновления на основе информации из других таблиц. Например, предыдущее обновление фонда финансиро-
вания кафедры баз данных факультета кибернетики может быть записано следующим образом:
UPDATE DEPARTMENT
SET Fund = 20000
WHERE LOWER(Name) = 'базы данных' AND
FacFK = (SELECT FacPK FROM FACULTY
WHERE LOWER(Name) = 'кибернетика'):
строка обновлена.
Во фразе FROM подзапроса может присутствовать имя обновляемой таблицы. В этом случае предполагается, что используется то состояние обновляемой таблицы, которое она имела до обновления. Посмотрим, как это работает.
Запрос. Увеличить на 10 % фонды финансирования кафедр тех факультетов, у которых суммарный фонд финансирования их кафедр менее 50 000.
Сначала для справки посмотрим, кафедры каких факультетов удовлетворяют этому условию:
SELECT f.Name, SUM(d.Fund) FROM FACULTY f, DEPARTMENT d WHERE f.FacPK = d.FacFK GROUP BY f.name:
NAME SUM(D.FUND)
информатика 48000*
кибернетика 51100
Итак, наш следующий запрос должен обновить фонды кафедр только факультета информатики.
UPDATE DEPARTMENT
SET Fund = Fund *1.1
WHERE FacFK = (SELECT FacPK FROM FACULTY f
WHERE 50000 > (SELECT SUM(d.Fund) FROM DEPARTMENT d WHERE d.FacFK = f.FacPK));
строк обновлено.
Убедимся, что обновлены фонды только кафедр факультета информатики:
SELECT f.Name, SUM(d.Fund) FROM FACULTY f, DEPARTMENT d WHERE f.FacPK = d.FacFK GROUP BY f.name;
NAMESUM(D.FUND)
информатика 52800 кибернетика 51100
Действительно, только на факультете информатики изменились фонды кафедр и это изменение составило 10 %.
Подзапрос может не только использовать имя обновляемой таблицы, как это было показано в предыдущем примере, но и делать на нее внешнюю ссылку. В этом
случае подзапрос становится коррелированным с обновляемой таблицей. Такая внешняя ссылка делается на ту строку обновляемой таблицы, которая проверяется в текущий момент фразой WHERE. Внешняя ссылка обращается к значениям, которые имеет текущая строка до обновления. Приведем пример.
Запрос. Увеличить на 5 % фонд кафедр, на которых обучается более одной группы.
Сначала посмотрим, какие именно кафедры имеют более одной группы и какой у них фонд:
SELECT d.FacFK, d.Name, d.Fund FROM DEPARTMENT d
WHERE 1 < (SELECT COUNT(*) FROM SGROUP s WHERE s.DepFK = d.DepPK);
FACFK NAMEFUND
1 базы данных 26000
программирование 12000
Теперь запишем требуемое обновление:
UPDATE DEPARTMENT d
SET Fund = Fund *1.05
WHERE 1 < (SELECT COUNH*) FROM SGROUP s WHERE s.DepFK = d.DepPK);
строк обновлено.
Посмотрим, фонды тех ли кафедр были обновлены:
SELECT d.FacFK, d.Name, d.Fund FROM DEPARTMENT d
WHERE 1 < (SELECT COUNH*) FROM SGROUP s WHERE s.DepFK = d.DepPK);
FACFK NAMEFUND
1 базы данных 27300
1 программирование 12600
Все сделано правильно.
Подзапросы во фразе SET
До сих пор новые значения представляли собой константы или выражения с использованием значений обновляемой строки. Однако если такие значения присутствуют в других строках обновляемой таблицы или вообще в других таблицах, можно воспользоваться подзапросом. В этом случае допускается использовать две формы фразы SET:
SET {имя_столбца | (список_имен_столбцов)} = (подзапрос)
В обоих вариантах подзапрос должен возвращать одну строку. В первом случае он также должен возвращать значение одного столбца, а во втором возвращаемая строка должна содержать столько значений, сколько столбцов приведено в списке имен столбцов. При этом производится присвоение значений строки подзапроса соответствующим столбцам из списка слева.
Запрос. Установить всем ассистентам надбавку, равную 70 % текущей средней надбавки по вузу.
UPDATE TEACHER
SET Rise = (SELECT SUM(Rise) * 0.7 / COUNT(*) FROM TEACHER)
WHERE LOWER(Post) = 'ассистент';
строк обновлено.
Запрос. Установить всем ассистентам надбавку, равную 70 % надбавки их непосредственных руководителей.
UPDATE TEACHER tl
SET Rise = (SELECT Rise * 0.7 FROM TEACHER t2
WHERE tl.Chief = t2.TchPK)
WHERE LOWER(tl.Post) = 'ассистент';
строк обновлено.
Подзапрос является коррелированным с внешним запросом на обновление. Более того, он делает внешнюю ссылку на обновляемую таблицу. Эта ссылка делается на значения обновляемой строки, которые она имеет до выполнения операции ее обновления.
Запрос. Установить преподавателю Лекарю ставку, равную 80 % ставки его непосредственного руководителя, а надбавку — 90 % надбавки его непосредственного руководителя.
UPDATE TEACHER tl
SET (Salary, Rise) = (SELECT Salary * 0.8, Rise * 0.9 FROM TEACHER t2
WHERE tl.Chief = t2.TchPK)
WHERE UPPER(tl.Name) = 'ЛЕКАРЬ';
строка обновлена.
Обновление нескольких таблиц
К сожалению, в одном запросе невозможно обновить более одной таблицы. Например, если номер корпуса 5 изменился на 12, такое обновление следует произвести в трех таблицах (FACULTY, DEPARTMENT и ROOM) с помощью трех команд UPDATE:
UPDATE FACULTY
SET Building = *12'
WHERE Building = ' 5':
UPDATE DEPARTMENT
SET Building = '12'
WHERE Building = ' 5':
UPDATE ROOM
SET Building = *12'
WHERE Building = '5';
Эти обновления приводят к временному нарушению целостности базы данных (в одних таблицах значение уже обновлено, а в других — нет). Как ее поддерживать, описывается в уроке 17 при рассмотрении транзакций.
Использование значений NULL и DEFAULT
С помощью фразы SET можно присваивать неопределенные значения требуемым столбцам.
Запрос. В таблице ROOM убрать указание этажа для аудиторий 6-го корпуса:
UPDATE ROOM SET Floor = NULL WHERE Building = '6':
строк обновлено.
Неопределенное значение может использоваться и в условии фразы WHERE. Запрос. В таблице ROOM установить равным 5 этаж для всех аудиторий корпуса 3, у которых значение этажа не определено.
UPDATE ROOM SET Floor = 5 WHERE Building = '3' AND Floor IS NULL;
О строк обновлено.
При обновлении столбцам можно устанавливать значения по умолчанию. Для этого используется ключевое слово DEFAULT.
Запрос. Всем профессорам установить значение по умолчанию для надбавки.
UPDATE TEACHER
SET Rise = DEFAULT WHERE LOWER(Post) = ’профессор';
строк обновлено.
Посмотрим, что получилось в результате обновления.
SELECT Name, Rise FROM TEACHER WHERE LOWER(Post) = 'профессор';
NAME RISE
Сидоров0
РезванО
Ахромеев О
Обновление представлений
С помощью предложения UPDATE могут обновляться и представления. Для этого достаточно указать имя представления вместо имени базовой таблицы. Что такое представления и как они обновляются, описано в уроке 14.
Слияние данных
Предложение MERGE используется для выбора строк из одной таблицы с целью обновления или вставки строк в другую таблицу. Выбор действия — обновить строку или добавить ее — определяется заданным условием. Это предложение, по
сути, представляет собой объединение двух операций — вставки и обновления. Предложение MERGE позволяет избежать многократного использования предложений INSERT и UPDATE. Синтаксис предложения MERGE следующий:
MERGE INTO целевая_таблица [[AS] синоним]
USING исходная_таблица [[AS] синоним]
ON (условие)
WHEN MATCHED THEN обновление.
WHEN NOT MATCHED THEN вставка;
Фраза обновление имеет следующий формат:
UPDATE SET столбец = выражение[. столбец = выражение]...
а фраза вставка имеет такой формат:
INSERT (список_столбцов) VALUES (список_выражений)
Остальные элементы предложения означают следующее:
О целевая^таблица - таблица, которая подвергается обновлению и/или вставке строк;
О исходная таблица — таблица, на основании которой производится обновление или вставка строк целевой таблицы; может быть представлена в виде базовой таблицы, представления или подзапроса;
О условие — предикат для определения, следует ли проводить обновление или вставку строк.
Предложение MERGE работает следующим образом. Выбирается очередная строка исходной таблицы и проверяется, существует ли такая строка целевой таблицы, что на ней становится истинным условие фразы ON. Если да — то производится обновление этой строки целевой таблицы согласно фразе обновления. Если таких строк целевой таблицы несколько, все они обновляются. Если для текущей строки исходной таблицы условие фразы ON равно FALSE для всех строк результирующей таблицы, то в результирующую таблицу вставляется строка согласно фразе вставки.
Приведем пример. Допустим, было принято решение вести отдельную таблицу по надбавкам преподавателям кафедры программирования. Прежде всего создадим такую таблицу:
CREATE TABLE BONUSES (
Tch_ID INTEGER,
Tch_Name VARCHAROO),
Tch_Rise NUMBER(6, 2) DEFAULT 100):
Таблица создана.
Сначала было принято решение установить всем преподавателям кафедры программирования, у которых более одной пары в расписании, базовую надбавку в размере установленного в базе данных значения по умолчанию. В связи с этим таблица BONUSES заполняется следующим образом:
INSERT INTO BONUSES (TchJD, Tch_Name)'
(SELECT t.TchPK, t.Name FROM TEACHER t, DEPARTMENT d
WHERE t.DepFK = d.DepPK AND
LOWER(d.Name) = ’программирование' AND
1 < (SELECT COUNT(*) FROM LECTURE 1 WHERE t.TchPK = l.TchFK));
9 строк создано.
Проверим результат:
SELECT * FROM BONUSES;
TCHJD
TCH_NAME
TCH-RISE
4
Рамишевский
100
2
Хоренко
100
1
Вибровский
100
3
Воропаев
100
5
Кузинцев
100
7
Лекарь
100
9
Мартынов
100
10
Резван
100
11
Недеведеев
100
Затем ответственным руководством было принято следующее решение. Для тех, у кого менее двух пар, установить надбавку в размере 150. Для преподавателей, имеющих две и более пары к надбавке добавить такие значения:
О ассистентам - 50 % ставки,
О преподавателям - 55 % ставки,
О доцентам — 60 % ставки,
О профессорам — 65 % ставки.
Вот как будет выглядеть требуемое предложение слияния.
MERGE INTO BONUSES b
USING (SELECT TchPK, Name, Salary, Post FROM TEACHER
WHERE DepFK = (SELECT DepPK
FROM DEPARTMENT
WHERE LOWER(Name) = 'программирование')) t
ON (b.TchJD = t.TchPK)
WHEN MATCHED THEN UPDATE
SET b.Tch_Rise =
CASE LOWER(t.Post)
WHEN 'ассистент'THEN b.Tch_Rise +t.Salary* 0.5
WHEN 'преподаватель' THEN b.Tch_Rise +t. Sal ary*0.55
WHEN 'доцент*THEN b.Tch_Rise +t.Sal ary* 0.6
WHEN 'профессор'THEN b.Tch_Rise +t. Sal ary*0.65
END
WHEN NOT MATCHED THEN INSERT (b.TchJD, b.Tch_Name, b.Tch_R1se)
VALUES (t.TchPK. t.Name, 150):
12 строк объединено.
Посмотрим, что собой представляет результирующая таблица.
SELECT * FROM BONUSES:
TCHJD TCH_NAME TCH_R1SE
4 Рамишевский2 Хоренко4 Рамишевский2 Хоренко598468.5598468.5
4 Рамишевский
2 Хоренко
4 Рамишевский
2 Хоренко
598
468.5
598
468.5
1 Вибровский
385
3 Воропаев
385
5 Кузинцев
446,5
7 Лекарь
634
9 Мартынов
365
10 Резван
815
11 Недеведеев
413,5
8 Козлутин
150
16 Сидоров
150
6 Завратинский
150
Как видим, в ранее существовавших в этой таблице девяти строках соответствующим образом изменена надбавка и, кроме того, добавились три новые строки для преподавателей, имеющих менее двух пар в расписании.
Удаление существующих строк
Удалять строки из таблицы можно с помощью предложения DELETE. Оно удаляет только строки целиком, а не индивидуальные значения столбцов. Синтаксис команды следующий:
DELETE FROM имя_таблицы [[AS] синоним]
[WHERE условие]:
При использовании предложения DELETE вы прежде всего обнаружите, что предупреждающая подсказка, как правило, не выдается. Обычно, когда пользователь удаляет какой-либо объект операционной среды, он получает сообщение типа «Вы уверены (Д/Н)?». В системах, поддерживающих SQL, строки удаляются без такого сообщения. Поэтому будьте внимательны.
В зависимости от применения фразы WHERE предложение DELETE позволяет удалить отдельную строку, несколько или все строки таблицы. Строки могут быть и не удалены. При использовании предложения DELETE помните о следующем:
О нельзя удалить значение отдельного столбца (используйте для этого предложение UPDATE);
О как и предложения INSERT и UPDATE, удаление строк может нарушить ограничения целостности;
О сама таблица не удаляется (используйте для этого предложение DROP TABLE).
Удаление всех строк таблицы
Чтобы удалить все содержимое таблицы, не нужно использовать фразу WHERE. Помните, что вы удаляете не саму таблицу, а только все ее строки.
Запрос. Удалить содержимое таблиц LECTURE.
DELETE FROM LECTURE:
22 строк удалено.
Удаление по условию
Обычно нужно удалять только некоторые строки из таблицы. Чтобы определить, какие строки будут удалены, нужно использовать условие во фразе WHERE. Приведем несколько примеров.
Запрос. Из таблицы LECTURE удалить те строки, которые имеют отношение к занятиям, проводящимся в субботу и воскресенье.
DELETE FROM LECTURE
WHERE LOWER(Day) ='суб' OR LOWER(Day) ='boc';
О строк удалено.
Запрос. Удалить сведения об ассистентах, которые были приняты на работу до 01.01.2003.
DELETE FROM TEACHER
WHERE LOWER(Post) ='ассистент' AND
Hiredate < DATE 12003-01-011;
DELETE FROM TEACHER
*
ошибка в строке 1:
ORA-01407: невозможно заменить ("VALERY"."LECTURE"."TCHFK") на NULL
Мы попытались удалить строку таблицы преподавателей, на которую имеется ссылка из таблицы LECTURE. Для этой ссылки (столбец TchFK) было определено, что она должна устанавливаться в NULL в этом случае. С другой стороны, этот столбец имеет ограничение NOT NULL, что и привело к выводу сообщения об ошибке в предыдущем запросе.
Удаление одной строки
Чтобы удалить одну конкретную строку, нужно сформулировать условие таким образом, чтобы Оно идентифицировало эту единственную строку. Обычно для этого в условии используются первичный ключ таблицы или уникальный набор столбцов.
Запрос. Удалить аудиторию с первичным ключом 120.
DELETE FROM ROOM
WHERE RomPK - 120;
Здесь RomPK — первичный ключ в таблице ROOM.
Запрос. Удалить факультет под названием ’математика*.
DELETE FROM FACULTY
WHERE LOWER(Name) = 'математика';
1 строка удалена.
Столбец Name в таблице FACULTY является уникальным ключом.
Запрос. Удалить кафедру 'базы данных', принадлежащую факультету с первичным ключом 2.
DELETE FROM DEPARTMENT
WHERE LOWER(Name) = 'базы данных' AND FacFK = 2;
строка удалена.
В таблице DEPARTMENT пара столбцов Name и FacFK составляют уникальный ключ.
Использование запросов
Как и при вставке и обновлении, во фразе WHERE предложения DELETE можно использовать подзапросы, которые могут быть как простыми, так и коррелированными.
Запрос. Из таблицы SGROUP удалить группы, у которых нет кураторов и которых нет в расписании.
DELETE FROM SGROUP s
WHERE CurFK IS NULL AND
NOT EXISTS (SELECT * FROM LECTURE 1
WHERE s.GrpPK = l.GrpFK):
строка удалена.
Поддержка целостности при манипулировании данными
Как мы уже отмечали, при выполнении операций вставки, удаления и замены может нарушаться целостность базы данных. В этом случае производится отказ в выполнении соответствующей команды с выдачей предупреждающего сообщения. Кратко опишем, в каких случаях операции манипулирования могут нарушать целостность при определении столбца с разными ограничениями.
О NOT NULL — предложения INSERT и UPDATE будут отклонены, если они присваивают такому столбцу значение NULL явно или по умолчанию.
О UNIQUE — предложения INSERT и UPDATE будут отклонены, если они присваивают такому столбцу значение, которое уже присутствует в таблице. Если UNIQUE определено для группы столбцов, это означает уникальность всех значений из этих столбцов в совокупности. Также для столбца (группы столбцов) с ограничением UNIQUE будет отклонено предложение DELETE, если на удаляемое значение этого столбца имеется обязательная ссылка из другой таблицы (имеется ссылка внешнего ключа другой таблицы).
О PRIMARY KEY — предложения INSERT и UPDATE будут отклонены, если они присваивают такому столбцу (или любому столбцу из группы) значение NULL, явно или по умолчанию, или нарушается уникальность значений этого столбца (группы столбцов) в пределах таблицы. Также будет отклонено предложение DELETE, если на удаляемое значение этого столбца имеется обязательная ссылка из другой таблицы (имеется ссылка внешнего ключа другой таблицы).
О FOREIGN KEY - предложения INSERT и UPDATE будут отклонены, если они присваивают такому столбцу (группе столбцов) значение, которое отсутствует среди множества значений того столбца, на который делается ссылка.
О CHECK — вставка, удаление строки или замена значения столбца будут отклонены, если они нарушают условие.
Наконец, отметим, что конкретные СУБД могут иметь свои дополнительные ограничения. Также отметим, что реакция на нарушения целостности может быть не во всех СУБД тождественной.
Импорт и экспорт данных
Предложения INSERT, DELETE и UPDATE являются чрезвычайно важными для их использования в программах, работающих с базами данных. Эти команды, совместно с SELECT, образуют основу оперирования базами данных. Однако SQL не обладает средствами экспорта и импорта данных из других источников. Например, предположим, что компания на протяжении многих лет вела базу данных в СУБД ACCESS. В связи с растущими потребностями в распределенной обработке данных в клиент-серверной архитектуре появилась необходимость в использовании другой более мощной СУБД, например Oracle. Если ваша исходная база данных слишком большая, следует приложить огромные усилия, чтобы с помощью команды INSERT загрузить в Oracle существующую в ACCESS базу данных. Очевидно, что команды INSERT, DELETE и UPDATE становятся полезными, когда база данных уже загружена, однако вряд ли вы захотите ввести вручную 400 000 команд INSERT, чтобы перезагрузить существующую базу данных.
Эта проблема решается намного проще в связи с тем, что большинство современных СУБД предоставляют средства экспорта/импорта баз данных. Одни СУБД имеют в своем составе программы-конверторы между собственным форматом хранения данных и форматами баз данных других СУБД. В этом случае при инициировании диалога импорта данных предоставляется возможность указать формат базы данных, из которой будет производиться импорт. Другие СУБД позволяют импортировать и экспортировать данные, используя формат текстовых файлов. Например, СУБД Microsoft Access позволяет экспортировать/импортировать текстовые файлы и файлы форматов баз данных dBASE, FoxPro и SQL Database: Microsoft SQL Server — текстовые файлы специального формата, a Oracle — данные из текстовых файлов, представляющих записи переменной или фиксированной длины.
Самостоятельная работа
В таблицу FACULTY введите строки из учебной базы данных.
В таблицу DEPARTMENT введите строки из учебной базы данных.
В таблицу DEPARTMENT введите строку, содержащую только значения столбцов DepPK, FacFK, Name.
Попытайтесь в таблицу DEPARTMENT ввести строку, которая содержит те же значения FacFK, Name, которые использовались на предыдущем шаге. Почему вы получили отказ?
Попытайтесь в таблицу DEPARTMENT ввести строку, которая содержит NULL для столбца DepPK. Почему вы получили отказ?
Попытайтесь в таблицу DEPARTMENT ввести строку, которая содержит NULL для столбца FacFK. Почему вы получили отказ?
Попытайтесь в таблицу DEPARTMENT ввести строку, которая содержит -23700 для столбца Fund. Почему вы получили отказ?
Измените на 270 000 фонд финансирования кафедры «базы данных» факультета, имеющего значение первичного ключа 2.,
Увеличьте фонд финансирования всех кафедр факультета, имеющего значение первичного ключа 2, на 20 %.
Во всей таблице DEPARTMENT поменяйте корпус под номером *3' на корпус с номером ’12А/7'.
И. Для кафедры «программирование» установите значение столбца DepPK равным 4. Почему вы получили отказ?
Удалите все строки таблицы DEPARTMENT, которые относятся к факультету с первичным ключом 2.
Удалите все оставшиеся строки таблицы DEPARTMENT. Удалите строки из таблицы FACULTY.
Если вы самостоятельно ввели строки в другие таблицы, удалите все эти строки.
Во все таблицы учебной базы данных введите строки, приведенные в приложении А.
Подведение итогов
Усвоив материал этого урока, вы научились:
0 вставлять в таблицу базы данных отдельные строки, содержащие значения всех столбцов таблицы;
0 вставлять в таблицу базы данных отдельные строки, содержащие значения не всех столбцов таблицы;
0 вставлять строки, содержащие значения NULL;
0 изменять порядок перечисления значений столбцов во вставляемых строках;
0 использовать в качестве вставляемых значений выражения;
0 обновлять значения столбцов во всех строках таблицы;
0 обновлять значения столбцов в выборочных строках таблицы;
0 использовать значение NULL при обновлении;
0 производить слияние строк;
0 удалять все строки таблицы;
0 удалять выборочные строки таблицы;
0 удалять единственную строку таблицы.
О УРОК Представления
Таблицы, с которыми мы имели дело до сих пор, называются базовыми. Это таблицы, которые содержат данные. Однако имеется другой вид таблиц — представления. Это виртуальные таблицы, которые актуализируются в результате выполнения указанного запроса на выборку данных. Представление с точки зрения определения — это именованный запрос, который сохраняется, как и другие объекты базы данных, а с точки зрения использования - это обычная таблица. Представления можно использовать в запросах и операторах НМД точно так же, как и базовые таблицы, но они не содержат никаких собственных данных. Представления подобны окнам, через которые вы просматриваете информацию, фактически хранящуюся в базовых таблицах. Представление — это запрос, который выполняется всякий раз, когда к нему производится обращение. Таблица, получающаяся в результате выполнения запроса, становится содержанием представления. Базовые таблицы, которые участвуют в формировании представления, называются исходными.
Создание представления
Представление создается предложением CREATE VIEW. Нельзя определить никаких свойств столбцов представления, кроме их имен. Синтаксис создания представления следующий:
CREATE VIEW имя_представления [(список_имен_столбцов)] AS предложение_5Е1ЕСТ
[WITH [CASCADE | LOCAL] CHECK OPTION];
Таким образом, представление — это именованная таблица, получаемая в результате выполнения предложения SELECT, с возможным изменением имен столбцов. Ниже мы рассмотрим все варианты создания и использования представлений.
Простое представление
Под простым подразумевают представление, являющееся копией исходной таблицы, но под другим именем.
CREATE VIEW FACULTY_COPY AS
SELECT * FROM FACULTY;
Этим мы создали представление FACULTY_COPY, являющееся точной копией таблицы FACULTY. Можно также создавать представления на основе других представлений. К представлению можно обращаться точно так же, как и к любой другой базовой таблице. К нему можно обратиться для выборки данных, представление можно изменить, в него можно вставить новые строки и удалить существующие, оно может быть соединено с другими базовыми таблицами и/или представлениями. Так, например, если выполнить запрос:
SELECT * FROM FACULTY__COPY;
то предварительно будет выполнен тот запрос, на основании которого определено само представление, и, согласно нашему запросу, все строки полученной таблицы представления будут выведены. Имея условие в запросе, можно выводить только определенные строки представления, например:
SELECT *
FROM FACULTY_COPY
WHERE Fund > 24000;
FACPK NAME DEAN BUILD FUND
1 информатика Сидоров 625000
2 кибернетика Петров 527000
Представление изменяется автоматически всякий раз, когда изменяется лежащая в его основе исходная таблица. Содержимое представления не фиксировано и формируется каждый раз, когда вы ссылаетесь на него. Если вы добавите еще один факультет в таблицу FACULTY базы данных, он автоматически появится в представлении FACULTY J)OPY.
Выбор столбцов и строк исходной таблицы
Представления значительно расширяют управление вашими данными. Это превосходный способ дать публичный доступ к некоторой, но не всей информации в таблице и представить ее в форме, удобной пользователю. В зависимости от характера выбираемых из исходной таблицы данных представления подразделяют на горизонтальные, вертикальные и смешанные. Горизонтальное представление содержит все столбцы исходной таблицы, но только часть ее строк.
Запрос. Создать представление, содержащее данные только о профессорах.
CREATE VIEW PROFESSORS AS
SELECT * FROM TEACHER
WHERE LOWER(Post) = 'профессор';
Представление создано.
Если представить, что таблица содержит в себе сведения о сущностях предметной области определенного класса, то горизонтальное представление позволяет отобрать полную информацию только о части сущностей этого класса.
Запрос. Создать представление, содержащее расписание занятий в понедельник первой недели.
CREATE VIEW LECT_ON_MON_1WEEK AS
SELECT * FROM LECTURE
WHERE LOWER(Day) = 'пид* AND Week - 1:
Представление создано.
Теперь, используя это представление, можно выражать в SQL различные запросы.
Запрос. Вывести расписание занятий в понедельник первой недели.
SELECT * FROM LECT_ON_MON_1WEEK;
TCHFK GRPFK SBJFK ROMFK TYPE WEEK DAY LESSON
1111 лаб 1 пнд 1
2112 лекц 1 пнд 2
Запрос. Вывести фамилии преподавателей, которые имеют занятия в понедельник первой недели.
SELECT t.Name FROM TEACHER t. LECT_ON_MON_1WEEK 1
WHERE t.TchPK - 1.TchFK;
NAME
Вибровский
Хоренко
Вертикальное представление выбирает часть столбцов исходной таблицы, предоставляя доступ ко всем ее строкам. Если какой-то пользователь или группа пользователей интересуется только фамилиями преподавателей, их должностями и датами приема на работу, для них можно создать следующее представление:
CREATE VIEW TEACHER_SHORT AS
SELECT Name, Post. Hi reDate FROM TEACHER;
Представление создано.
Наконец, смешанное представление производит вырезание из исходной таблицы и по строкам, и по столбцам.
Запрос. Создать представление, содержащее фамилии, должности и номера телефонов преподавателей, имеющих на первой неделе занятия в аудиториях шестого корпуса.
CREATE VIEW TEACHER_SH0RT_BLD6 AS
SELECT Name. Post, Tel FROM TEACHER
WHERE TchPK IN (SELECT TchFK FROM LECTURE
WHERE Week = 1 AND
RomFK IN (SELECT ROMPK FROM ROOM
WHERE Building = '6'));
Представление создано.
Имея такое представление, легко выразить следующий запрос.
Запрос. Вывести фамилии ассистентов, имеющих на первой неделе занятия в аудиториях шестого корпуса.
SELECT Name AS "Преподаватели" FROM TEACHER_SH0RT_BLD6
WHERE LOWER(Post) = 'ассистент';
Преподаватели
Вибровский
Воропаев
Мартынов
Переименование столбцов
В предыдущих примерах столбцы создаваемых представлений наследовали имена столбцов исходной таблицы. Во многих случаях это оказывается удобным. Однако в следующих ситуациях необходимо предоставлять столбцам новые имена:
О столбец является результатом вычисления выражения;
О два или более столбца соединяемых таблиц имеют одинаковые имена.
И в том и другом случае вы получите отказ в создании представления. Имеется два варианта решения этой задачи. Во-первых, можно воспользоваться возможностями фразы SELECT запроса по переименованию столбцов. Во-вторых, синтаксис создания представлений позволяет переименовывать столбцы исходной таблицы. Для этого необходимо указать требуемые имена столбцов в предложении CREATE VIEW вслед за именем представления.
Запрос. Создать представление, содержащее фамилии и должности кураторов групп пятого курса. Столбец фамилии должен называться Surname, а должности — Position.
CREATE VIEW TEACHER_CURATOR_5 (Surname. Position) AS
SELECT Name. Post FROM TEACHER
WHERE TchPK IN (SELECT CurFK FROM SGROUP WHERE Year - 5);
Представление создано.
ПРИМЕЧАНИЕ Именовать нужно либо все столбцы представления, либо ни одного.
Агрегированные представления
Агрегированным называется представление, которое содержит агрегатную функцию в списке фразы SELECT. Вспомним, что такие функции могут применяться как с фразой GROUP BY, так и без нее.
Запрос. Создать представление, содержащее среднюю зарплату преподавателей, а также процентное соотношение средней ставки к средней надбавке и наоборот.
CREATE VIEW AGRJDATA (AVG Sal, Sal_Per_Rise, Rise_Per_Sal) AS
SELECT AVG(Salary + Rise), AVG(Salary) * 100 / AVG(Rise), AVG(Rise) * 100 / AVG(Salary) FROM TEACHER;
Представление создано.
Созданное представление можно либо только просмотреть, либо использовать полученные данные в другом запросе.
Запрос. Вывести среднюю зарплату преподавателей, а также процентное соотношение средней ставки к средней надбавке и наоборот.
SELECT * FROM AGR DATA:
AVG_SAL SAL_PER_RISE RISE_PER_SAL
1053,4 237,556078 42.0953237
Запрос. Вывести фамилии преподавателей, у которых процентное соотношение ставки к надбавке превышает среднее значение этого соотношения по вузу.
SELECT Name, Salary * 100 / Rise FROM TEACHER
WHERE Salary * 100 / Rise > (SELECT SAL_PER_RISE FROM AGR_DATA);
NAME SALARY*100/RISE
Хоренко Вибровский Воропаев Козлутин Мартынов Недеведеев
291,304348
335,294118
380
240,909091
240,909091
247,826087
Представления можно использовать везде, где можно применять подзапросы, то есть во фразах SELECT, FROM, WHERE и других. Выше мы показали использование представления во фразе WHERE. Приведем также пример его использования во фразе SELECT.
Запрос. Вывести фамилии преподавателей, у которых процентное соотношение надбавки к ставке меньше среднего значения этого соотношения по вузу. Помимо фамилий преподавателей вывести также само значение процентного соотношения у преподавателя и по вузу.
SELECT NameAS "Преподаватель",
Rise * 100 / SalaryAS "X надбавки к ставке",
(SELECT RISE_PER_SAL FROM AGR_DATA) AS "X надбавки к ставке по вузу"
FROM TEACHER
WHERE Rise * 100 / Salary < (SELECT RISE_PER_SAL FROM AGR_DATA);
Преподаватель К надбавки к ставке К надбавки к ставке по вузу
Хоренко
34,3283582
42,0953237
Вибровский
29,8245614
42,0953237
Воропаев
26,3157895
42,0953237
Козлутин
41,509434
42.0953237
Мартынов
41,509434
42,0953237
Недеведеев
40,3508772
42.0953237
Намного больше возможностей предоставляют агрегированные представления, полученные с помощью фразы GROUP BY.
Запрос. Создать представление, содержащее по каждой должности на каждой кафедре количество преподавателей и суммарные значения ставки и зарплаты. Если кафедра преподавателя не указана, считать ее равной 999.
CREATE VIEW DEP_POST_STAT (DepNo. TchPost. No, SalSum, RiseSum) AS
SELECT COALESCE(DepFK. 999) DepNo. Post, COUNH*), SUM(Salary). SUM(Rise)
FROM TEACHER
GROUP BY COALESCE(DepFK, 999), Post;
Посмотрим его содержимое:
SELECT * FROM DEP_POST_STAT:
)EPNO TCHPOST
NO SALSUM
RISESUM
2 ассистент
4 2200
760
2 доцент
3 2490
1151
2 преподаватель
3 1870
730
2 профессор
2 2170
940
999 доцент
1770
350
999 преподаватель
1570
250
999 профессор
1 1050
500
Геперь воспользуемся этим представлением для получения различной информации.
Запрос. Какова средняя зарплата у профессоров?
JELECT AVGCSalSum + RiseSum) FROM DEP_POST_STAT
JHERE LOWER(TchPost) = 'профессор':
WGCSALSUM+RISESUM)
2330
Запрос. Вывести суммарное значение ставки и надбавки по должностям.
;ELECT TchPost. SUM(SalSum), SUM(RiseSum) FROM DEP_POST_STAT
IROUP BY TchPost:
'CHPOST
SUM(SALSUM) SUM(RISESUM)
1ссистент
2200
760
юцент
3260
1501
|реподаватель
2440
980
|рофессор
3220
1440
Запрос. Вывести суммарное значение ставки и надбавки по должностям при ус- ювии, что сумма ставки по должности превышает все значения столбца Ri seSum таблицы DEP_POST_STAT.
1ELECT TchPost. SUM(SalSum). SUMCRiseSum) FROM DEP_POST_STAT iROUP BY TchPost
IAVING SUM(RiseSum) > ALL (SELECT RiseSum FROM DEP_POST_STAT);
CHPOST SUM(SALSUM) SUM(RISESUM)
юцент32601501
|рофессор32201440
Обратите внимание, что в запросах, использующих агрегированные представле- шя, можно производить дальнейшую группировку и применять агрегатные функ- ши к уже агрегированным значениям.
ноготабличные представления
Тредставления могут определяться на многих исходных таблицах путем их соеди- гения в запросе, который определяет представление. Более того, представления
могут определяться на других представлениях. Так, следующее представление определяет преподавателей факультета информатики:
CREATE VIEW CS_TEACHERS AS
SELECT t.*
FROM FACULTY f. DEPARTMENT d. TEACHER t
WHERE f.FacPK = d.FacFK AND d.DepPK = t.DepFK AND
LOWER(f.Name) = 'информатика';
Представление создано.
На базе этого представления можно определить еще одно для ассистентов факультета информатики:
CREATE VIEW CS_ASSISTANTS AS
SELECT *
FROM CS_TEACHERS
WHERE LOWER(Post) = 'ассистент';
Представление создано.
Теперь можно строить запросы к этим представлениям.
Запрос. Вывести фамилии преподавателей факультета информатики с зарплатой, превышающей 1500.
SELECT Name FROM CSJEACHERS
WHERE Salary + Rise > 1500;
NAME
Сидоров Резйан
Запрос. Вывести ассистентов факультета информатики, принятых на работу после 01.01.2003."
SELECT Name FROM CS_ASSISTANTS
WHERE Hiredate > Date *2003-01-01';
NAME
Вибровский
Удаление представления
Стандарт SQL не предусматривает возможности изменения определения представления. Предполагается, что в этом случае следует удалить его и определить вновь. Тем не менее многие СУБД предоставляют такую возможность. Представление может быть удалено в любое время. Для этого используется предложение DROP VIEW, которое имеет следующий формат:
DROP VIEW имя_представления {CASCADE | RESTRICT}
Альтернативные фразы CASCADE и RESTRICT имеют тот же смысл, что и при удалении обычных таблиц. В Oracle вместо этих фраз используется факультативная фраза CASCADE CONSTRAINTS. Удалим некоторые из ранее созданных представлений.
DROP VIEW FACULTY_COPY;
DROP VIEW PROFESSORS:
DROP VIEW LECT_ON_MON_1WEEK;
DROP VIEW TEACHER_SHORT;
DROP VIEW TEACHER_SHORT_BLD6;
ПРИМ ЕЧ АН И EУдаление представления не означает удаление тех исходных базовых
таблиц и представлений, на которых оно было определено.
Модификация данных через представления
Один из наиболее трудных и неоднозначных аспектов представлений — непосредственное их использование с командами модификации ЯМД (предложения INSERT, UPDATE, DELETE). Эти команды фактически воздействуют на значения в базовой таблице. Однако, как оказывается, не всегда очевидно, на какие именно строки базовых таблиц та или иная модификация должна распространяться. Рассмотрим следующее простое представление, показывающее для каждого из преподавателей номера групп, в которых они читают лекции:
CREATE VIEW TEACHER_GROUP AS
SELECT DISTINCT t.Name. g.Num
FROM TEACHER t, LECTURE 1. SGROUP g
WHERE t.TchPK = l.TchFK AND l.GrpFK = g.GrpPK;
Так как один и тот же преподаватель может вести несколько занятий в одной и той же группе, для удаления дубликатов строк мы использовали фразу DISTINCT в определении представления TEACHER_GROUP. В этом случае мы теряем информацию о том, к какой лекции такая строка представления относится. Поэтому если мы попытаемся удалить строку (Рамишевский, 505), то получим сообщение, что с помощью этого представления невозможно манипулировать данными:
DELETE TEACHER_GROUP
WHERE UPPER(Name) = 'РАМИШЕВСКИЙ* AND Num = 505;
DELETE TEACHER_GROUP
*
ошибка в строке 1:
ORA-01732: обработка данных для данного предст.пользователя не разрешена
Представления, через которые нельзя производить изменения данных, получили название немодифицируемых (или представлений только для чтения). Если же они могут использоваться для изменения данных базовых таблиц, то называются модифицируемыми (или обновляемыми).
Условия модифицируемости
Мы будем предполагать, что представление модифицируемое, если относительно него можно использовать все три команды модификации ЯМД — INSERT, UPDATE, DELETE. Как можно определить, модифицируемо представление или нет? Точное определение условий модифицируемости является открытым. Однако основной принцип ответа на этот вопрос следующий: представление модифицируемое, если по каждой модифицируемой строке представления можно найти строку в исходной таблице и для каждого модифицируемого столбца представления можно
определить столбец исходной таблицы. Однако использование этого принципа на практике затруднено. Кроме того, некоторые представления, которые являются модифицируемыми теоретически, на самом деле не являются модифицируемыми в SQL. Критерии, по которым определяют, является ли представление модифицируемым или нет, в стандарте SQL следующие:
О представление должно формироваться из одной базовой таблицы;
О оно не должно содержать ключевого слова DISTINCT в списке фразы SELECT;
О список фразы SELECT должен содержать только имена столбцов — запрещается использовать в этом списке константы, выражения над столбцами, функции и запросы;
О оно не должно использовать фраз GROUP BY или HAVING в своем определении;
О оно не должно использовать подзапросы во фразах FROM и WHERE;
О для предложений INSERT и UPDATE оно должно содержать все столбцы базовой таблицы, которые имеют ограничение NOT NULL.
Это очень жесткие ограничения. Существуют такие представления, через которые можно модифицировать базовую таблицу, хотя они не соответствуют приведенным выше правилам. Кроме того, существуют представления, через которые нельзя выполнять одни операции манипулирования, но можно использовать другие. Наконец, возможны ситуации, когда некоторые из столбцов обновить нельзя, а другие можно.
Многие СУБД снимают некоторые из ограничений или делают их не такими строгими. Например, некоторые СУБД допускают модификацию через представления, которые определяются соединением базовых таблиц. Но для этого такие представления-соединения должны обладать определенными свойствами. Одним из основных таких свойств является присутствие в представлении первичных ключей соединяемых базовых таблиц.
Решая вопрос, можно ли производить модификацию базовых таблиц через то или иное представление, обратитесь к документации СУБД, которую вы используете. Приведем несколько примеров представлений этих двух типов.
CREATE VIEW DEPJLD (Building, DepCount) AS
SELECT Building, COUNT(*) FROM DEPARTMENT
GROUP BY Building:
Это представление допускает только чтение, так как в его определении используется группировка и агрегатная функция.
CREATE VIEW LECT_IN_MON AS
SELECT * FROM LECTURE WHERE LOWER(Day) = 'пид';
Это представление модифицируемо.
CREATE VIEW TCH_TOTAL_SAL (Name. TotalSal) AS
SELECT Name. Salary + Rise FROM TEACHER
WHERE LOWER(Post) = 'ассистент*:
Это представление предназначено только для чтения, так как один из результирующих столбцов представляет собой выражение:
CREATE VIEW DEP_IN_CS AS
SELECT * FROM DEPARTMENT
WHERE FacFK IN (SELECT FacPK FROM FACULTY
WHERE LOWER(Name) = 'информатика');
Это представление немодифицируемое из-за использования в его определении запроса, однако некоторые СУБД допускают использование таких представлений для модификации.
CREATE VIEW LECTUREJN_MON_TUE_WED AS
SELECT * FROM LECTURE
WHERE LOWER(Day) IN Спнд', 'втр', 'срд');
Это представление модифицируемо.
Проверка модифицируемых значений
Если представление является модифицируемым, могут возникать проблемы «исчезновения» результатов модификации. Рассмотрим пример. Пусть задано следующее представление:
CREATE VIEW R00M_IN_57 AS
SELECT * FROM ROOM WHERE Building IN ('5', '7');
Это представление модифицируемо. Оно просто предоставляет доступ к определенным строкам базовой таблицы. Предположим, что через это представление происходит вставка следующей строки:
INSERT INTO ROOM_IN_57 VALUES (22. 902, 3. 9, 37);
1 строка создана.
Это допустимая вставка для нашего представления. Указанная строка будет вставлена в таблицу ROOM. Однако если мы попытаемся проверить результат нашей вставки, то вновь вставленную строку не увидим.
SELECT * FROM ROOM_IN_57;
ROMPK NUM FLOOR BUILD SEATS
3 2012560
5 2252 795
Дело в том, что мы вставили строкуеоб аудитории в корпусе 9, а само представление позволяет воспроизводить аудитории только корпусов 5 и 7. Пользователь может не понять, почему, введя строку, он ее не видит в своей таблице (напомним, что пользователь может и не знать, что та таблица, с которой он работает, является виртуальной). Чтобы обезопасить базу данных от модификаций такого типа, в определении представления используется фраза WITH CHECK OPTION:
CREATE VIEW ROOM__IN_57 AS
SELECT * FROM ROOM
WHERE Building IN ('5', *7')
WITH CHECK OPTION;
Эта фраза указывает, что при модификации строк через представление они (строки) должны удовлетворять условию фразы WHERE определения представления. Таким образом, если представление R00M IN 57 определено с этой фразой, через него можно вставить, обновить или удалить сведения только о тех аудиториях, которые находятся в корпусах 5 или 7. Используйте фразу WITH CHECK OPTION, если не хотите производить вставку, обновление и удаление таких строк базовой таблицы, которые само представление не может содержать.
Похожая проблема возникает в том случае, когда определение представления содержит предикаты на столбцах, которые не входят во фразу SELECT, то есть которые не видны через представление. Например, может показаться разумным создание следующего представления:
CREATE VIEW ROOM_IN_7 AS
SELECT RomPK, Num, Seats FROM ROOM
WHERE Building = '7';
Казалось бы нет смысла включать столбец Bui 1 di ng во фразу SELECT, если все корпуса должны быть равными 7. Однако при отсутствии этого столбца при вставке новых строк мы не сможем указать номер корпуса, поэтому, вероятнее всего, его значением будет NULL, и все вставляемые строки не будут видны в представлении. В этом случае следует либо указать столбец Building в списке фразы SELECT, либо воспользоваться фразой WITH CHECK OPTION в зависимости от того, чего вы хотите достигнуть. Тем не менее, рекомендуем всегда включать в представление столбцы, на которых определяются предикаты условия фразы WHERE, даже если они излишни с точки зрения назначения представления. Если вы не хотите видеть эти столбцы в том или ином запросе, исключите их из самого запроса, базирующегося на представлении, а не в самом представлении. Другими словами, вы могли бы определить представление Roomln7 следующим образом:
CREATE VIEW ROOM_IN_7 AS
SELECT * FROM ROOM
WHERE Building = *7* WITH CHECK OPTION;
Эта таблица будет содержать одни и те же значения столбца Bui 1 di ng, а именно 7, которые вы можете исключить в запросе на вывод данных:
SELECT RomPK, Num, Seats FROM R00M_IN_7;
Следует упомянуть еще об одной особенности фразы WITH CHECK OPTION в интерпретации стандарта SQL. В этой фразе можно применять ключевые слова CASCADE и LOCAL в том случае, когда представление определено на другом представлении. Фраза WITH CASCADE CHECK OPTION указывает, что при попытке выполнить модификацию через такое представление СУБД должна будет принять во внимание фразу WITH CHECK OPTION вложенного представления, если она там имеется. То есть должна проводиться каскадная проверка во всех вложенных представлениях. Этот вариант применяется в качестве варианта по умолчанию. Если же представление верхнего уровня создано с фразой WITH LOCAL CHECK OPTION, проверка этой фразы производится только в этом представлении.
Использование представлений
Мы уже упоминали о некоторых применениях представлений. Перечислим здесь все основные варианты их использования.
О Обеспечение логической независимости. Одна из основных задач, которую позволяют решать представления, — обеспечение логической независимости прикладных программ от изменений в структуре базы данных, например изменение порядка расположения столбцов, расщепление таблицы на две или более таблиц, изменение имен таблиц и столбцов и т. д. В таких случаях изменяются запросы в определениях соответствующих представлений. При этом никаких изменений в программы, работающие с такими представлениями, вносить не нужно.
О Прикладной взгляд на данные. Представления дают возможность различным пользователям по-разному видеть одни и те же данные, возможно, даже в одно и то же время. Это особенно ценно при работе различных категорий пользователей с единой интегрированной базой данных. Пользователям предоставляют только интересующие их данные в наиболее удобной для них форме или формате. Например, довольно легко можно решить проблему преобразования данных о зарплате, хранимых в базе данных в одной денежной единице, во многие другие денежные единицы в различных представлениях.
О Защита данных. Представления предоставляют дополнительный уровень защиты данных в таблицах. От определенных пользователей могут быть скрыты некоторые данные, невидимые через предложенное им представление. Таким образом, принуждение пользователя осуществлять доступ к базе данных через представления является простым, но эффективным механизмом для управления ограничением доступа.
О Скрытие сложности данных. Пользователь работает с представлением как с обычной таблицей, обращаясь к нему по имени, хотя само оно может представлять собой сложный запрос. Представления дают возможность создавать библиотеку сложных запросов, которые пользователи могут впоследствии выполнять многократно.
Представления могут использоваться в качестве альтернативы поддержке ограничений целостности, что продемонстрировано в следующем разделе.
Поддержка целостности
Представление можно использовать в качестве альтернативы поддержке ограничений целостности с помощью фразы WITH CHECK OPTION. Предположим, нам нужно гарантировать, что в таблице FACULTY значения корпусов находятся в пределах заданного списка. Этого можно достичь двумя способами. Во-первых, установить ограничение CHECK непосредственно на столбец Building в определении таблицы. Во-вторых, можно создать представление, которое исключает неправильные значения корпуса.
CREATE VIEW BldRestrOnFac AS
SELECT * FROM FACULTY
WHERE Building IN ('1', *2*. '2b', *3*. '4', *5*)
WITH CHECK OPTION:
Теперь вместо предоставления пользователям привилегий по модификации базовой таблицы FACULTY вы можете предоставить им привилегии относительно представления BldRestrOnFac. Преимущество такого подхода в том, что, если вам нужно сделать изменение в списке допустимых корпусов, представление можно удалить, создать новое и предоставить относительно него ранее существовавшие привилегии. Это проще и безопаснее, чем изменять ограничения целостности в определении таблицы.
С другой стороны, упомянутый выше подход вполне допускает возможность предоставления привилегий по модификации самой таблицы FACULTY, например, чтобы обходить ограничения целостности, поддерживаемые представлением. Это иногда бывает желательным (то есть как бы поддерживать принцип двойного стандарта — через виртуальную таблицу можно сделать одно, а при непосредственном обращении к базовой таблице — другое). Если бы мы специфицировали ограничение целостности в определении самой базовой таблицы, обойти его было бы невозможно. Если мы выбираем этот подход, пользователи не смогут увидеть через представление BldRestrOnFac те строки таблицы FACULTY, которые содержат нестандартные значения корпуса. В этом случае можно определить еще одно представление для строк с такими нестандартными значениями корпуса:
CREATE VIEW NotStandardBuilding AS
SELECT * FROM FACULTY
WHERE Building NOT IN (*Г, *2*. '2b'. *3*. *4*. '5')
и предоставлять пользователям только полномочие SELECT в этом представлении, чтобы они могли видеть такие исключающие строки, но не могли помещать строки с недопустимыми значениями корпуса.
Самостоятельная работа
Создайте представление, которое является точной копией таблицы преподавателей.
Создайте представление под именем TCH_AFTER_96, которое содержит сведения о преподавателях, принятых на работу после 31.12.1996.
Используя представление TCH AFTER 96, выведите фамилии ассистентов.
На базе представления TCH_AFTER_96 создайте представление TCH_AFTER_96_RICH, которое содержит сведения о преподавателях, имеющих ставку более 1000.
Из представления TCH_AFTER_96_RICH выведите фамилии и надбавки профессоров.
Для факультета информатики создайте представление, содержащее фамилии преподавателей, названия их дисциплин и номера аудиторий, в которых они проводят занятия.
Создайте представление, содержащее названия факультетов, их фонды и суммарные фонды их кафедр. Дайте подходящие имена столбцам представления.
Создайте представление, содержащее суммарное значение зарплаты всех преподавателей.
L Удалите все ранее созданные представления.
). Создайте представление GRP_5, содержащее информацию о группах пятого курса.
Используя представление GRP_5, введите информацию о группе третьего курса.
■ Посмотрите, видна ли введенная строка через представление GRP_5.
!. Используя представление GRP_5, замените номер группы 307 на 407.
Удалите представление GRP_5.
Создайте представление GRP_PROG, содержащее сведения о группах кафедры программирования.
>. Используя представление GRP_PROG, в группе 201 установите количество студентов равным 33. Почему ни одна из строк не обновилась?
дведение итогов
/своив материал этого урока, вы научились:
3 определять простые, горизонтальные, вертикальные, смешанные представления;
3 переименовывать столбцы представления;
3 создавать агрегированные представления;
3 определять представления на многих таблицах;
3 удалять представления;
3 определять, является ли представление модифицируемым;
3 производить вставку, удаление и обновление строк базовых таблиц через представления;
3 контролировать процесс модификации базы данных через представления.
§) УРОК Защита данных
В контексте баз данных термин безопасность означает защиту данных от несанкционированного раскрытия, изменения или уничтожения данных. SQL позволяет индивидуально защищать как целые таблицы, так и отдельные их столбцы. Для этого имеются две возможности:
О подсистема санкционирования доступа, позволяющая предоставить указанным пользователям определенные привилегии на доступ к данным и дать им возможность избирательно и динамически передавать часть выделенных привилегий другим пользователям, отменяя впоследствии эти привилегии, если потребуется;
О механизм представлений, используемый для скрытия конфиденциальных данных от пользователей, не обладающих правом доступа.
Составляющие системы защиты
Определить защиту данных — это означает зафиксировать в системе защиты следующую информацию:
О субъекты защиты данных,
О условия предоставления доступа,
О объекты, на которые распространяется защита,
О операции, относительно которых специфицируется защита,
О возможность передачи прав доступа другим лицам.
Далее мы кратко рассмотрим эти составляющие.
Субъекты защиты данных
Права доступа предоставляются всем тем, кто обращается к базе данных. Это могут быть пользователи, группы пользователей, прикладные программы, операционные системы, другие приложения и т. д. Главное то, что все, кто обращается к базе данных, должны прежде всего указать сбое имя и пароль. Для СУБД не
существенно, кто именно обращается к базе данных, главное, чтобы все, кто хотят иметь возможность работать с базой данных, были предварительно зарегистрированы в системе.
Обычно при установке СУБД указывается имя и пароль лица, которое далее рассматривается как наиболее привилегированный пользователь — системный администратор. Каждый, кто входит в систему с этим паролем, будет считаться системным администратором до выхода из системы. Системный администратор обладает неограниченными правами, включая создание баз данных, ее объектов, регистрацию пользователей и предоставление им соответствующих прав. В свою очередь, пользователи, получившие определенные права от системного администратора, могут передать их (или их часть) другим пользователям, которые могут их передать следующим и т. д.
Условия предоставления доступа
Иногда оказывается полезным специфицировать условия, при выполнении которых пользователям предоставляется доступ. Причем имеются в виду условия, которые не задаются другими составляющими системы защиты (кому предоставляется доступ, к каким данным, какие операции). Примерами таких дополнительных условий могут быть следующие:
О временные характеристики (например, специфицируемые права доступа действуют только между 16 и 17 часами первого понедельника каждого месяца);
О локализация компьютеров в локальной сети (например, специфицируемые права доступа действуют только для компьютеров, установленных в плановом отделе).
Отметим, что как в стандарте SQL, так и в большинстве СУБД нет явных возможностей по описанию таких дополнительных условий. Все они должны быть реализованы в конкретной прикладной системе, если в этом имеется необходимость.
Защищаемые объекты
Обычно выделяют объекты двух классов: системные объекты и объекты базы данных. К системным объектам относятся, например, базы данных, пользователи, роли и т. д. К объектам базы данных относятся таблицы, представления, процедуры, функции. Кроме того, в таблицах и представлениях могут дополнительно указываться столбцы, относительно которых специфицируются права доступа. В некоторых случаях появляется необходимость специфицировать также строки таблиц. Примерами таких ограничений прав доступа могут быть следующие:
О любой пользователь может изменять в таблице преподавателей значения столбцов только той единственной строки, которая относится к нему самому (то есть он может изменять только свои собственные данные), за исключением величины его зарплаты и ставки;
О в таблице преподавателей изменять зарплату и надбавку может только тот пользователь, который является начальником этого преподавателя.
Наконец, отметим, что в некоторых случаях сами данные могут быть закрытыми, однако выводимые (вычисляемые) на их основании данные могут быть открытыми. Так, например, сведения о заболеваниях конкретного человека могут быть
конфиденциальными, однако статистика заболеваемости по различным регионам вполне может быть общедоступной.
Защищаемые операции
Такими операциями являются стандартные операции работы с объектами базы данных. К ним относятся:
О определение, переопределение и удаление таблиц, представлений и других объектов базы данных;
О выборка, вставка, удаление, обновление строк в таблице или представлении;
О запуск на выполнение различных системных и прикладных процедур и функций.
Передача прав доступа
Вполне естественной является ситуация, когда тому или иному пользователю предоставляются не только определенные права, но также и возможность передавать эти права другим. Например, пользователю передается право создать таблицу и что угодно с ней делать (вводить данные, изменять и удалять их), вплоть до удаления всей таблицы. Таким образом, он становится как бы полноправным пользователем этой таблицы — это его собственная таблица и он может с ней делать что угодно. В связи с этим естественной является ситуация, когда ему передаются права на передачу любых прав на эту таблицу любым другим пользователям.
Пользователи и роли
Любой пользователь для получения доступа к базе данных должен быть зарегистрирован в системе под определенным именем и определенным паролем. Регистрация необходима для того, чтобы знать, с кем имеет дело система в текущий момент работы. Отметим, что под пользователем может подразумеваться не только конкретное лицо, но и любой источник, который в состоянии обратиться к базе данных (программа, операционная система, приложение Интернет и т. д.).
Определение пользователей
Стандарт SQL не специфицирует способ определения пользователей, оставляя конкретным СУБД право самостоятельно решать этот вопрос, однако предполагает, что такое понятие, как идентификатор пользователя все же существует. Более того, стандарт SQL предполагает, что идентификатор пользователя может ассоциироваться с конкретной последовательностью предложений SQL, которая называется модулем. Тем самым одна и та же программа может выполнять различные задачи (модули) от имени различных пользователей.
Рассмотрим, как определяется пользователь в Oracle. Упрощенной конструкцией для определения пользователя является следующая:
CREATE USER пользователь [UDENTIFIED BY пароль | EXTERNALLY};
где пользователь — имя пользователя, а пароль — его пароль. Фраза EXTERNALLY означает, что пользователь имеет тот пароль, который определен для него в операционной системе.
С каждым созданным пользователем ассоциируется домен его привилегий, который первоначально пустой. Чтобы пользователь мог выполнить ту или иную операцию над базой данных, его домен полномочий должен содержать соответствующую привилегию. Домен полномочий пользователя содержит те привилегии, которые непосредственно ему предоставлены, и привилегии от тех ролей, которые ему приписаны.
Как и для многих других команд создания объектов SQL, относительно пользователей существует команда ALTER USER, которая позволяет изменить характеристики пользователя, включая его пароль. Наконец, удаление пользователя из системы производится такой командой:
DROP USER пользователь [CASCADE];.
Ключевое слово CASCADE означает, что вместе с удалением пользователя удаляются все те объекты базы данных, которыми он владеет. Помните, что при удалении одних объектов, например таблиц, могут становиться недействительными другие объекты, например базирующиеся на них представления или ограничения ссылочной целостности, которые ссылаются на удаляемую таблицу.
Идентификация и подтверждение подлинности
Перед началом работы с базой данных пользователь должен идентифицировать себя. Для этого указывается имя пользователя. Кроме того, учитывая, что имя пользователя может носить общедоступный характер, пользователь также должен подтвердить подлинность указанного имени, введя пароль, который известен только системе и самому пользователю.
В общем случае эти два шага — идентификация и подтверждение подлинности — выполняются однократно при подключении к базе данных. Любое подключение к СУБД инициирует сеанс связи с пользователем, который действует до окончания работы пользователя СУБД. В стандарте SQL имеется специальная фраза CURRENT_USER (USER в Oracle), которая позволяет сослаться на пользователя, инициировавшего выполнение того предложения, где эта фраза расположена.
Определение ролей
Роль — это совокупность привилегий, которые могут предоставляться группам пользователей или другим ролям. Роли введены для того, чтобы можно было описывать ситуацию, когда группы пользователей имеют одинаковые функциональные обязанности, а значит, они могут иметь и одинаковые полномочия по работе с базой данных. Роли используются для администрирования привилегиями базы данных. Можно присвоить привилегии ролям и затем относить пользователей к тем или иным ролям. Когда пользователь отнесен к роли, он обладает теми привилегиями, которыми обладает роль. Роль обладает всеми теми привилегиями, которые присвоены роли, и всеми теми привилегиями, которые переданы ей другими ролями.
В стандарте SQL роль определяется следующим образом:
CREATE ROLE имя_роли [WITH ADMIN {CURRENT_USER | CURRENT_ROLE}]
Фраза WITH ADMIN указывает, кто обладает правом администрирования этой ролью. Им может быть текущий пользователь или текущая роль (напомним, что там, где идет речь о правах, роль рассматривается как специальный пользователь, а именно групповой пользователь). Если фраза отсутствует, то этим правом обладает текущий пользователь, а если его нет, то текущая роль.
Упрощенный синтаксис определения роли в Oracle следующий:
CREATE ROLE роль [NOT INENTIFIED | IDENTIFIED {BY пароль | EXTERNALLY}]
где роль — имя роли, а пароль — пароль роли. Пароль роли нужен для выполнения определенных действий.
Первоначально роль является пустой, то есть не имеющей ни одной привилегии. Включение привилегий в роль производится командой GRANT. Роли могут создавать администратор и те пользователи, которым такое право предоставил администратор. Тот, кто создал роль (в Oracle), или тот, кто явно указан при определении роли (стандарт SQL), обладает правами ее администрирования, то есть может: О предоставлять роль другому пользователю или роли;
О аннулировать роль для другого пользователя или роли;
О изменять определение роли, например, с целью изменения авторизации доступа к ней;
О удалять роль.
Как и любой другой объект базы данных, определение роли можно изменять с помощью команды ALTER ROLE и удалять с помощью команды DROP ROLE. Предложение ALTER ROLE отсутствует в стандарте SQL, a DROP ROLE присутствует в стандарте SQL и в Oracle и имеет следующий вид:
DROP ROLE имя_роли
Предоставление и отмена привилегий
Стандарт SQL имеет предложения по предоставлению привилегий и их отмене, которые рассматриваются далее. Предоставление привилегий производится двумя предложениями. Одно предоставляет привилегии на объекты базы данных, а другое — на роли.
Предоставление привилегий на объекты базы данных
Предоставление привилегий на объекты производится следующим предложением:
GRANT {ALL PRIVILEGES | список_привилегий} ON объект
ТО {PUBLIC | {пользователь | роль}...}
[WITH HIERARCHY OPTION]
[WITH GRANT OPTION]
[GRANTED BY {CURRENT_USER | CURRENT_ROLE}]
К множеству объектов, для которых специфицируются привилегии, относятся следующие (приведем только те, которые мы рассмотрели ранее):
О таблицы и представления базы данных;
О домены, на которых определяются типы столбцов;
О определяемые типы данных;
О последовательности;
О вызываемые из SQL программы.
Приведем список привилегий, предоставляемых для работы с объектами базы данных.
О Использование предложения SELECT ко всей таблице или только к отдельным ее столбцам.
О Использование предложения DELETE.
Q Использование предложения INSERT ко всей таблице или только к отдельным ее столбцам. В этом случае одни пользователи могут вводить строки таблицы только со значениями отдельных столбцов, а другие пользователи затем могут обновить значения других столбцов.
О Использование предложения UPDATE ко всей таблице или только к отдельным ее столбцам.
О Ссылки на таблицы или их столбцы любым способом — привилегия REFERENCES, которая позволяет ссылаться на столбцы во внешнем ключе или при задании ограничения целостности CHECK.
О Использование некоторых из объектов базы данных способом, отличающимся от описанных выше — привилегия USAGE. Если пользователь получит такую привилегию по отношению, например, к домену, он может использовать его для указания типа столбца определяемой таблицы. В противном случае он этого сделать не может.
О Инициирование триггеров из указанной таблицы - привилегия TRIGGER.
О Выполнение вызываемой из SQL программы — привилегия EXECUTE.
Дополнительные фразы предложения GRANT означают следующее.
О WITH HIERARCHY OPTION — передает права указанного объекта всем его подобъектам. Она имеет смысл только для привилегии SELECT, предоставленной объекту в иерархической структуре объектов (иерархическая структура наследования в объектно-ориентированном SQL). В этом случае специфицируемая привилегия распространяется на все производные объекты того объекта, относительно которого специфицировано это полномочие.
О WITH GRANT OPTION — означает, что указанному пользователю не только предоставляются специфицированные привилегии, но и права предоставлять эти привилегии другим пользователям.
О GRANTED BY — указывает, кто именно передает полномочия. Ими могут быть либо текущий пользователь, либо текущая роль.
Приведем несколько примеров.
GRANT SELECT, UPDATE (Salary, Rise) ON TEACHER TO Kostya;
GRANT ALL PRIVILEGES ON ROOM TO Jones WITH GRANT OPTION;
GRANT SELECT ON FACULTY TO PUBLIC;
GRANT DELETE, UPDATE ON SUBJECT TO Ivanov, Petrov;
GRANT REFERENCES (DepPK), UPDATE (Name, Head. Building) ON DEPARTMENT TO Blake;
Последний пример означает следующее. Пользователю Blake предоставлено право обновлять значения столбцов Name, Head, Building в таблице DEPARTMENT. Кроме того, он может ссылаться любым образом на столбец DepPK этой таблицы. В частности, он может определять внешний ключ, который ссылается на этот столбец. Последнее означает, что он может создать таблицу со следующим внешним ключом:
CREATE TABLE MyTeachers (
ID INTEGER.
Name CHAR(20),
Address CHAR(50).
Works_In INTEGER CONSTRAINT TchrlnDep REFERENCES DEPARTMENT(DepPK));
Внешний ключ TchrlnDep гарантирует, что всем учителям в MyTeachers будут соответствовать кафедры из DEPARTMENT.
Предоставление ролей пользователям или ролям
Предоставление привилегий на роли задается следующим предложением:
GRANT список^ролей
ТО {PUBLIC | (пользователь | роль}...}
[WITH ADMIN OPTION]
[GRANTED BY (CURRENT_USER | CURRENT_ROLE}]
Таким образом, предоставление роли имеет три варианта:
О PUBLIC — все имеющиеся в указанных ролях привилегии оказываются доступными всем пользователям;
О пользователь — получает все привилегии, которые имеются в указанных ролях;
О роль — получает дополнительно все привилегии указанных ролей.
Фраза WITH ADMIN OPTION указывает, что вторая роль приобретает все права по администрированию первой роли (то есть предоставлять или отменять ее другим ролям или пользователям, изменять список се полномочий или даже вообще удалять эту роль). Фраза GRANTED BY имеет тот же смысл, что и в предыдущем предложении.
Отметим, что роль — это единственный системный объект, на который можно предоставлять пользователям привилегии по их использованию. Приведем пример:
GRANT Sped al Role TO Smith;
Здесь пользователь Smith получает все полномочия, имеющиеся в роли Sped al Role.
GRANT Sped al Role TO AccountGroupRole;
Здесь вторая роль получает все те привилегии, которые имеются в первой роли.
GRANT Sped al Role TO PUBLIC
Здесь все пользователи получают полномочия роли Sped al Role.
В Oracle общая структура предложения GRANT соответствует стандарту SQL. Единственное существенное отличие заключается в том, что список системных объектов и объектов базы данных, а также перечень привилегий намного богаче.
Привилегии владельца
Пользователь, создавший таблицу (а для этого он должен иметь такое право), является владельцем этой таблицы. Это означает, что он имеет абсолютно все права на эту таблицу, вплоть до передачи прав на нее другим пользователям.
Пользователь, создавший представление, становится его владельцем. Но не все привилегии по отношению к нему он получает автоматически. Для создания представления необходимо иметь привилегию SELECT ко всем ее таблицам. Таким образом, владелец представления получает такую привилегию автоматически. Все другие привилегии он может получить посредством явного предоставления таковых по отношению ко всем базовым таблицам представления.
Отмена привилегий на объекты
Отмена ранее переданных привилегий производится командой REVOKE. В стандарте SQL имеется две разновидности этой команды — для отмены полномочий на объекты и отмены роли. Вторая будет рассмотрена ниже, а синтаксис первой разновидности команды REVOKE следующий:
REVOKE [{GRANT | HIERARCHY} OPTION FOR] {ALL PRIVILEGES | список_привилегий} ON объект
FROM {PUBLIC | {пользователь | роль}...}
[GRANTED BY {CURRENT_USER | CURRENT_ROLE}]
{CASCADE | RESTRICT}
Как видно, это предложение имеет структуру, аналогичную структуре предложения GRANT: оно содержит набор отменяемых привилегий, объект, относительно которого отменяются привилегии, и пользователей, у которых отменяются привилегии. С помощью этой команды можно отменить все ранее предоставленные привилегии или только некоторые. Фраза HIERARCHY OPTION FOR отменяет ту разновидность привилегии, которая предоставляется предложением GRANT с использованием фразы WITH HIERARCHY OPTION. Фраза GRANTED BY имеет тот же смысл, что и в предложении GRANT.
Вот простые примеры использования этого предложения. Для отмены полномочия UPDATE над таблицей TEACHER для Andrew следует записать:
REVOKE UPDATE ON TEACHER FROM Andrew;
Следующее предложение отменяет все полномочия пользователей Ivanov и Petrov относительно таблицы SUBJECT:
REVOKE ALL PRIVILEGES ON SUBJECT FROM Ivanov, Petrov;
2/JПРИМЕЧАНИЕ Любой пользователь может отменять только те привилегии, которые 4—лон ранее передавал, но не может отменить полномочия, которыми об
ладает сам.
Отмена многократно предоставленных привилегий
Многие пользователи могут предоставить одну и ту же привилегию на объект одному и тому же пользователю (или роли). Для аннулирования у пользователя
такой привилегии необходимо, чтобы ее отменили все пользователи, которые ее ранее передали. Если хотя бы один из пользователей не отзовет такую привилегию, то ее получатель будет ею обладать. Рассмотрим пример. Пусть пользователь Dep_Head предоставил пользователю Andrew полномочия выбирать данные из таблицы TEACHER, а также выбирать и обновлять таблицу SGROUP:
GRANT SELECT ON TEACHER TO Andrew:
GRANT SELECT, UPDATE ON SGROUP TO Andrew:
После этого еще один пользователь, Dep_Deputy, предоставил Andrew возможность выбирать и удалять данные из таблицы SGROUP и выбирать данные из таблицы SUBJECT:
GRANT SELECT. DELETE ON SGROUP TO Andrew:
GRANT SELECT ON SUBJECT TO Andrew:
Обратите внимание, что Andrew получил привилегии на таблицу SGROUP от двух лиц, причем привилегия SELECT получена от обоих пользователей. Чуть позже пользователь Dep Deputy решил отменить все ранее переданные им привилегии пользователю Andrew. В связи с этим он инициирует следующее предложение:
REVOKE ALL PRIVILEGES ON SGROUP FROM Andrew;
В связи с этим Andrew лишился права обновлять таблицу SGROUP, однако выбирать из нее данные и удалять их он все же может, так как такое право у него осталось от пользователя Dep_Deputy.
Каскадный эффект при отмене привилегий
Возможность передавать привилегии вместе с правами на передачу их другим приводит к возможности порождения целой цепочки порожденных привилегий. Например, пользователь Chief передал Andrew привилегию UPDATE на таблицу FACULTY с правом передавать ее (привилегию) другим пользователям (WITH GRANT OPTION). Воспользовавшись этим правом, Andrew передал пользователю Valery ту же привилегию на FACULTY с тем же правом передавать ее другим пользователям.
В связи с этим возникает следующий вопрос: как поступить в этом случае, если у пользователя Andrew забирается право обновлять таблицу FACULTY? Для ответа на этот вопрос в стандарт SQL включены два альтернативных ключевых слова - CASCADE и RESTRICT. Первое из них означает, что помимо отмены привилегии у Andrew также следует отменить эту же привилегию у Valery и так далее. Второе ключевое слово означает, что нельзя будет отменить привилегию у Andrew, если он уже передал ее другому пользователю. В этом случае необходимо, чтобы сначала Andrew отменил эту привилегию у Valery, и только после этого ее можно будет отменить у Andrew.
Отмена права предоставления привилегий
Очевидно, что если пользователь лишается тех или иных привилегий, он также лишается прав передачи их другим, если они у него имелись. Стандарт SQL позволяет отменять права предоставления привилегий, сохраняя при этом право
пользоваться самими привилегиями. Пусть, например, пользователю Andrew были предоставлены следующие привилегии с правом передачи их другим:
GRANT SELECT, UPDATE, DELETE ON SGROUP TO Andrew WITH GRANT OPTION;
Теперь, если у него будут забраны эти привилегии:
REVOKE SELECT, UPDATE, DELETE ON SGROUP FROM Andrew;
он также лишается прав передавать их другим. Однако можно следующим образом забрать у Andrew права передачи этих привилегий другим, оставляя возможность ими пользоваться:
REVOKE GRANT OPTION FOR SELECT, UPDATE, DELETE ON SGROUP FROM Andrew;
После этого у Andrew остаются привилегиями SELECT, UPDATE, DELETE по таблице SGROUP, но он уже не может передавать эти привилегии другим.
Более того, можно лишить Andrew прав передачи одних привилегий, оставляя за ним такие права по другим привилегиям:
REVOKE GRANT OPTION FOR UPDATE, DELETE ON SGROUP FROM Andrew:
После этого у Andrew все же сохранились права по передаче привилегии SELECT другим пользователям.
Отмена ролей у пользователей или других ролей
Отмена ролей производится следующей командой:
REVOKE [ADMIN OPTION FOR] список_ролей
FROM {PUBLIC | {пользователь | роль}...}
[GRANTED BY {CURRENT_USER | CURRENT_ROLE}]'
{CASCADE J RESTRICT}
Фраза GRANTED BY имеет тот же смысл, что и в предложении GRANT. Роль может быть аннулирована у пользователя или другой роли. При отмене роли у пользователя он теряет те привилегии, которые имеются у этой роли. При отмене роли у другой роли вторая роль теряет те привилегии, которые имеются у первой роли. При отмене роли у PUBLIC привилегии забираются у тех пользователей, которым они были предоставлены с помощью PUBLIC.
Фраза ADMIN OPTION FOR указывает, что у пользователя забираются права администрирования указанной ролью, однако ее привилегии за ним остаются. Альтернативные ключевые слова CASCADE и RESTRICT указывают, как поступать со ссылочным ограничением целостности, если его существование было разрешено привилегией REFERENCES, которая отменяется предложением REVOKE. В этом случае CASCADE означает, что все такие ссылочные целостности должны быть также удалены. В свою очередь, RESTRICT указывает, что привилегию REFERENCES нельзя отменить до тех пор, пока согласно ее существованию имеется ссылочная целостность. Приведем примеры отмены ролей.
REVOKE Sped al Role FROM Smith;
REVOKE Sped al Role FROM AccountGroupRole:
REVOKE Sped al Role FROM PUBLIC;
Представления и защита данных
Используя представления, привилегии можно определить. Всякий раз, когда вы предоставляете привилегии относительно базовой таблицы, они автоматически распространяются на все строки и столбцы. Если же вы создаете представление, а затем специфицируете привилегии относительно него, то ограничиваете область действия привилегий только теми столбцами и строками, которые видны через представление. Это значительно усиливает возможности команды GRANT.
Привилегии на базовые таблицы и представления
Чтобы иметь возможность выбора данных из представления, вы должны иметь право выбора данных из всех тех базовых таблиц и/или представлений, на которых данное представление определено. Если представление модифицируемо (см. урок 14 для ознакомления с условиями модифицируемости представлений), любая привилегия INSERT, UPDATE и DELETE, которую вы имеете в базовых таблицах, будет автоматически передаваться представлению. Если вы не обладаете привилегиями на модификацию в базовых таблицах, то не сможете иметь их и в представлениях, которые вы создали, даже если они модифицируемые.
Так как внешние ключи не определяются относительно представлений, полномочие REFERENCES никогда не используется при создании представления. Все эти ограничения определяются стандартом SQL. В последующих разделах мы предполагаем, что владельцы приводимых представлений имеют соответствующие привилегии во всех базовых таблицах.
Распространение привилегий на столбцы
Предположим, вы хотите дать пользователю John право видеть только столбцы Name, Head, Building таблицы DEPARTMENT. Вы можете сделать это, создав представление на этих столбцах:
CREATE VIEW DepForJohn AS
SELECT Name, Head, Building
FROM DEPARTMENT;
и предоставив ему привилегию SELECT относительно этого представления:
GRANT SELECT ON DepForJohn TO John;
Таким образом вы достигли желаемого. Однако следует отметить, что привилегию SELECT можно указывать в предложении GRANT вместе со списком столбцов, которые разрешается выбирать. Приведенное выше решение для ограничения доступа по столбцам с использованием представления можно представить и без него следующим образом:
GRANT SELECT (Name, Head, Building) ON DepForJohn TO John;
Аналогичным образом вы можете специфицировать столбцы и для других привилегий, однако это также излишне, так как:
О предложение INSERT, действующее через представление, имеет такое поведение по умолчанию (нельзя вставить значения столбцов, отсутствующих в представлении);
О команда DELETE не воспринимает никаких ограничений на столбцы, она всегда удаляет строку целиком;
О для привилегий REFERENCES и UPDATE ограничения на столбцы могут задаваться в самой команде GRANT.
Итак, представления не дают ничего нового для ограничения доступа по столбцам в сравнении с предложением GRANT.
Распространение привилегий на строки
Представления оказываются незаменимыми для ограничения действий привилегий на определенные строки базовой таблицы. Для этого определяется представление, содержащее необходимые строки, и относительно него специфицируется привилегия. Например, чтобы предоставить Andrew привилегию обновления только тех строк таблицы DEPARTMENT, которые относятся к факультету информатики, нужно создать следующее представление:
CREATE VIEW DepFromCS AS
SELECT * FROM DEPARTMENT
WHERE FacFK IN (SELECT FacPK FROM FACULTY
WHERE LOWER(Name) = 'информатика')
WITH CHECK OPTION;
и затем предоставить пользователю Andrew полномочие UPDATE относительно этого представления:
GRANT UPDATE ON DepFromCS TO Andrew;
Фраза WITH CHECK OPTION в определении представления предохраняет Andrew от изменения столбца FacFK на любое другое значение, которое не является номером факультета информатики.
Предоставление доступа к агрегированным данным
В некоторых случаях отдельные значения, хранимые в базе данных, могут носить конфиденциальный характер и поэтому следует ограничивать к ним доступ. Однако обобщающие данные, базирующиеся на этих значениях, могут быть вполне доступными. С помощью представлений эта проблема вполне разрешима.
Например, если сведения о ставке и надбавке конкретных служащих являются именно такими данными, к ним не определяются никакие права доступа. Поскольку агрегированные сведения о зарплате являются обезличенными, их можно делать доступными, и в связи с этим определить такое представление:
CREATE VIEW Aggregatesalary
SELECT Sum(Salary). SUM(Rise)
FROM TEACHER
и теперь по отношению к этому представлению можно предоставлять привилегии по чтению, например:
GRANT SELECT ON AggregateSal TO PUBLIC;
Самостоятельная работа
Создайте пользователя с именем Nick и паролем ForNick.
Создайте пользователя с именем Bob и паролем, определенным для него в операционной системе.
Удалите пользователя Bob.
Создайте роль Staff, администрировать которой имеет право текущий пользователь, и затем удалите ее.
Предоставьте пользователю Nick привилегии по выборке и удалению данных таблицы FACULTY.
Создайте пользователя Jones с паролем psw_22_7 и предоставьте ему привилегии по удалению строк таблицы LECTURE и обновлению столбца Day в этой таблице с правом передачи этих привилегий другим пользователям.
Предоставьте всем пользователям привилегию по выборке данных из всех столбцов таблицы факультетов, за исключением столбца Fund.
Создайте пользователя John с паролем pswrd_of_John. Предоставьте ему привилегию ссылаться на столбец SbjPK таблицы SUBJECT, а также обновлять столбец Name этой таблицы.
Создайте роль LowerRole. Предоставьте всем пользователям привилегии, имеющиеся в роли LowerRole.
Создайте роль Sped al Role. Предоставьте этой роли привилегию выбора данных из таблицы TEACHER, за исключением столбцов Salary и Rise, а также право обновлять столбец Post.
Отмените все привилегии пользователя John по таблице SUBJECT.
Подведение итогов
Усвоив материал этого урока, вы научились:
выделять составляющие системы защиты;
создавать и удалять пользователей;
создавать роли и удалять роли;
0 предоставлять привилегии пользователям и ролям;
0 передавать полномочия на предоставление привилегий и отменять их;
0 отменять привилегии;
0 управлять каскадным эффектом при отмене привилегий;
0 использовать представления для защиты данных.
Ж) УРОК Процедурный SQL
До сих пор мы изучали так называемый интерактивный SQLOh применяется для непосредственного выполнения действий пользователем с целью получения результата. Пользователь вводит команду, и результат ее выполнения выдается ему непосредственно. Сейчас мы приступаем к изучению так называемого процедурного SQL, который предполагает расширение SQL средой программирования.
Отметим, что это не встроенный SQL, предполагающий включение конструкций SQL в текст программы, написанной на полноценном языке программирования (например, на языке С), который обычно называется включаюгцим или базовым. Процедурный SQL — это язык, который интерпретирует сама СУБД. Стандарт SQL определяет язык SQL/PSM (SQL/Persistent Stored Modules — SQL для создания постоянно хранимых модулей), который предназначен для описания хранимых процедур и функций. В этом уроке мы изучим один из диалектов этого языка, реализованный в Oracle и имеющий название PL/SQL.
Курсоры
Одним из важных механизмов процедурного SQL, как впрочем и встроенного SQL, являются курсоры. Учитывая важность курсоров, их определение было введено в стандарт SQL. Далее мы опишем курсоры в интерпретации SQL, а затем укажем их особенности в Oracle.
Курсор базы данных в каком-то смысле подобен курсору обычного текстового редактора. При нажатии на клавишу со стрелкой вниз курсор перемещается на одну строку вниз, нажатие на клавишу со стрелкой вверх, наоборот, приводит к перемещению курсора на одну строку вверх. Нажатие клавиш PgUp и PgDn приводит к перемещению курсора вверх или вниз на несколько строк. Нечто подобное происходит и с курсором базы данных.
Курсор базы данных позволяет выбрать из базы данных группу строк, перемещаться от строки к строке и проводить анализ строки, на которой в текущий момент установлен курсор. Другим вариантом использования курсора является сохранение результатов выполнения запроса для последующего использования.
Результирующее множество строк курсора формируется на основании выполнения предложения SELECT. Если приложение или процедура требуют повторного использования набора строк, лучше всего создать один раз курсор и многократно его использовать вместо многократного выполнения предложения SELECT по отношению к базе данных.
Для использования курсора следует выполнить следующие шаги.
Определить курсор.
Открыть курсор.
Обработать строки курсора по одной за раз.
Закрыть курсор.
Уничтожить курсор.
Курсоры в стандарте SQL
Стандарт SQL специфицирует определение курсора и работу с ним, которые кратко описаны далее.
Определение курсора
Курсор определяется с помощью предложения DECLARE CURSOR, которое имеет следующий синтаксис:
DECLARE имя_курсора [чувствительность] [прокручиваемость] CURSOR [сохраняемость] [возвращаемость]
FOR спецификациЯ-Нурсора
Чувствительность курсора определяет, являются ли видимыми через курсор изменения данных, произведенные в той транзакции SQL, в которой курсор был открыт, до того момента, когда курсор будет закрыт. Параметр принимает одно из следующих значений:
SENSITIVE | INSENSITIVE | ASENSITIVE
Значение SENSITIVE указывает, что такие изменения являются видимыми, значение INSENSITIVE — что эти изменения оказываются невидимыми. Наконец, значение ASENSITIVE указывает, что видимость изменений определяется конкретной реализацией.
Прокручиваемость курсора свидетельствует о возможности перемещения курсора вверх и вниз по таблице, специфицирующей курсор. Его синтаксис весьма прост:
[NO] SCROLL
Значение SCROLL свидетельствует, что прокручиваемость допускается, значение NO SCROLL — нет.
Сохраняемость курсора определяет свойство курсора оставаться открытым после завершения транзакции, в которой курсор был создан. Параметр принимает одно из следующих двух значений:
{WITH I WITHOUT) HOLD
Значение WITH HOLD указывает, что курсор сохраняемый, то есть не закрывается (если находится в открытом состоянии) при завершении транзакции предложением COMMIT и закрывается, если транзакция завершается предложением ROLLBACK. Значение WITHOUT HOLD свидетельствует, что курсор несохраняемый, то есть закрывается по завершении транзакции, в которой он был создан.-
Возврагцаемостъ — это способность курсора возвращать таблицу, которая его специфицирует. Параметр принимает одно из следующих двух значений:
{WITH I WITHOUT} RETURN
Значение WITH RETURN указывает, что если к моменту выхода из процедуры курсор был открытым, он возвращает во внешнюю программу таблицу, которая его специфицирует.'
Спецификация курсора имеет следующий синтаксис:
запрос
[ORDER BY список_упорядочения]
[FOR {READ ONLY | UPDATE [OF список_столбцов]}]
Основу спецификации курсора составляет запрос, который определяет таблицу курсора. Упорядоченность строк таблицы указывается фразой ORDER BY, которая совпадает по своим возможностям с аналогичной фразой в предложении SELECT. Альтернативные фразы READ ONLY и UPDATE определяют, запрещается ли через курсор производить изменения в состоянии базы данных через таблицу курсора (READ ONLY) или разрешается (UPDATE). В последнем случае также допускается производить удаление строк. Если предполагается обновление строк, можно дополнительно указать столбцы, которые разрешается обновлять.
Работа с курсором
Курсор может находиться в открытом или закрытом состоянии. После объявления курсор оказывается в закрытом состоянии. Чтобы можно было работать с курсором, его следует открыть командой OPEN:
OPEN имя_курсора
В результате открытия курсора создается таблица, которая его специфицирует, устанавливается упорядоченность строк и курсор располагается перед первой строкой таблицы.
В открытом состоянии курсор может располагаться перед первой строкой, на определенной строке или после последней строки. Если курсор находится на строке, она является текущей строкой курсора. Курсор может располагаться перед первой строкой или после последней строки таблицы, даже если таблица пустая. Чтобы переместить курсор на необходимую строку таблицы и запомнить значения столбцов найденной строки, используется предложение FETCH со следующим синтаксисом:
FETCH [[ориентация] FROM] имя_курсора
INTO целевой_список
Ориентация определяет способ получения необходимой строки и принимает одно из следующих значений:
NEXT | PRIOR | FIRST | LAST | {ABSOLUTE | RELATIVE} значение
Эти значения указывают, какая строка будет выбрана:
О NEXT — следующая;
О PRIOR — предыдущая;
О FIRST — первая;
О LAST - последняя;
О ABSOLUTE значение — с указанным номером;
О RELATIVE значение — отстоящая на указанное значение (оно может быть положительным и отрицательным).
Целевой список в простейшем случае — это список переменных, в которых запоминаются столбцы найденной строки таблицы. Запомненные в переменных значения используются в процедуре или прикладной программе.
Если курсор является обновляемым, можно изменять и/или удалять строки таблицы курсора. Для этого используются разновидности предложений UPDATE и DELETE, которые получили название позиционного обновления и позиционного удаления. Эти разновидности команд имеют следующий синтаксис:
UPDATE имя_таблицы [[AS] псевдоним]
SET список_обновления
WHERE CURRENT OF имя_курсора
DELETE FROM имя_таблицы [[AS] псевдоним]
WHERE CURRENT OF имя_курсора
При обновлении изменяется та строка указанной таблицы, которая является текущей в указанном курсоре. То же самое имеет место и при удалении.
В закрытое состояние курсор возвращается командой CLOSE:
CLOSE имя_курсора
или предложением ROLLBACK той транзакции, которая его содержит. Открытый курсор, который не был определен как сохраняемый, закрывается также предложением COMMIT.
Курсоры в Oracle
В Oracle имеются некоторые специфические особенности работы с курсорами, которые мы ниже кратко опишем.
Определение курсора
Курсор в PL/SQL определяется в специальном разделе DECLARE, предназначенном для объявления переменных и других объектов. Для определения курсора используется следующий синтаксис:
DECLARE CURSOR имя_курсора [(список_параметров)] [RETURN тип_возврата] IS запрос;
где тип_возврата указывает на тип строки таблицы базы данных, возвращаемой курсором, а запрос — произвольное предложение SELECT. Например, вы можете определить такой курсор:
DECLARE CURSOR TchrMain IS
SELECT Name. Tel. Hiredate
FROM TEACHER
WHERE LOWER(Post) - 'ассистент';
Курсор может содержать параметры. Они могут указываться в запросе курсора в тех местах, где допустимо использовать константы. Все параметры являются только входными, то есть через них нельзя вернуть значения вызывающей программе. Параметр в списке параметров задается следующим образом:
имя_параметра [IN] тип_данных [{:= | DEFAULT) выражение]
Далее приводится определение курсора с указанием типов параметров и их значений по умолчанию — поступая таким образом, вы можете передавать курсору различное количество фактических параметров, используя или отклоняя значения по умолчанию.
DECLARE CURSOR DeptBetween (lowFund NUMBER DEFAULT 20000.00, hlghFund NUMBER DEFAULT 40000.00) IS SELECT * FROM DEPARTMENT
WHERE Fund >- lowFund AND Fund <- hlghFund;
Область действия параметров является локальной по отношению к курсору. Это означает, что к ним можно обращаться только в пределах определяемого в курсоре запроса. Значения параметров курсора используются соответствующим запросом при открытии курсора.
Открытие курсора
При открытии курсора происходит выполнение запроса и создание результирующего набора таблицы согласно запросу курсора. Синтаксис предложения открытия курсора следующий:
OPEN имя^урсораЕСсписок^фактических^араметров)];
При выполнении команды OPEN не происходит поиск строк результирующего набора — это делается командой FETCH.
При открытии курсора происходит передача курсору фактических параметров. Если для формального параметра в определении курсора не определено значение по умолчанию, фактическое значение необходимо указать в предложении OPEN. Например, если имеется следующее определение курсора:
DECLARE CURSOR TeacherSal (tname VARCHAR, tSal NUMBERS, 2)) IS
SELECT * FROM TEACHER
WHERE TEACHER.Name <> tname AND TEACHER.Sal ary > tSal;
то курсор можно открыть, например, таким образом:
OPEN TeacherSal('Иванов*, 750);
Поиск с помощью курсора
Предложение FETCH производит выборку очередной строки из результирующего набора строк курсора. Синтаксис предложения следующий:
FETCH имя_курсора INTO список_переменных;
Приведем пример предложения FETCH:
FETCH TchrMain INTO myTchrName. myTchrTel. myTchrHiredate;
Для каждого значения столбца, возвращаемого запросом курсора, должна быть соответствующая переменная в списке INTO. Типы данных переменных должны быть совместимы с возвращаемыми значениями. Обычно предложение FETCH используется следующим образом:
LOOP
FETCH TchrMain INTO myRecord;
EXIT WHEN TchrMainSNOTFOUND:
... -- обработка данных записи
END LOOP;
Предложение LOOP, являющееся конструкцией PL/SQL, приводит к циклическому выполнению команд, указанных в его теле, атрибут курсора NOTFOUND (об атрибутах см. далее в этом уроке) позволяет определить конец таблицы. Переменная myRecord имеет тип записи, о котором мы расскажем в этом уроке в разделе, посвященном языку PL/SQL.
В запросе курсора можно использовать переменные PL/SQL, которые находятся в области действия запроса. Однако любая переменная вычисляется только один раз — когда происходит открытие курсора. Для изменения результирующего набора строк таблицы курсора или значений переменных в запросе следует закрыть курсор и открыть его повторно при измененных значениях используемых переменных.
Закрытие курсора
Предложение закрытия курсора CLOSE имеет следующий синтаксис:
CLOSE имя_курсора;
При этом происходит удаление курсора и его результирующей таблицы. Пример закрытия курсора:
CLOSE TchrMain;
После закрытия курсор может быть открыт повторно.
Использование подзапросов в определении курсора
В предложении SELECT, определяющем курсор, можно использовать подзапросы. Например, следующий запрос возвращает строки сотрудников кафедры программирования:
DECLARE CURSOR ThcrFromEcon IS
SELECT * FROM TEACHER
WHERE DepFK IN (SELECT DepPK FROM DEPARTMENT
WHERE LOWER(Name) = 'программирование');
В следующем определении курсора подзапрос используется во фразе FROM, а сам запрос возвращает название, фамилию заведующего и количество преподавателей тех кафедр, которые имеют более 10 преподавателей:
DECLARE CURSOR DepLarge IS
SELECT dl.Name, dl.Head. Staff
FROM DEPARTMENT dl.
(SELECT DepPK. COUNT(*) AS Staff
FROM DEPARTMENT d3. TEACHER t3
WHERE d3.DepPK = t3.DepFK
GROUP BY DepPK) d2
WHERE dl.DepPK = d2.DepPK AND d2.Staff > 10;
Атрибуты курсора
Атрибут курсора — это свойство курсора, значение которого можно получить, используя соответствующее ключевое слово. Ключевые слова атрибутов курсора начинаются с символа %. Курсор имеет такие атрибуты:
О %ISOPEN — открыт ли курсор;
О %FOUND — найдена ли командой FETCH очередная строка;
О %NOTFOUND - значение противоположно предыдущему;
О %ROWCOUNT — количество строк, найденных к текущему моменту.
Для использования атрибута курсора перед именем атрибута следует указать имя того курсора, к которому он применяется. Атрибуты курсора используются в качестве процедурных предложений PL/SQL, то есть их нельзя использовать в предложениях SQL. Приведем примеры использования атрибутов курсора.
IF TchrMainKISOPEN THEN -- курсор открыт
ELSE-- курсор не открыт, открываем его
OPEN TchrMain;
END IF;
В следующем примере атрибут XFOUND используется для определения дальнейшего действия:
LOOP
FETCH TchrMain INTO myName, myTel, myHiredate;
IF TchrMain^FOUND THEN --команда FETCHвернуластроку
...--обработать ее
ELSE--команда FETCHневернула строку
EXIT;--выйти из цикла
END IF;
END LOOP;
После выполнения команды FETCH атрибут XROWCOUNT увеличивается на 1, а значит, содержит количество найденных до сих пор строк. В приведенном далее примере атрибут ^ROWCOUNT используется для совершения специального действия после обработки 10 строк:
LOOP
FETCH TchrMain INTO myName, myTel. myHiredate;
IF TchrMainSROWCOUNT > 10 THEN
END IF;
END LOOP;
Введение в PL/SQL
PL/SQL — это процедурный язык Oracle, который базируется на SQL и расширяет его возможности. Он включает множество средств процедурной обработки данных, которые имеются в обычных языках программирования и позволяет обрабатывать ошибки, которые встречаются в момент выполнения программы.
Хорошим способом продемонстрировать PL/SQL является изучение примера. Ниже приводится программа, которая переводит определенную сумму из фонда финансирования кафедры программирования в фонд финансирования кафедры лингвистики. Сначала в разделе DECLARE объявляется переменная типа NUMBER(7. 2) для запоминания размера фонда. Затем выбирается фонд финансирования кафедры программирования. Если этот фонд больше суммы перевода (1000), эта сумма вычитается из фонда кафедры программирования и добавляется в фонд кафедры лингвистики. Иначе программа вставляет запись в строку журнала регистрации нестандартных ситуаций.
DECLAREmyFund NUMBERC7, 2);BEGINSELECT Fund INTO myFund FROM DEPARTMENTWHERE Name = 'программирование*FOR UPDATE OF Fund;IF myFund > 1000 THENUPDATE DEPARTMENTSET Fund = Fund - 1000WHERE Name = 'программирование*:UPDATE DEPARTMENTSET Fund = Fund + 1000WHERE Name = 'лингвистика*;ELSEINSERT INTO MY_PROBLEMSVALUES (SYSDATE. *не переведена сумма END IF;COMMIT;END;DECLAREmyFund NUMBERC7, 2);BEGINSELECT Fund INTO myFund FROM DEPARTMENTWHERE Name = 'программирование*FOR UPDATE OF Fund;IF myFund > 1000 THENUPDATE DEPARTMENTSET Fund = Fund - 1000WHERE Name = 'программирование*:UPDATE DEPARTMENTSET Fund = Fund + 1000WHERE Name = 'лингвистика*;ELSEINSERT INTO MY_PROBLEMSVALUES (SYSDATE. *не переведена сумма END IF;COMMIT;END;-- объявляем переменную-- выбираем фонд кафедры программирования-- объявляем переменную-- выбираем фонд кафедры программирования-- проверяем значение фонда-- уменьшаем значение фонда-- проверяем значение фонда-- уменьшаем значение фонда-- увеличиваем значение фонда кафедры лингвистики-- фонд кафедры программирования меньше 1000-- заносим строку в журнал 1000*);-- увеличиваем значение фонда кафедры лингвистики-- фонд кафедры программирования меньше 1000-- заносим строку в журнал 1000*);
DECLARE
myFund NUMBERC7, 2);
BEGIN
SELECT Fund INTO myFund FROM DEPARTMENT
WHERE Name = 'программирование*
FOR UPDATE OF Fund;
IF myFund > 1000 THEN
UPDATE DEPARTMENT
SET Fund = Fund - 1000
WHERE Name = 'программирование*:
UPDATE DEPARTMENT
SET Fund = Fund + 1000
WHERE Name = 'лингвистика*;
ELSE
INSERT INTO MY_PROBLEMS
VALUES (SYSDATE. *не переведена сумма END IF;
COMMIT;
END;
DECLARE
myFund NUMBERC7, 2);
BEGIN
SELECT Fund INTO myFund FROM DEPARTMENT
WHERE Name = 'программирование*
FOR UPDATE OF Fund;
IF myFund > 1000 THEN
UPDATE DEPARTMENT
SET Fund = Fund - 1000
WHERE Name = 'программирование*:
UPDATE DEPARTMENT
SET Fund = Fund + 1000
WHERE Name = 'лингвистика*;
ELSE
INSERT INTO MY_PROBLEMS
VALUES (SYSDATE. *не переведена сумма END IF;
COMMIT;
END;
-- объявляем переменную
-- выбираем фонд кафедры программирования
-- объявляем переменную
-- выбираем фонд кафедры программирования
-- проверяем значение фонда
-- уменьшаем значение фонда
-- проверяем значение фонда
-- уменьшаем значение фонда
-- увеличиваем значение фонда кафедры лингвистики
-- фонд кафедры программирования меньше 1000
-- заносим строку в журнал 1000*);
-- увеличиваем значение фонда кафедры лингвистики
-- фонд кафедры программирования меньше 1000
-- заносим строку в журнал 1000*);
Язык PL/SQL предоставляет следующие возможности:
О определять переменные различных типов;
О использовать выражения допустимых типов;
О присваивать переменным значения;
О управлять процессом обработки данных путем использования управляющих команд;
О описывать специальные процедуры обработки ошибочных ситуаций;
О создавать интерактивные программы, которые принимают входные данные от пользователей;
О разбивать программы на логические блоки.
Кратко рассмотрим некоторые из этих возможностей
Типы данных PL/SQL
Каждая переменная и константа имеют тип данных, который определяет формат хранения, ограничения и допустимый диапазон значений. В PL/SQL имеется несколько предопределенных типов данных:
О скалярный — не имеет внутренних компонентов;
О составной — имеет внутренние компоненты, которые можно обрабатывать индивидуально;
О ссылочный — содержит значения, называемые указателями, которые указывают на другие программные элементы.
В PL/SQL Oracle поддерживает механизм подтипов для типов данных, которые называются базовыми. Базовый тип — это тип данных, из которого порождается подтип. Подтип ассоциируется с базовым типом с помощью некоторых дополнительных ограничений и, таким образом, определяет подмножество значений базового типа. Например, тип данных NUMBER имеет подтип INTEGER.
Базовые типы
Базовыми являются обычные типы Oracle (CHAR, VARCHAR, NUMBER, DATE и т. д.), а также ряд дополнительных, среди которых выделим BOOLEAN и RECORD. Первый из них является скалярным логическим типом для представления логических значений TRUE, FALSE и NULL, а второй — составным типом для представления значений строк таблиц.
Атрибут XROWTYPE можно использовать для объявления переменной типа записи, которая будет иметь структуру строки таблицы или строки, выбираемой курсором. Однако, используя явно тип записи, можно определять собственные поля записи. Запись содержит уникально именованные поля, которые могут иметь различные типы данных. Предположим, имеются различные данные о служащем, такие, как имя, зарплата, дата приема на работу. Эти элементы не похожи по их содержимому, однако логически связаны. Запись, содержащая поля для этих элементов данных, позволяет трактовать их как логически единый элемент данных. Рассмотрим следующий пример:
DECLARE
TYPE TimeRec IS RECORD (minutes SMALLINT. hours SMALLINT);
TYPE MeetingTyp IS RECORD (
DayDATE.
TimeTimeRec, -- вложенная запись
Place VARCHAR(20).
(§J ВНИМАНИЕ(§J ВНИМАНИЕPurpose VARCHAR(50));
(§J ВНИМАНИЕ
(§J ВНИМАНИЕ
Записи можно вкладывать друг в друга, то есть запись может быть компонентом другой записи.
Подтипы
Подтип — это механизм порождения новых типов на основании базовых. Существует ряд подтипов, входящих в состав встроенных типов. К ним, например, относится INTEGER, который является подтипом NUMBER и определяется как NUMBER(38, 0). Тип NUMBER имеет еще восемь подтипов (DEC, DECIMAL, DOUBLE RECISION, FLOAT, INT, NUMERIC, REAL, SMALLINT). Кроме того, существует возможность определять другие подтипы, то есть создавать так называемые определенные пользователем типы. Это делается в декларативной части программы, используя такой синтаксис:
SUBTYPE имя_подтипа IS базовый_тип[(ограничение)] [NOT NULL]:
Его составные элементы которого означают следующее:
О имя_подтипа — имя определяемого подтипа;
О базовый_тип — любой скалярный или определенный пользователем тип;
О ограничение — используется только для базового типа и указывает точность, масштаб или максимально допустимый размер.
Приведем несколько примеров определения подтипов:
DECLARE
SUBTYPE BIRTHDATEIS DATE NOT NULL;--подтипнаосноветипа DATE
SYBTYPE MONEY IS NUMBER(7. 2);--подтипнаосноветипа NUMBER
SYBTYPE SALARY ISMONEY;--подтипнаосновеMONEY
SUBTYPE TCH_ID ISTEACHER ЛСНРКШРЕ;--на основетипа столбца
При определении подтипа можно использовать атрибут XTYPE для спецификации базового типа. Так, в последнем примере TEACHER. TCHPKHYPE указывает на тип столбца ТСНРК таблицы TEACHER. После определения подтипа его можно использовать для объявления переменных этого типа, например:
DECLARE
SYBTYPE MONEY IS NUMBER(7, 2);
mySalary MONEY;
muFund MONEY;
Структура блока PL/SQL
Язык PL/SQL имеет блочную структуру. Это означает, что программа PL/SQL состоит из фрагментов, которые могут вкладываться друг в друга. Блок PL/SQL может содержать до трех разделов.
О DECLARE — раздел объявлений. Содержит определения типов, переменных, констант, курсоров и других объектов. Этот раздел является факультативным.
О BEGIN END — выполняемый раздел. Содержит собственно предложения SQL, команды манипулирования данными и управления вычислениями. Этот раздел является единственным обязательным разделом в блоке PL/SQL.
О EXCEPTION — раздел исключений. Содержит описания того, как обрабатывать специфические ошибки и определенные пользователем исключительные ситуации. Этот раздел является факультативным.
Таким образом, блок — это логическая единица программного кода PL/SQL, которая содержит, по крайней мере, выполняемый раздел и может содержать разделы DECLARE и EXCEPTION. Базовая структура блока SQL следующая:
DECLARE -- начало раздела объявлений
...--объявления объектов программы
BEGIN -- начало выполняемого раздела
...--предложения программы
EXCEPTION -- начало раздела исключений
...--обработчики исключительных ситуаций
END; -- конец выполняемого раздела
Язык PL/SQL непосредственно поддерживает команды языка манипулирования данными и языка запросов SQL. Однако он не поддерживает команды языка определения данных. Таким образом, с помощью PL/SQL можно манипулировать данными в пределах существующей структуры базы данных, но нельзя манипулировать (создавать, изменять, уничтожать) самой структурой базы данных.
Раздел объявлений DECLARE
Раздел объявлений начинается ключевым словом DECLARE и состоит из определения типов данных, переменных, констант, курсоров. Все используемые в блоке переменные должны быть определены в этом разделе путем приписывания им типов данных (правила определения подтипов мы описали выше).
Объявление переменных
Переменные — это те значения, которые могут изменяться в блоке PL/SQL. При объявлении переменной ей приписывается допустимый тип данных и может быть присвоено начальное значение. В приводимом ниже примере определяется несколько переменных в разделе DECLARE:
DECLARE
owner CHAR(IO);
tablename CHAR(30):
bytes NUMBER(IO);
today DATE;
По умолчанию переменная инициализируется значением NULL. При объявлении переменная также может быть явно проинициализирована. Например:
DECLARE
customerID CHAR(5) := 'XXXXX';
fiscal_>ear NUMBERC4) := 2006;
Кроме того, вместо оператора присваивания может использоваться фраза DEFAULT. Например, объявления:
lecture_type CHAR := 'L';
valid BOOLEAN := FALSE;
могут быть также представлены следующим образом:
lecture_type CHAR DEFAULT 'L';
valid BOOLEAN DEFAULT FALSE;
Атрибут ПУРЕ дает возможность специфицировать тип данных переменной или столбца таблицы базы данных. В следующем примере creditHYPE предоставляет тип данных переменной credit:
credit NUMBERS, 2);
debit credltHYPE;
Декларация с использованием HYPE может содержать фразу инициализации, например:
balance NUMBERHO. 2);
minimum_balance balanceHYPE := 100000.00;
Атрибут HYPE оказывается особенно полезным при объявлении переменных, которые должны ссылаться на столбцы таблиц базы данных, например:
myFacName FACULTY.NameHYPE;
Данное объявление указывает, что переменная myFacName имеет тот же тип, что и столбец Name таблицы FACULTY. Такое косвенное объявление переменной имеет
два преимущества. Во-первых, при объявлении переменной myFacName нет необходимости точно знать тип столбца Name. Во-вторых, при изменении типа столбца Name нет необходимости менять тип переменной — он сам изменится автоматически при обработке программы.
Атрибут XROWTYPE предоставляет возможность специфицировать тип записи, который имеют строки таблицы. Переменная типа записи может хранить всю строку данных, выбранную из таблицы базы данных или полученную в результате выполнения курсора. В приведенном ниже примере объявляется две переменных типа записи. Первая переменная может содержать строку, выбираемую из таблицы LECTURE, а вторая - строку, выбираемую по курсору DepShort:
DECLARE
lectureRec LECTUREXROWTYPE;
CURSOR DepShort IS
SELECT Name, Head, Building FROM DEPARTMENT;
departRec DepShort^ROWTYPE;
Столбцы в выбираемой строке курсора и соответствующие поля переменной-записи имеют одни и те же имена и типы данных. В следующем примере в переменную-запись teacherRec выбирается значение строки из таблицы TEACHER:
DECLARE teacherRec TEACHERXROWTYPE;
BEGIN
SELECT * INTO teacherRec FROM TEACHER WHERE...
END
Значения столбцов, возвращаемых предложением SELECT, сохраняются в полях переменной-записи. Для обращения к полю следует указать имя переменной и затем имя поля через точку, например:
IF teacherRec.Post = 'профессор* THEN...
Можно также присваивать значение или выражение тому или иному полю переменной-записи, например:
teacherRec.Name := 'Иванов*;
teacherRec.Sal ary : = 800;
teacherRec.Rise := teacherRec.Rise * 1.15;
Объявление констант
Константы объявляются так же, как и переменные, за исключением того, что перед спецификатором типа необходимо расположить ключевое слово CONSTANT, как это показано в следующем примере:
creditLimit CONSTANT REAL := 5000.00;
В этой декларации определяется константа creditLimit типа REAL и ей присваивается начальное (и окончательное) значение 5000,00. Константе, в отличие от переменной, нельзя изменять значение. Константа должна быть проинициализиро- вана при ее декларации.
Объявление курсоров
В разделе деклараций определяются также и курсоры. Способы определения и использования курсоров детально описаны в начале этого урока.
Выполняемый раздел
Выполняемый раздел является единственным обязательным разделом блока PL/SQL. Здесь происходит основная обработка данных — использование переменных, манипулирование курсорами для обращения к данным базы данных, использование управляющих структур и команд SQL. Выполняемый раздел окаймляется ключевыми словами BEGIN и END.
Управление курсором
В выполняемом разделе используются курсоры для поиска необходимых данных в базе данных и их последовательного просмотра. Это производится с помощью команд OPEN, FETCH, CLOSE. Описание использования этих команд и курсоров в целом приведено в начале этого урока.
Управление вычислениями
Известно, что три управляющие структуры, приведенные на рис. 16.1, обладают полнотой. Для решения любой поставленной задачи необходимо, чтобы они могли вкладываться друг в друга произвольным образом.
Рис. 16.1. Структуры управления вычислениями
PL/SQL содержит все эти три структуры управления вычислениями:
О последовательность — выполнение предложений согласно их упорядоченности;
О выбор — проверка условия и выполнение той или иной последовательности в зависимости от истинности или ложности условия;
О повторение (или итерация) — выполнение последовательности до тех пор, пока условие принимает истинное значение.
Условные предложения
Условные предложения дают возможность определять, каким образом обрабатывать предложения SQL. Условные предложения PL/SQL напоминают многие из тех, которые имеются в языках программирования. К ним относятся предложения IF THEN, IF THEN ELSE, IF THEN ELSIF.
IF THEN
Простейшим вариантом предложения IF является форма IF THEN, которая имеет следующий синтаксис:
IF условие THEN
последовательность_предложений;
END IF;
Последовательность предложений выполняется, только если условие равно TRUE. Если условие равно FALSE или NULL, ничего не вычисляется. В любом случае управление передается на следующее предложение. Пример:
IF numLectures > norma THEN
bonus := computeRi'se(tchlD);
UPDATE TEACHER SET Rise = bonus WHERE TchPK = tchlD;
END IF;
IF THEN ELSE
Следующая форма предложения IF содержит дополнительную фразу ELSE:
IF условие THEN
последовательность_предложений;
ELSE
последовательность_предложений;
END IF;
Последовательность предложений во фразе ELSE выполняется только в том случае, когда условие дает FALSE или NULL, например:
IF lectureWeek = 'один* THEN
UPDATE LECTURE SET Week = 1 WHERE...
ELSE
UPDATE LECTURE SET Week = 2 WHERE...
END IF;
Фразы THEN и ELSE, в свою очередь, могут содержать предложения IF. Таким образом, предложения IF могут вкладываться друг в друга, как это показано в следующем примере:
IF lectureWeek = 'один* THEN
UPDATE LECTURE SET Week = 1 WHERE...
ELSE
IF lectureWeek = 'два* THEN
UPDATE LECTURE SET Week = 2 WHERE...
ELSE
RAISE 1ncorrect_Lecture_Week;
END IF;
END IF:
IF THEN ELSIF
Иногда необходимо произвести выбор из многих взаимно исключающих альтернатив. Третья форма предложения IF использует фразу ELSIF для ввода дополнительных условий, как это показано ниже:
IF условие THEN
последовательность_предложений;
ELSIF условие THEN
последовательность_предложений:
ELSIF...
ELSE
последовательность_предложений:
END IF;
Если первое условие дает FALSE или NULL, фраза ELSIF тестирует второе условие. Предложение IF может иметь любое количество фраз ELSIF; конечная фраза ELSE является факультативной. Условия проверяются последовательно сверху вниз. Если условие оказывается истинным, отрабатывается соответствующая последовательность предложений и управление передается следующему предложению. Если все условия дают FALSE или NULL, выполняются предложения фразы ELSE. Приведем следующий пример:
BEGIN
IF numLecturesInWeek > 5 THEN bonus : = 50:
ELSIF numLecturesInWeek > 8 THEN bonus := 70;
ELSIF numLecturesInWeek > 11 THEN bonus ;= 100;
ELSE bonus := 30;
END IF;
UPDATE TEACHER SET Rise = Rise + bonus WHERE TchPK = tchlD;
END:
Итеративное управление
Команда LOOP позволяет выполнить совокупность предложений многократно. Имеется три формы этой команды: LOOP, WHILE LOOP, FOR LOOP.
LOOP
Предложение LOOP является простейшей формой итерации, которая позволяет многократно выполнить вложенные в этот цикл предложения. Такой цикл окаймляется ключевыми словами: LOOP и END LOOP следующим образом:
LOOP
последовательность_предложений;
END LOOP:
Циклическое выполнение вложенных предложений прерывается и происходит выход из цикла по предложению EXIT. Имеется две формы предложения EXIT: безусловный выход из цикла, условный выход из цикла. Безусловный выход из цикла указывается командой EXIT. Например:
LOOP
IF numDepartments > 3 THEN
EXIT: -- безусловный выход из цикла
END IF:
END LOOP;
...-- управление передается сюда
Условный выход из цикла производится такой командой:
EXIT WHEN условие
Выход происходит только в том случае, если условие истинно. Довольно часто такая форма выхода используется в курсорах, например:
LOOP
FETCH LectureRooms INTO currentRoom
EXIT WHEN LectureRooms^NOTFOUND; -- выход из цикла
END LOOP;
CLOSE LectureRooms;
WHILE LOOP
Предложение WHILE LOOP ассоциирует условие с последовательностью предложений, обрамленных ключевыми словами LOOP и END LOOP. Его синтаксис следующий:
WHILE условие LOOP
последовательность_предложений: END LOOP;
Перед каждой итерацией вычисляется условие. Если условие равно TRUE, выполняются предложения цикла, в противном случае происходит выход из него. Приведем пример:
WHILE total <= 25000 LOOP
SELECT Salary INTO salVar FROM TEACHER WHERE... total := total + salVar;
END LOOP;
Так как условие проверяется в начале цикла, предложения могут вообще не выполниться ни разу. Например, если начальное значение total больше 25 000, предложения цикла не выполняются ни разу.
FOR LOOP
Тип цикла FOR LOOP используется в том случае, когда известно количество итераций. Циклы FOR повторяются с учетом указанного интервала значений. Синтаксис следующий:
FOR счетчик IN [REVERSE] нижняя_граница..верхняя_граница LOOP последовательность_предложений;
END LOOP;
Здесь две точки (..) представляют собой оператор диапазона, а нижняя и верхняя границы — целые числа. Первоначально счетчику присваивается значение нижней границы, затем в каждом из циклов счетчик увеличивается на 1. Вычисление цикла производится до выхода счетчика за верхнюю границу. Приведем пример:
FOR 1 IN 1..3 LOOP-- 1 принимает значения 1, 2, 3
последовательность_предложений; -- выполняется три раза
END LOOP:
По умолчанию итерация производится от нижней границы к верхней. Однако при использовании факультативного ключевого слова REVERSE итерация производится в обратном направлении — от верхней границы к нижней. После каждой итерации счетчик уменьшается.
Для курсора используется специфическая форма цикла FOR LOOP с таким синтаксисом:
FOR переменная^курсора IN имя_курсора LOOP последовательность^предложений;
END LOOP;
При входе в цикл переменная курсора принимает значение первой строки из набора строк курсора, а в последующих итерациях — значения следующих строк набора. При достижении конца строк набора происходит автоматический выход из цикла. Приведем пример:
DECLARE
teacherRec TEACHERXROWTYPE;
salary_total NUMBERC6, 2) := 0:
CURSOR tchCursor IS
SELECT Name. Salary, HireDate, DepFK FROM TEACHER;
BEGIN
FOR teacherRec IN tchCursor LOOP
salary__total :- salary_total + teacherRec.Sal ary;
END LOOP;
END
Раздел исключений EXCEPHON
Раздел EXCEPTION является факультативной частью блока PL/SQL. Если этот раздел отсутствует и встретилась ошибка, блок завершается. Некоторые из ошибок могут и не вызывать непосредственное завершение блока. Раздел EXCEPTION может использоваться для управления стандартными ошибками, которые зафиксированы в PL/SQL, или определенными программистом исключительными ситуациями. Все стандартные ошибки имеют свои имена, по которым можно инициировать обработку этой ошибки. Например, ситуация деления на нуль имеет имя ZEROJIVIDE.
Синтаксис определения, инициирования и обработки определяемой программистом исключительной ситуации следующий:
DECLARE имя_исключительной_ситуации EXCEPTION; -
BEGIN
IF условие THEN
RAISE имя_исключительной_ситуации;
END IF;
EXCEPTION
WHEN имя_исключительной_ситуации THEN предложения_обработки_исключительной_ситуации;'
END:
Здесь показаны основные моменты явного инициирования исключительной ситуации. Сначала в разделе DECLARE объявляется имя исключительной ситуации. В выполняемом разделе эта исключительная ситуация инициируется с помощью предложения RAISE при достижении определенного условия. Наконец, в разделе EXCEPTION располагается обработчик исключительной ситуации, который предпринимает соответствующие действия.
В блоке можно определить, инициировать и обрабатывать множество исключительных ситуаций. В этом случае синтаксис раздела EXCEPTION следующий:
EXCEPTION
WHEN исключительная_ситуация THEN
предложения-Обработки:
WHEN исключительная_ситуация THEN предложения_обработки:
WHEN OTHERS THEN
предложения-Обработки ;
Отметим, что выражение исключительная ситуация по сути может быть списком имен исключительных ситуаций, соединяемых логической связкой OR. Фраза WHEN OTHERS указывает, что соответствующие ему предложения обрабатываются в том случае, когда произошла исключительная ситуация, которая не перечислена в предыдущих предложениях WHEN. Эта фраза позволяет управлять обработкой любой ошибки, которая может встретиться в блоке. Приведем пример обработки исключительных ситуаций.
DECLARE
bad_teacherJd EXCEPTION;
bad_salary_value EXCEPTION;
bad_chief_value EXCEPTION;
BEGIN
EXCEPTION
WHEN bad_teacher_id OR salary_value THEN -- определяемая ошибка ROLLBACK;
WHEN bad_chief_value THEN-- определяемая ошибка
UPDATE TEACHER SET Chief = NULL
WHERE TchPK = tchlD;
COMMIT;
WHEN ZERO_DIVIDE THEN-- стандартная ошибка
INSERT INTO TEACHERLOG VALUES
(SYSDATE. 'Деление на ноль*);
COMMIT;
END;
Выдача сообщений пользователю
Во многих случаях, особенно при обработке исключительных ситуаций, возникает необходимость выдавать пользователю сообщения, чтобы информировать о процессе выполнения программ PL/SQL. В PL/SQL отсутствуют непосредственные команды вывода сообщений, однако имеется специальная функция, которая позволяет организовывать вывод пользователю сообщений. Эта функция называется DBMS_OUTPUT. Она реализована в виде специального объекта Oracle, который называется пакетом.
Например, в описанную выше обработку ситуации деления на ноль можно добавить вывод следующего сообщения
WHEN ZERO_DIVIDE THEN -- стандартная ошибка
INSERT INTO TEACHERLOG VALUES
(SYSDATE, 'Деление на ноль');
DBMS_0UTPUT.put_l1ne('ОШИБКА: ДЕЛЕНИЕ НА НОЛЬ.'):
COMMIT:
Управление транзакциями
PL/SQL в полной мере использует возможности по управлению транзакциями. В частности, вы можете явно фиксировать завершение транзакции или производить ее откат, как это было показано в предыдущих примерах.
Расширения SQL
Включение SQL в среду программирования требует использования расширений. На некоторых из них мы кратко остановимся в следующих разделах.
Использование фраз FOR UPDATE и CURRENT OF
Если вы определяете курсор, на который будут ссылки во фразе CURRENT OF предложений UPDATE или DELETE, необходимо использовать фразу FOR UPDATE в запросе курсора. Например:
DECLARE
CURSOR cl IS SELECT Name. Salary FROM TEACHER WHERE Post = 'профессор* FOR UPDATE:
Если курсор формируется из нескольких таблиц, фразу FOR UPDATE можно использовать для уточнения того, какая из таблиц будет обновляться. Для этого следует указать имя обновляемого столбца (или столбцов). Например, следующий запрос указывает на обновление строк таблицы TEACHER (так как обновляется столбец Salary), но не DEPARTMENT:
DECLARE
CURSOR cl IS SELECT t.Name AS tname. d.Name AS dname
FROM TEACHER t. DEPARTMENT d
WHERE t.DepFK = d.DepPK AND Post = 'ассистент' FOR UPDATE OF Salary:
В предложениях UPDATE и DELETE фраза CURRENT OF используется для того, чтобы сослаться на текущую зафиксированную курсором строку, как это показано в следующем примере:
DECLARE
CURSOR cl IS SELECT Name. Post, Salary FROM TEACHER FOR UPDATE:
BEGIN
OPEN cl:
LOOP
FETCH cl INTO...
UPDATE TEACHER SET Salary = newSal ary
WHERE CURRENT OF cl:
END LOOP:
END
Это так называемые позиционные обновления и удаления, о которых уже было сказано при рассмотрении курсоров в начале этого урока.
Фраза INTO предложения SELECT
PL/SQL предоставляет возможность сохранить результат вычисления запроса в переменной. Для этого используется фраза INTO. Очевидно, что при этом предложение SELECT должно выбирать одну строку. Мы уже пользовались этой возможностью в предыдущих примерах. В следующем предложении:
SELECT Salary *0.10 + Rise INTO bonus
FROM TEACHER
WHERE TchPK = teacherID:
переменной bonus присваивается результат вычисления выражения Salary * 0.10 + Rise, где значения Salary и Rise определяются строкой, выбранной этим предложением SELECT. Еще одной переменной является teacher ID, которая определяет уникальный идентификатор преподавателя.
С помощью фразы INTO можно производить присвоение выбранных значений нескольким переменным, например:
SELECT Name. Dean INTO facName. deanName
FROM FACULTY
WHERE FacPK = 12
Наконец, если переменная объявлена как запись соответствующего типа, ей можно присваивать значения целых строк таблицы, как это показано ниже:
declare'
lectureRec LECTURE^ROWTYPE;
BEGIN
SELECT * INTO lectureRec FROM TEACHER WHERE TchPK = 173
END:
Здесь объявлено, что переменная lectureRec имеет тип строк таблицы LECTURE, поэтому ей можно присваивать значение любой строки этой таблицы.
Фраза RETURNING предложений INSERT и UPDATE
При использовании в PL/SQL предложений INSERT и UPDATE предоставляется возможность использовать фразу RETURNING для указания, что значения изменяемых строк должны запоминаться в соответствующих переменных. Она имеет следующий формат:
RETURNING список_выражений INTO список_переменных
Выражения, задаваемые в списке выражений, могут использовать значения обновляемых столбцов. При обновлении одной строки фраза RETURNING позволяет вычислить выражения, которые присутствуют в списке выражений, и присвоить
их значения переменным PL/SQL. При обновлении нескольких строк значения присваиваются переменным-массивам.
Фраза RETURNING может использоваться и при обновлении представления, если оно определено на одной базовой таблице. В следующем примере значения соответствующих выражений сохраняются в переменных salVar, sal Ri sVar, tchVar, depIDVar:
UPDATE TEACHER
SET Post = 'ассистент*. Salary = Salary + 100. DepPK = 17
WHERE UPPER(Name) = 'ИВАНОВ*
RETURNING Salary * 0.25, Salary + RiseName, DepPK
INTO salVar. salRisVar. tchVar, depIDVar;
Самостоятельная работа
Напишите объявление чувствительного, прокручиваемого, сохраняемого и возвращающего значение курсора с именем MyCursor.
Откройте курсор и выберите 15-ю по порядку строку. Переместите курсор на одну позицию вперед, а затем на две позиции назад.
Напишите объявление типа данных RECORD, который соответствовал бы строкам таблицы FACULTY.
Определите подтип MySalary на основе типа столбца Salary таблицы TEACHER.
Определите две переменных подтипа MySalary со значениями по умолчанию 700 и 850,50.r"
Определите переменную myReference, которая имела бы тип переменной hisRe- ference.
Объявите константу mySalaryConstant, которая принимает значение 1050.
Напишите программу, которая заменяет названия дней недели на их порядковые числа.
Напишите программу, которая увеличивает ставку преподавателей на 10 %, однако производит откат выполнения транзакции, если у очередного преподавателя ставка окажется отрицательной. При этом следует вывести предупреждающее сообщение пользователю.
Подведение итогов
Усвоив материал этого урока, вы научились:
Q создавать курсоры и работать с ними;
0 создавать типы и подтипы PL/SQL;
0 объявлять переменные, константы и курсоры PL/SQL;
0 использовать управляющие структуры PL/SQL;
0 обрабатывать ошибочные ситуации в PL/SQL;
0 выполнять позиционное удаление с помощью курсора;
0 запоминать результаты вычисления запросов, а также вставки и удаления данных.
) УРОК Транзакции и триггеры
Транзакции и триггеры являются механизмами поддержки целостности базы данных. Транзакции позволяют поддерживать целостность в тех случаях, когда происходит программный или аппаратный сбой, который в состоянии вывести базу данных из целостного состояния. Триггеры, в свою очередь, позволяют описывать и поддерживать так называемые процедурные ограничения целостности, которые не могут быть выражены предложением CREATE TABLE.
Использование транзакций
Рассмотрим природу и необходимость использования транзакций на примере. Пусть задано следующее предложение обновления, которое увеличивает на 10 % ставку всех преподавателей, имеющимся в базе данных:
UPDATE TEACHER
SET Salary = Salary *1.1:
С точки зрения пользователя — это атомарная команда по обновлению таблицы базы данных. Однако при ее выполнении происходит обновление всех строк таблицы TEACHER. Если в процессе этого обновления произойдет какой-либо сбой (например, обесточивание сети электропитания), мы не знаем, какие именно строки уже были обновлены, а какие — нет. Единственный способ восстановления результатов этого сбоя — просмотреть все строки таблицы TEACHER, сверить ставку, зафиксированную в базе данных, с той, что имеется в бухгалтерских документах, и там, где обновление не было произведено, внести соответствующие изменения.
Рассмотрим второй пример. Допустим, что принято решение коренным образом изменить систему финансирования в вузе.
Увеличить всему преподавательскому составу ставку на 10 %.
Установить величину надбавки всем преподавателям в размере 25 % от ставки.
Установить размер фонда финансирования кафедр равным 200 % суммарной зарплаты всех ее сотрудников.
Установить размер фонда финансирования факультетов равным 130 % размера фонда финансирования их кафедр.
Для выполнения этого решения в базе данных следует произвести следующие изменения:
UPDATE TEACHER
SET Salary = Salary * 1.1:
UPDATE TEACHER
SET Rise = Salary * 0.25;
UPDATE DEPARTMENT d
SET d.Fund = 2 * (SELECT SUM(Salary + Rise) FROM TEACHER t WHERE t.DepFK = d.DepPK);
UPDATE FACULTY f
SET f.Fund = 1.3 * (SELECT SUM(Fund) FROM DEPARTMENT d
WHERE d.FacFK = f.FacPK):
Только после того, как будут выполнены все четыре приведенных выше предложения обновления, можно будет считать, что база данных перешла в новое состояние, которое действительно соответствует новому состоянию предметной области. До тех пор, пока они все не будут выполнены, в базе данных будет зафиксировано не соответствующее действительности состояние и любое обращение к ней в этот момент будет приводить к выводу некорректных данных.
Еще один пример. Допустим, что администратор базы данных принял решение поменять первичный ключ кафедры (столбец DepPK) с 15 на 1015. Для этого необходимо произвести изменения в трех таблицах:
UPDATE DEPARTMENT SET DepPK=1015 WHERE DepPK = 15;
UPDATE SGROUPSET DepFK=1015 WHERE DepFK = 15;
UPDATE TEACHERSET DepPK=1015 WHERE DepPK = 15;
В процессе выполнения этих трех операций обновления нарушается ссылочная целостность базы данных. Действительно, выполнив команду изменения значения DepPK в DEPARTMENT, мы переходим в состояние, когда значения столбцов DepFK из SGROUP и TEACHER ссылаются на уже не существующий ключ в DEPARTMENT. Это плохо по двум причинам. Во-первых, если в таблицах SGROUP и TEACHER задано ограничение внешнего ключа, такая последовательная замена вообще не допустима. Если этого ограничения нет, то, во-вторых, такое нарушение целостности может сказаться на результатах выполнения запросов других пользователей (вспомним, что большинство СУБД допускают одновременную работу многих пользователей). Положение не спасает и перестановка последовательности обновления таблиц. Целостность базы данных восстановится только после выполнения всех обновлений, то есть после выполнения логической единицы работы — полной замены ключа кафедры во всей базе данных.
Наконец, последний пример. Мы не производим никаких изменений состояния базы данных, а просто хотим узнать, сколько всего преподавателей в вузе и сколько из них кураторов:
SELECT COUNT(*)
FROM TEACHER;
SELECT COUNTCDISTINCT CurFK)
FROM SGROUP;
Мы можем с удивлением обнаружить, что кураторов больше чем преподавателей. Как это могло получиться? Если мы попытаемся выполнить эти два запроса еще раз, кураторов уже будет меньше. Дело в том, что при первой попытке между выполнением первого и второго запроса какой-то другой пользователь в результате выполнения операций обновления временно нарушил целостность базы данных и перевел ее в противоречивое состояние, поэтому мы получили абсурдный результат. К моменту второго выполнения запросов база данных была уже в целостном состоянии. Как бороться с этими нежелательными явлениями? Для этого в базах данных и были введены транзакции.
Транзакция — это последовательность предложений SQL, которые рассматриваются как единое целое. Под этим подразумевается следующее: либо все предложения, содержащиеся в транзакции, выполнятся успешно, либо ни одно из них не будет выполнено. Это свойство поддерживается СУБД, даже если в процессе выполнения транзакции произойдет программный или аппаратный сбой. Транзакции преобразуют базу данных из одного целостного состояния в другое, но в процессе выполнения транзакции допускается нарушение целостности. Транзакция также может гарантировать, что в процессе ее выполнения промежуточное противоречивое состояние базы данных будет невидимым для других пользователей.
Модель транзакции в стандарте SQL
Стандарт SQL специфицирует следующую модель выполнения транзакции.
' О Транзакция может инициироваться только в том случае, когда в текущем сеансе работы нет действующей транзакции.
О Транзакция инициируется началом выполнения некоторых предложений SQL, выполнением специального предложения по инициированию транзакции или выполнением предложения по завершению текущей транзакции, если это предусмотрено соответствующими параметрами этого предложения. Не все предложения SQL приводят к автоматическому инициированию транзакции. Однако такие предложения, как определение объектов базы данных (создание таблиц, представлений, доменов, триггеров, индексов и т. д.), манипулирование данными базы данных (вставка, удаление, обновление и слияние строк таблиц) и выборка данных (предложение SELECT) инициируют транзакцию (о специальных предложениях инициирования и завершения транзакции речь пойдет дальше).
О В теле транзакции можно проставлять так называемые контрольные точки, они позволяют производить откат не всей транзакции, а только до указываемой контрольной точки.
О В процессе выполнения транзакции можно проверять ограничения целостности непрерывно по ходу выполнения предложений, содержащихся в транзакции, либо отложить эту проверку до завершения транзакции.
О Транзакция завершается одним из следующих четырех способов: предложением фиксации завершения транзакции (COMMIT), предложением отката вы-
полнения транзакции (ROLLBACK), успешным или неуспешным завершением программы (вспомним, что к SQL можно обращаться из программ).
Не все СУБД поддерживают эту схему. Далее мы детально рассмотрим использование всех предложений управления транзакциями стандарта SQL. *
Явное инициирование транзакции
Как мы уже отметили, транзакция может инициироваться автоматически при инициировании выполнения определенных предложений SQL либо явно с помощью предложения START TRANSACTION. Напомним также, что транзакция инициируется (явно или автоматически) только в том случае, если в текущем сеансе работы с СУБД отсутствует активная транзакция. В противном случае будет отказано в инициировании новой транзакции. Упрощенный синтаксис предложения инициирования транзакции следующий:
START TRANSACTION [список_параметров]
где список_параметров может определять способ доступа и уровень изоляции. Оба вида параметров являются факультативными.
Способ доступа
Параметр способа доступа указывает, будут ли в транзакции содержаться только запросы на выборку данных или она будет выполнять запросы как на выборку данных, так и на их изменение. Для этого используются следующие альтернативы:
READ {ONLY | WRITE)
Уровень изоляции
Уровень изоляции транзакции SQL определяет степень, в которой на операции определения и/или манипулирования данными в одной транзакции оказывают влияние операции других одновременно выполняемых транзакций. Короче говоря, это степень изоляции одной транзакции от других. Уровень изоляции определяется следующей фразой:
ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE)
Все четыре приведенных выше уровня изоляции гарантируют, что любая транзакция будет выполнена полностью или вообще не будет выполнена. Они также гарантируют, что в процессе выполнения транзакции не будут потеряны произведенные ею обновления. Имеется в виду ситуация, когда две транзакции инициируют одновременное обновление одних и тех же данных.
Отличие уровней изоляции заключается в различной поддержке описанных ниже трех ситуаций, связанных с выборкой данных.
О Считывание незафиксированных измененных данных (dirty read). Транзакция Т1 изменяет значение строки, но не фиксирует это изменение (то есть не выдает команду COMMIT). Затем транзакция Т2 читает эту измененную строку. Если после этого транзакция Т1 производит откат (ROLLBACK) изменений в строке, то получается, что транзакция Т2 прочитала строку, которой фактически нет в базе данных.
О Считывание данных до и после их фиксации (non-repeatable read). Транзакция Т1 считывает строку. Транзакция Т2 затем изменяет или удаляет эту строку и фиксирует (COMMIT) произведенные изменения. Если после этого Т1 попытается повторно прочитать эту строку, то получит измененную строку или вообще обнаружит, что ее нет.
О Строки-призраки (phantom). Транзакция Т1 читает множество строк, которые удовлетворяют некоторому условию. Затем транзакция Т2 вставляет одну или несколько строк, которые удовлетворяют условию поиска первой транзакции. Если после этого транзакция Т1 повторит чтение строк с тем же условием, то получит другой набор строк.
В табл. 17.1. указывается, какие именно ситуации поддерживаются предлагаемыми уровнями.
Таблица 17.1. Поддержка уровнями изоляции различных ситуаций
Уровень изоляции
Считывание незафиксированных данных
Считывание данных до и после их фиксации
Строки-призраки
SERIALIZABLE
Нет
Нет
Нет
REPEATABLE READ
Нет
Нет
Да
READ COMMITTED
Нет
Да
Да
READ UNCOMMITTED
Да
Да
Да
Итак, наиболее высокий уровень изоляции обеспечивает SERIALIZABLE. Сериализуемость означает, что результаты одновременного выполнения транзакций будут такими же, как и их последовательное выполнение. Этот уровень выбирается в стандарте SQL по умолчанию. Следующий уровень, REPEATABLE READ, гарантирует, что транзакция не будет выбирать незафиксированных и промежуточных данных других транзакций, однако все же будет выбирать строки, вводимые в базу данных другими транзакциями. Третий уровень, READ COMMITTED, запрещает только выборку промежуточных незафиксированных данных других транзакций. Наконец, четвертый, самый слабый уровень изоляции, READ UNCOMMITTED, допускает все три ситуации, связанные с влиянием других транзакций на выборку данных.
Если в транзакции указывается способ доступа READ WRITE, уровень изоляции не может быть READ UNCOMMITTED. То есть в этом случае транзакция не может считывать такие строки данных, которые возможно будут обновлены другой транзакцией READ WRITE. Если не указан способ доступа, а уровень изоляции равен READ UNCOMMITTED, по умолчанию подразумевается способ доступа READ ONLY, иначе — READ WRITE.
Успешное завершение транзакции
Поскольку транзакция — это совокупность операций, в такой совокупности необходимо выделить, кроме ее начала, также и конец. Транзакция может завершиться успешно или безуспешно. В этом разделе мы остановимся на процедуре успешного завершения транзакции, а в следующем — на безуспешном.
Транзакция завершается успешно либо неявно в результате успешного завершения программы, которая ее инициировала, либо явно с помощью команды COMMIT. Имейте в виду, что до тех пор, пока транзакция не завершилась успешно, все произведенные ею изменения в базе данных не приобретают статус зафиксированных на постоянной основе изменений. Чтобы объяснить этот тезис, обратимся к примеру. Посмотрим, какова ставка преподавателя Хоренко:
SELECT Salary FROM TEACHER WHERE UPPER(Name) = 'XOPEHKO*:
SALARY
670
Теперь изменим ее на 700:
UPDATE TEACHER SET Salary = 700 WHERE UPPER(Name) = 'XOPEHKO*;
1 строка обновлена.
Убедимся, что обновление действительно произошло:
SELECT Salary FROM TEACHER WHERE UPPER(Name) = 'XOPEHKO*:
SALARY
700
Вроде бы все правильно. А теперь произведем аварийное завершение работы той программы, в которой мы инициировали эти запросы. Если, например, вы работаете в Oracle SQL*Plus, закройте программу щелчком на кнопке Закрыть в правом верхнем углу окна этой программы. Теперь опять войдите в эту программу и посмотрите ставку Хоренко.
SELECT Salary FROM TEACHER WHERE UPPER(Name) = 'XOPEHKO*;
SALARY
670
Как видите, ставка не изменилась — производимые в транзакции изменения хотя и видны в самой транзакции, не фиксируются в базе данных, и если транзакция завершается аварийно, все незафиксированные изменения исчезают, то есть восстанавливаются значения, которые были до изменения. Это относится не только к изменяемым строкам данных, но и к вновь вставляемым и удаляемым. Завершение транзакции и фиксация произведенных ею изменений производится командой COMMIT, которая имеет следующий простой синтаксис (ключевое слово WORK является вспомогательным и никакого влияния не оказывает):
COMMIT [WORK] [AND [NO] CHAIN];
Этой командой все произведенные в транзакции изменения фиксируются в базе данных как постоянные и после этого не исчезают. Транзакция завершает работу. Если временная таблица была определена с фразой ON COMMIT DELETE (см. урок И) и при выполнении транзакции изменялась, все строки такой таблицы будут удалены. Если для транзакции было указано, что проверка ограничений целостности откладывается до завершения транзакции (см. раздел ниже), то перед действительным завершением транзакции производится проверка необходимых ограничений
целостности. И если хотя бы одно из них нарушается все произведенные транзакцией изменения в базе данных аннулируются (происходит откат транзакции).
Вернемся к предыдущему нашему примеру. Если после изменения ставки Хорен- ко мы хотим, чтобы эти изменения действительно были зафиксированы в базе данных, мы должны записать следующее:
UPDATE TEACHER SET Salary = 700 WHERE UPPER(Name) = 'ХОРЕНКО':
COMMIT;
Фиксация обновлений завершена.
И теперь мы можем больше не беспокоиться о том, что обновленное значение будет потеряно.
Автоматическое инициирование следующей транзакции
Итак, по команде COMMIT транзакция завершается. Однако если мы воспользуемся фразой AND CHAIN автоматически инициируется новая транзакция SQL, с теми же значениями параметров способа доступа и уровня изоляции, что и у завершившейся транзакции. Фраза AND NO CHAIN указывает, что новая транзакция не инициируется автоматически. По умолчанию предполагается AND NO CHAIN.
Откат транзакции
Второй вариант завершения транзакции — аварийный. В этом случае все произведенные в транзакции изменения базы данных аннулируются и база данных возвращается в то состояние, которое она имела до начала выполнения транзакции. Аварийное завершение транзакции инициируется автоматически при аварийном завершении программы, которая эту транзакцию инициирована, или специальной командой ROLLBACK. Аварийный вариант завершения транзакции также называется откатом — по имени предложения, которое инициирует такое завершение. Предложение ROLLBACK имеет следующий синтаксис:
ROLLBACK [WORK] [AND [NO] CHAIN] [TO SAVEPOINT имя_точки_сохранения];
Функционирование команды ROLLBACK зависит от того, используется ли в ней контрольная точка или нет.
Завершение транзакции с откатом
Завершение транзакции с откатом всех изменений, которые были произведены этой транзакцией в базе данных, происходит по команде ROLLBACK. Фраза AND [NO] CHAIN имеет тот же смысл, что и в предложении COMMIT. Приведем пример использования отката. Сначала посмотрим, чему равна ставка ассистентов:
SELECT Name, Salary FROM TEACHER WHERE Post = 'ассистент*-;
NAME SALARY
Вибровский 570
Воропаев570
Козлутин530
Мартынов530
Изменим им всем размеры ставки:
UPDATE TEACHER SET Salary= 600WHEREName ='Вибровский';
UPDATE TEACHER SET Salary= 630WHEREName ='Воропаев';
UPDATE TEACHER SET Salary= 580WHEREName ='Козлутин';
UPDATE TEACHER SET Salary= 590WHEREName =’Мартынов';
Убедимся, что эти изменения отражены в базе данных:
SELECT Name, Salary FROM TEACHER WHERE Post = 'ассистент';
NAMESALARY
Вибровский600
Воропаев630
Козлутин580
Мартынов590
Решаем отказаться от произведенных изменений:
ROLLBACK;
Откат завершен.
Убедимся, что старые значения ставок восстановлены:
SELECT Name, Salary FROM TEACHER WHERE Post = 'ассистент';
NAMESALARY
Вибровский570
Воропаев570
Козлутин530
Мартынов530
Итак, после отката все ранее произведенные изменения ставки четырех ассистентов были аннулированы и восстановлены старые значения.
Указывать команду ROLLBACK после COMMIT бессмысленно, так как при выполнении предложения COMMIT изменения базы данных, инициированные в транзакции, оказываются необратимыми, их уже нельзя отменить. В процессе же выполнения транзакции можно в любой момент отменить все произведенные изменения и вернуть состояние базы данных к тому, которое она имела до начала выполнения транзакции.
Откат по контрольной точке
Контрольная точка — это позиция расположения в транзакции. Контрольная точка располагается в том месте транзакции, где находится предложение SAVEPOINT. Это предложение имеет следующий простой синтаксис:
SAVEPOINT имя_точки_сохранения
В транзакции могут определяться много точек сохранения. Точка сохранения может быть уничтожена такой командой:
RELEASE SAVEPOINT имя_точки_сохранения
Контрольные точки используются для того, чтобы можно было произвести откат транзакции не полностью, а, частично — вплоть до той команды транзакции,
которая располагается сразу же после контрольной точки. Еще одна особенность отката до контрольной точки заключается в том, что в этом случае транзакция не завершается. То есть оставшиеся изменения можно зафиксировать. Поскольку транзакция не завершается, в предложении отката нельзя одновременно использовать фразы AND CHAIN и ТО SAVEPOINT. Приведем вариант предыдущего примера с использованием точек сохранения.
При обновлении каждой строки проставляем контрольную точку:
UPDATE TEACHER SET Salary = 600 WHERE Name = 'Вибровский':
SAVEPOINT One_Teacher_Updated;
UPDATE TEACHER SET Salary = 630 WHERE Name = 'Воропаев*;
SAVEPOINT TwO-TeachersJJpdated;
UPDATE TEACHER SET Salary = 580 WHERE Name = ’Козлутин';
SAVEPOINT Three_Teachers_Updated;
Производим откат до первой контрольной точки. При этом транзакция не завершается:
ROLLBACK ТО SAVEPOINT One_Teacher_Updated;
Продолжаем транзакцию. Обновляем еще одну строку:
UPDATE TEACHER SET Salary = 590 WHERE Name = 'Мартынов*;
Завершаем транзакцию с фиксацией изменений:
COMMIT:
Проверяем результаты транзакции:
SELECT Name, Salary FROM TEACHER WHER Post = 'ассистент*:
NAME SALARY
Вибровский 600
Воропаев570
Козлутин530
Мартынов590
Как видим, вторая и третья строки не изменились, так как по ним был произведен откат. Первая строка в область отката не вошла, поэтому она изменилась. Наконец, четвертая строка была изменена уже после отката.
Точки сохранения оказываются полезными в интерактивных программах, так как они позволяют выделять и именовать промежуточные шаги программы. Это позволяет более гибко управлять большими сложными программами. Например, можно проставить точки сохранения в длинной цепочке предложений обновления. При этом, обнаружив ошибки, можно будет произвести откат к нужному месту и тем самым не выполнять повторно все обновления, как если бы был произведен откат всей транзакции.
Точки сохранения также оказываются полезными при написании прикладных программ. Если программа содержит подпрограммы, можно проставить точки сохранения перед обращением к каждой из подпрограмм. Если подпрограмма завершилась аварийно, можно легко восстановить базу данных на момент до выполнения этой подпрограммы.
Установка характеристик транзакции
Параметры транзакции (способ доступа и уровень изоляции) можно установить до инициирования транзакции. Это достигается с помощью предложения SET TRANSACTION , которое имеет следующий синтаксис:
SET TRANSACTION {способ_доступа | уровень_изоляции}...
Этой командой можно установить не более одного способа доступа и/или уровня изоляции, но хотя бы один из них должен быть задан. Выполнение этого предложения во время транзакции запрещается. Предложение SET TRANSACTION указывает характеристики последующей транзакции, а если до начала очередной транзакции указано несколько предложений SET TRANSACTION, принимается во внимание последнее. Предложение SET TRANSACTION действует только для последующей транзакции и не оказывает воздействия на транзакцию, которая следует за ней.
SET TRANSACTION READ ONLY ISOLATION LEVEL SERIALIZABLE;
SELECT Name FROM TEACHER WHERE TchPK = 2;
NAME
Хоренко
UPDATE TEACHER SET Post = 'преподаватель' WHERE Name = 'Воропаев';
*.
ошибка в строке 1;
ORA-01456: вставка/удаление/обновление данных невозможны внутри READ ONLY транзакции
Прокомментируем этот пример. Первое предложение устанавливает параметры последующей транзакции. Возникает вопрос, где же инициирование последующей транзакции? Вспомним, что транзакция инициируется либо явно, командой START TRANSACTION, либо автоматически по выполнении одной из подходящих команд SQL. К таким относится предложение SELECT. Это предложение отработало нормально, а следующее за ним предложение UPDATE не было выполнено, так как мы указали, что в транзакции будет выполняться только выборка данных из базы данных, а не изменение. Об этом свидетельствует выведенное сообщение об ошибке. Выполняемые далее предложения SELECT также будут принадлежать текущей транзакции. И только по выполнении команды COMMIT транзакция будет завершена.
Установка проверки ограничений целостности
С таблицами могут быть связаны ограничения целостности. Всякое изменение данных в таблицах может повлечь нарушение этих ограничений. СУБД должна поддерживать объявленные ограничения целостности и не допускать такие изменения в базе данных, которые эти ограничения нарушают. Проверка правильности изменений данных с точки зрения их целостности может проводиться сразу после выполнения предложения манипулирования, или эта проверка может быть отложена до завершения транзакции.
Необходимость в откладывании проверки целостности объясняется тем, что некоторая последовательность предложений манипулирования базой данных может временно переводить ее в противоречивое состояние и только по завершению такой последовательности команд база данных возвращается в целостное
состояние. Примеры таких изменений мы приводили в начале этого урока. Для установки момента проверки ограничений целостности в транзакции используется предложение SET CONSTRAINTS, которое имеет следующий синтаксис:
SET CONSTRAINTS {ALL | список_имен_ограничений} [DEFERRED | IMMEDIATE};
Это предложение может располагаться как внутри транзакции, так и вне какой-либо транзакции. Если оно располагается внутри транзакции, то указывает на режим проверки ограничений целостности для нее, а если вне — то для последующей транзакции. По одному такому предложению можно указывать момент проверки одного или нескольких конкретных ограничений целостности или для всех. Ключевое слово DEFERRED указывает на откладывание проверки, a IMMEDIATE — на немедленную проверку целостности по мере выполнения соответствующих предложений манипулирования. Детальное описание возможностей по откладыванию проверки ограничений целостности дано в уроке 12.
Блокировка транзакций
Большинство СУБД позволяют множеству пользователей одновременно работать с одной и той же базой данных. Это означает, что одновременно могут работать множество транзакций. Поскольку транзакции могут производить доступ к одним и тем же данным как для их совместного чтения, так и совместного обновления, могут возникать нежелательные эффекты. Для управления параллельными процессами и предотвращения нежелательных воздействий одних транзакций на другие в СУБД разрабатываются специальные механизмы. Одним из них является механизм блокирования, главная идея которого достаточно проста.
Если транзакции нужны гарантии, что некоторый объект или ресурс (вся база данных, таблица, строка или столбец), в котором она заинтересована, не будет изменен другой транзакцией каким-либо непредсказуемым образом в течение требуемого промежутка времени, она устанавливает блокировку этого объекта. Результат блокировки заключается в том, чтобы изолировать этот объект от других транзакций и, в частности, предотвратить его изменение средствами этих транзакций. Для транзакции, таким образом, имеется возможность выполнять предусмотренную в ней обработку, располагая определенными знаниями о том, что объект в запросе будет оставаться в стабильном состоянии до тех пор, пока данная транзакция этого пожелает. Существуют различные алгоритмы и механизмы блокировок, с которыми можно познакомиться в специальной литературе. Механизмы блокировок не являются составной частью стандарта SQL, хотя во многих СУБД они используются.
Использование триггеров
В этом разделе мы рассмотрим механизм триггеров, предлагаемый для инициирования необходимых действий при наступлении определенных событий. Мы рассмотрим возможности стандарта SQL по описанию триггеров, а затем рассмотрим дополнительные его возможности, предлагаемые в Oracle.
Что такое триггер базы данных?
Существует такое понятие, как событийно управляемые действия. Смысл его заключается в том, что в рассматриваемой предметной области фиксируется множество правил вида «событие -> действие». Интерпретирующая система отслеживает все происходящие в предметной области события, и при наступлении одного из тех, которые приведены в списке, инициируется соответствующее ему действие. В этом случае детерминированная последовательность выполняемых действий отсутствует .
Управление такой системой заключается в том, чтобы находиться в состоянии ожидания событий и активировать соответствующие происшедшим событиям действия. Примером может служить следующее описание порядка работы магазина:
О в 8.00, что соответствует открытию магазина, сбросить в нулевое состояние счета всех кассовых аппаратов;
О в 9.00 подготовить обобщающий отчет о продажах за прошлый день;
О при поступлении из любого кассового аппарата информации об оформленной покупке занести эти данные в базу;
О в 18.00, что соответствует закрытию магазина, произвести сводную ревизию всех покупок за день.
В этом примере три события привязаны к временным вехам и одно к операции покупки/продажи. Нечто подобное существует и в базах данных. Здесь события привязываются к изменению состояния системы баз данных, а действия представляют собой совокупность специальным образом оформленных процедур SQL.
Триггер базы данных — это процедура, которая хранится в виде объекта базы данных и выполнение которой неявно инициируется при наступлении определенных событий. Как правило, такими событиями являются изменения в состоянии базы данных, которые инициируются предложениями INSERT, UPDATE или DELETE по отношению к соответствующей таблице базы данных. Однако в общем случае события, активирующие триггеры, могут быть связаны не только с базой данных. Триггеры расширяют стандартные возможности СУБД по управлению базами данных. Список возможных вариантов использования триггеров приводится в конце раздела.
Впервые триггеры были введены в стандарт только в 1999 году (SQL3). К этому времени триггеры уже около 20-ти лет существовали в развитых СУБД. Стандарт SQL обобщил те возможности, которые авторы стандарта посчитали полезными. В связи с этим ситуация в настоящий момент такова: общая концепция описания и использования триггеров, поддерживаемая в СУБД, совпадает с предложениями стандарта SQL, однако практически все СУБД имеют свои специфические особенности. В связи с этим мы сначала опишем триггеры согласно стандарту SQL, а затем приведем их специфические особенности в Oracle.
ПРИМЕЧАНИЕ Далее при демонстрации примеров функционирования триггеров мы будем использовать их определение в синтаксисе Oracle. Это прежде всего касается тела триггера.
Составляющие триггера
Синтаксис определения триггеров в стандарте SQL следующий:
CREATE TRIGGER имя_триггера время_инициирования_триггера
событие_триггера ON имя_таблицы
[REFERENCING список_переменных_или_таблиц_перехода]
Еуровень_триггера]’
[условие_триггера]
действие_триггера
Как видим, описание триггера состоит из многих составляющих, которые мы далее и рассмотрим.
Заголовок триггера
Заголовок триггера предназначен для идентификации триггера. Он имеет следующий синтаксис:
CREATE TRIGGER имя_триггера
Триггер — это именованный объект схемы базы данных. Имя триггера должно быть уникальным среди имен триггеров схемы базы данных.
Указание момента инициирования триггера
При определении триггера предоставляется возможность указать момент инициирования выполнения его тела, а именно — должен ли триггер быть инициирован перед выполнением предложения-события {триггер предобработки) или после {триггер постобработки). Для этого в SQL используются фразы BEFORE или AFTER. Эти оба вида триггеров применяются как в триггерах над строками, так и в триггерах над предложением (см. далее).
Триггеры предобработки (или, как их еще называют, бифор-триггеры) инициируются до того, как будет выполнено их предложение-событие. Триггеры этого типа обычно используются в двух случаях.
О Действие триггера должно определить, является ли допустимым использование предложения-события в текущем контексте. Использование в этом случае триггера предобработки позволяет аннулировать нежелательное выполнение предложения-события.
О До выполнения предложений-событий INSERT или UPDATE следует получить специфические значения тех или иных столбцов.
Триггеры постобработки (которые также называются афтер-триггерами) инициируются после выполнения их предложений-событий. Они обычно используются, когда триггер должен дополнить результаты выполнения предложения-события, как это показано в следующем примере.
Допустим, имеется таблица, в которой будут регистрироваться некоторые действия, выполняемые над таблицей FACULTY:
CREATE TABLE FacultyLog (LogDate DATE, Action VARCHARC255)):
Определим триггер, который после завершения выполнения обновления фонда в таблице FACULTY записывает в журнал регистрации изменений FacultyLog соответствующую строку:
CREATE TRIGGER LogFacFundUpdate AFTER
UPDATE OF Fund ON FACULTY
BEGIN
INSERT INTO FacultyLog (LogDate, Action)
VALUES (SYSDATE, 'Фонд обновлен');
END;
Теперь, если мы выполним обновление фонда любого из факультетов:
UPDATE FACULTY SET Fund = 30000 WHERE FacPK = 1;
то в файле журнала появится соответствующая строка:
SELECT TO_CHAR(LogDate, 'DD-MM-YYYY HH:MI:SS') "Дата", Action "Действие"-
FROM FacultyLog;
ДатаДействие
12-01-2006 08:58:20 Фонд обновлен
Событие триггера
В стандарте SQL в качестве событий триггера могут выступать только изменения состояния базы данных. Они, естественно, связаны с командами вставки, изменения и удаления строк таблицы. Событие триггера специфицируется следующим образом:
INSERT | DELETE | {UPDATE [OF список_столбцов]}
Как видите, с триггером может быть связано только одно событие. Если предложением-событием является UPDATE, можно добавить факультативный список столбцов. Если они указаны, триггер инициируется при их обновлении. Если список столбцов отсутствует, триггер инициируется при обновлении любого столбца. В зависимости от вида события говорят о триггерах вставки, удаления и обновления.
Объект триггера
Объект триггера специфицируется фразой:
ON имя_таблицы
Как видим, в стандарте SQL в качестве объекта триггера может выступать только таблица базы данных, причем только одна.
Ссылочные имена триггера
Совокупность всех удаляемых, вставляемых или заменяемых в триггере строк называется таблицей переходов. Для триггера удаления имеется одна таблица перехода, которая называется старой таблицей переходов. Для триггера вставки имеется также одна таблица переходов, которая называется новой таблицей переходов. Для триггера обновления существует как старая таблица переходов (строки, которые заменяются), так и новая (строки, на которые производится замена).
Стандарт SQL предполагает существование специальных переменных, которые позволяют ссылаться на таблицы переходов в теле триггера. Для триггеров на уровне предложения (об уровнях триггера см. далее) значением соответствующей переменной является вся таблица перехода. Для триггеров на уровне строки переменная принимает значение соответствующей строки таблицы переходов и называется переменной перехода. Когда при обновлении на уровне строк базовой таблицы создаются две таблицы переходов (старая и новая), переменные этих таблиц переходов попарно синхронизированы. То есть одна из них указывает на строку до обновления, а другая — на ту же строку после обновления. Для указания имен этих четырех переменных используется приводимая ниже конструкция:
REFERENCING {OLD [ROW] [AS] имя_старой_переменной_перехода | NEW [ROW] [AS] имя_новой_переменной_перехода | OLD TABLE [AS] имя_старой_таблицы_перехода | NEW TABLE [AS] имя_новой_таблицы_перехода}...
Каждый из четырех вариантов может присутствовать в списке только один раз. В связи с ограничениями на существование старых (новых) таблиц и переменных переходов в зависимости от вида события допускаются не все варианты определения ссылочных имен — они представлены в табл. 17.2.
Таблица 17.2. Допустимые варианты определения ссылочных имен
Событие Вариант
INSERT
NEW ROW, NEW TABLE
DELETE
OLD ROW, OLD TABLE
UPDATE
любой
Кроме того, если определяется триггер на уровне строки (см. далее), можно указать имена только для вариантов NEW ROW и OLD ROW.
Уровень триггера
Уровень триггера определяется синтаксически одной из следующих форм:
FOR EACH {ROW | STATEMENT}
Тем самым можно указать, сколько раз триггер будет выполняться по отношению к инициирующему его событию. Возможны два варианта.
О По одному разу относительно каждой строки, которая будет подвергнута воздействию предложением-событием триггера (фраза FOR EACH ROW). В этом случае говорят, что это триггер уровня строки (или триггер над строками)}
О Один раз относительно предложения-события независимо от того, сколько строк оно обрабатывает (фраза FOR EACH STATEMENT). В этом случае говорят, что это триггер уровня предложения (или триггер над предложением).
Триггер над строками инициируется всякий раз, когда происходит обработка строки таблицы. Например, предложение UPDATE может обновлять множество строк таблицы и при этом триггер над строками инициируется для каждой обновляемой строки. Если предложение-событие не оказывает воздействия ни на одну строку, триггер над строками вообще не выполняется.
Приведем пример триггера над строками. Допустим, мы решили регистрировать обновления ставок преподавателей. Для этого создадим таблицу:
CREATE TABLE TeacherLog (
TchlD INTEGER,
LogDate DATE.
OldSalary NUMBER(6, 2),
Newsalary NUMBERC6, 2));
В ней мы будем сохранять идентификатор преподавателя, дату изменения ставки, значение ставки до обновления и после. Теперь создадим триггер:
CREATE TRIGGER LogSalUpdate AFTER
UPDATE OF Salary ON TEACHER
FOR EACH ROW
BEGIN
INSERT INTO TeacherLog (TchlD, LogDate, OldSalary, NewSalary)
VALUES (:NEW.TchPK. SYSDATE, :OLD.Salary. :NEW.Salary);
END;
Триггер создан.
Здесь :NEW и :OLD являются ссылочными именами на новые и старые переменные перехода в синтаксисе Oracle. Теперь увеличим на 10 % ставку доцентов и посмотрим, что будет зафиксировано в таблице TeacherLog.
UPDATE TEACHER SET Salary = Salary *1.10 WHERE LOWER(Post) = 'доцент';
4 строк обновлено.
SELECT * FROM TeacherLog;
TCHID LOGDATE OLDSALARY NEWSALARY
4 12.01.2006
830
913
6 12.01.2006
770
847
7 12.01.2006
890
979
14 12.01.2006
770
847
Как видим, по одному предложению обновления в журнале регистрации сформировано четыре строки, так как наш триггер является триггером на уровне строк. Триггер на уровне предложения обрабатывается только один раз относительно предложения-события независимо от того, сколько строк подвергаются воздействию этого предложением (даже если ни одна строка не будет обработана!). Например, если предложение-событие предполагает удаление многих строк, его триггер, описанный на уровне предложения, будет отработан только один раз, даже когда предложение-событие не удалит ни одной строки.
Триггеры на уровне предложения оказываются полезными в том случае, если их действие не зависит от предоставляемых предложением-событием данных, в частности от обрабатываемых строк. Такими являются триггеры, поддерживающие специальные механизмы безопасности данных, которые, например, связаны со временем или пользователем, или осуществляющие регистрацию обращений к таблицам базы данных.
Условие триггера
Условие триггера определяет логическое выражение, истинность которого разрешает выполнить тело триггера. Если условие принимает значения FALSE или UNKNOWN, триггер не выполняется. Синтаксис условия следующий:
WHEN (условие)
где условие — любое допустимое в SQL условное выражение. Ограничение триггера задается только в триггерах над строками. При его наличии условие проверяется на каждой строке, которая должна инициировать триггер. Если выражение оказывается истинным запускается на выполнение тело триггера. Если же выражение принимает значение FALSE или UNKNOWN тело триггера не выполняется для такой строки. Приведем пример условного триггера.
CREATE TRIGGER DepFundChanged AFTER
UPDATE ON DEPARTMENT
FOR EACH ROW
WHEN (NEW.Fund <> OLD.Fund)
BEGIN
UPDATE FACULTY
SET FACULTY.Fund = (SELECT SUM(Fund) + 10000 FROM DEPARTMENT WHERE DEPARTMENT.FacFK =‘:NEW.FacFK)
WHERE FACULTY.FacPK = :NEW.FacFK;
END;
Это триггер постобработки, который инициируется командой обновления таблицы DEPARTMENT. Условием выполнения триггера является изменение значения фонда финансирования кафедры. В этом случае тело триггера подсчитывает новое значение фонда финансирования факультета, которому принадлежит кафедра. То есть в данном случае предполагается, что фонд факультета должен автоматически подсчитываться равным сумме фондов всех его кафедр плюс 10 000.
Действие триггера '
Согласно стандарту SQL действие триггера представляет собой либо отдельное допустимое предложение SQL, либо совокупность таких предложений, задаваемых в соответствии с таким синтаксисом:
BEGIN
{80Е_предложение;}...
END
Таким образом, стандарт предполагает, что тело триггера может состоять из совокупности предложений SQL.
Удаление триггера
Как и любой другой объект базы данных, триггер может быть удален. Это производится с помощью следующего предложения:
DROP TRIGGER имя триггера
Переопределение триггера в стандарте SQL не предусматривается. В этом случае предполагается его удаление и последующее повторное определение с новыми параметрами.
Триггеры в Oracle
В Oracle возможности по созданию триггеров наиболее развитые по сравнению с другими СУБД. Поэтому в данном разделе мы кратко опишем те дополнительные возможности триггеров Oracle, которые отсутствуют в стандарте SQL.
Заголовок триггера
Имеет дополнительную возможность, которая синтаксически выражается факультативной фразой OR REPLACE:
CREATE [OR REPLACE] TRIGGER имя_триггера
Эта фраза указывает на возможность переопределения уже существующего триггера без его предварительного уничтожения.
Указание момента инициирования триггера
Предоставляется возможность указать, что определяемый триггер выполняется вместо предложения-события. Для этого используется фраза INSTEAD OF и сами триггеры называются замещающими (или инстидоф-триггерами). Такой триггер может быть определен только для представлений, которые не могут быть непосредственно модифицированы с помощью предложений ЯМД (INSERT, DELETE, UPDATE). Для триггеров этого типа предложение-событие никогда не выполняется, а вместо него отрабатывается тело триггера. Триггеры этого типа производят операции обновления, вставки и удаления непосредственно в таблицах, на которых определены представления.
Пользователи могут писать обычные предложения INSERT, DELETE или UPDATE по отношению к таким представлениям, а вместо них будут отработаны замещающие триггеры невидимым для пользователя образом. И при этом они производят корректные операции манипулирования над базовыми таблицами. По умолчанию замещающие триггеры активизируются для каждой строки.
Как мы уже знаем, существуют серьезные ограничения на модификацию представлений. Все необновляемые представления, тем не менее, могут быть обновлены с помощью замещающих триггеров. Приведем пример такого использования замещающего триггера для замены строк. Допустим, имеется следующее представление, которое содержит все номера корпусов, содержащиеся в трех таблицах учебной базы данных (FACULTY, DEPARTMENT, ROOM).
CREATE VIEW ALL_BUILDINGS (Building) AS
SELECT Building FROM FACULTY
UNION
SELECT Building FROM DEPARTMENT
UNION
SELECT Building FROM ROOM;
Пусть номер корпуса 6 поменялся — на 6/А. Теперь, если мы попробуем поменять этот номер сразу во всех трех таблицах через наше представление ALLJUIL- DINGS, получим отказ:
UPDATE ALL_BUILDINGS SET Building = '6/A' WHERE Building = '6';
UPDATE ALLJUILDINGS SET Building = '6/A' WHERE Building = '6' *
ошибка в строке 1:
ORA-01732: обработка данных для данного предст. пользователя не разрешена
Дело в том, что представление ALLJUILDINGS является необновляемым в связи с тем, что оно содержит операторы объединения таблиц (UNION). Однако с помощью замещающего триггера эта проблема решается. Создадим следующий триггер:
CREATE TRIGGER UpdateJuildings INSTEAD OF
UPDATE ON ALLJUILDINGS
FOR EACH ROW
BEGIN
UPDATE FACULTY SET Building = :NEW.Building
WHERE Building = :OLD.Building;
UPDATE DEPARTMENT SET Building = :NEW.Building
WHERE Building = :OLD.Building;
UPDATE ROOM SET Building = ;NEW.Building
WHERE Building = :OLD.Building:
END;
Он инициируется вместо выполнения операции обновления нашего представления и последовательно изменяет номера корпусов во всех трех таблицах. Теперь наше предложение обновления выполнится:
UPDATE ALLJUILDINGS SET Building = '6/A' WHERE Building = *6';
строка обновлена.
He удивляйтесь, что подсказка указала на обновление одной строки. Это обновление одной строки представления, а фактически произошло обновление шести строк трех таблиц учебной базы данных.
Событие триггера
Допускается специфицировать события трех типов.
О Определение объектов базы данных, к которым относятся, в частности, известные нам предложения CREATE, ALTER и DROP.
О Манипулирование базой данных, к которым относятся команды INSERT, DELETE, UPDATE. Однако с одним триггером можно связать сразу несколько событий. Любое из указанных событий будет запускать триггер. В этом случае предусматривается использование так называемых 'условных предикатов для обнаружения, какой тип предложения манипулирования действительно инициировал триггер. Таким образом, можно создать один триггер, который выполняет различный программный код в зависимости от предложения, инициировавшего триггер.
О Операции над базой данных в целом (так называемые системные события), к которым относятся, например, возникновение системной ошибки, подключение к системе пользователя и программы или их отключение, открытие или закрытие базы данных и др.
Объект триггера
Для событий, связанных с манипулированием базой данных, к объектам триггера, помимо базовых таблиц, относятся также представления. Кроме того, для событий двух других видов объектами триггера являются схема базы данных и вся база данных в целом.
Действие триггера
Выразительные способности тела триггера намного выше по сравнению со стандартом SQL в связи с возможностью использовать язык программирования PL/SQL.
Включение, отключение и переименование триггера
С помощью предложение ALTER TRIGGER предоставляется возможность включения, выключения и переименования триггера. Выключение (деактивирование) означает, что триггер не будет выполняться при наступлении соответствующего ему события. После его включения (повторного активирования) триггер принимает свой обычный статус.
Дополнительные аспекты использования триггеров
В данном разделе мы прежде всего обратим ваше внимание на некоторые специфические особенности использования триггеров, а именно их применение для поддержки ограничений целостности, использование триггеров совместно с транзакциями, недопустимость определения рекурсивных триггеров. Затем кратко перечислим их возможное использование для решения конкретных задач, которые возникают при эксплуатации баз данных.
Выполнение триггеров и проверка целостности
Предложение SQL может инициировать выполнение множества триггеров описанных выше четырех типов. Предложение-событие, а также предложения в теле триггера могут инициировать различные процедуры проверки целостности. Более того, триггеры могут инициировать выполнение других триггеров, которые также могут инициировать процедуры проверки целостности. Таким образом, одно предложение манипулирования может вызвать целую лавину проверок целостности. В связи с этим при использовании той или иной СУБД внимательно ознакомьтесь с используемыми в ней правилами инициирования триггеров и проверок целостности.
Триггеры и транзакции
С каждым предложением манипулирования SQL автоматически связывается транзакция, которая обеспечивает полностью выполнение всего предложения целиком или его откат в случае неудачи. Если такое предложение является предложением-событием каких-то триггеров, все инициируемые по нему триггеры автоматически включаются в эту транзакцию. Так что само предложение манипулирования и инициируемые им транзакции составляют единое целое и выполняются в составе одной транзакции. Можно предположить, что их выполнение происходит следующим образом.
Неявно инициируется транзакция перед выполнением предложения манипулирования таблицей базы данных.
Выполняется предложение манипулирования таблицей (INSERT, UPDATE, DELETE).
Вызывается и выполняется триггер.
. 4. В зависимости от результата выполнения триггера транзакция либо успешно завершается, либо происходит ее откат.
Рекурсивные триггеры
Рекурсивный триггер содержит в своем теле предложение манипулирования таблицей, которые (предложение и таблица) составляют событие этого триггера, В этом случае тело триггера инициирует событие, которое вызывает выполнение самого триггера. Приведем пример:
CREATE TRIGGER TeacherUpdated AFTER
UPDATE ON TEACHER
FOR EACH ROW
BEGIN
UPDATE TEACHER SET... WHERE...;
END;
Такая рекурсия приводит к зацикливанию выполнения, поэтому рекурсивные триггеры не допустимы.
Использование триггеров
Мы уже приводили некоторые примеры использования триггеров. Другие возможные варианты использования триггеров следующие:
О автоматическое вычисление значений производных (вычисляемых) столбцов;
О предотвращение выполнения недопустимых транзакций;
О выполнение сложных проверок защиты данных;
О поддерживание сложных ограничений целостности, действующих в предметной области;
О возможность регистрации событий, происходящих в базе данных;
О сбор статистики по доступу к таблицам базы данных.
Самостоятельная работа
Напишите предложение SQL, которое производит инициирование транзакции только для чтения с сериализуемым уровнем изоляции.
Напишите транзакцию, в которой производится увеличение фондов всех факультетов на 10 % и завершите выполнение транзакции откатом.
Напишите транзакцию, в которой выполняются следующие действия: ассистентам ставка увеличивается на 10 %, доцентам — на 8 %, профессорам — на 7 %. Перед каждой операцией обновления проставьте контрольные точки. Посмотрите результат обновления. Произведите откат до второй контрольной точки. Увеличьте надбавку всем преподавателям на 5 %. Завершите транзакцию фиксацией результатов ее работы. Проанализируйте полученные результаты.
В транзакции установите отсрочку проверки ограничений целостности. Из таблицы FACULTY удалите строку, относящуюся к факультету информатики. Завершите транзакцию. Проанализируйте, что получилось.
Напишите триггер, который позволяет только увеличивать размер фонда финансирования факультетов.
Напишите триггер, который фиксирует в журнале сведений о преподавателях все операции манипулирования, производимые над таблицей TEACHER.
Подведение итогов
Усвоив материал этого урока, вы научились:
0 производить явное инициирование транзакции с указанием ее параметров;
0 завершать транзакцию с фиксированием результатов ее работы или с откатом;
0 проставлять в транзакции контрольные точки и производить откат до них;
0 устанавливать характеристики транзакции;
0 производить в транзакции отсрочку проверки целостности;
0 создавать и удалять триггеры.
^SjyppK^SjyppKОбъектно-ориентирова нныйSQL
^SjyppK
^SjyppK
Объектно-ориентированная технология является наиболее популярной в настоящее время при анализе, проектировании и разработке программного обеспечения. Большинство современных языков программирования расширены до включения в них средства описания объектов и манипулирования ими.
В таких языках остро стоит проблема запоминания объектов для постоянного хранения с последующим их использованием при любом другом вызове программы. Это породило исследования в области баз данных, позволяющих хранить объекты и манипулировать ими, а также разработку таких СУБД. Можно выделить два направления разработки: объектно-ориентированные СУБД и объектно-реляционные СУБД. Если первое направление предполагает создание чисто объектных СУБД, то второе — расширение существующих реляционных СУБД до включения в них объектно-ориентированной парадигмы.
Объектно-ориентированный SQL является примером второго подхода к внедрению объектной технологии в базы данных. На этом уроке мы в общих чертах рассмотрим объектно-ориентированные возможности SQL, следуя его стандарту.
Основные объектные возможности SQL
В этом разделе мы кратко опишем те основные особенности SQL, которые делают его объектно-ориентированным.
О Большие объекты данных. В SQL имеются специальные типы данных, которые позволяют хранить и манипулировать данными очень больших размеров. Они могут иметь размеры в мега- и гигабайты и позволяют хранить символьные и битовые данные.
О Коллекции данных. Это специальные типы, которые представляют собой упорядоченную или неупорядоченную совокупность однотипных элементов. Коллекции позволяют строить структуры данных, которые представляются вложенными друг в друга таблицами.
О Пользовательские типы данных. Стандарт SQL предоставляет возможность пользователю определять типы данных произвольной сложности и использовать их при определении типов столбцов таблиц и типов самих таблиц.
О Конструкторы типов. Определяемые типы данных обладают стандартными конструкторами, позволяющими создавать объекты соответствующих типов. Кроме того, такие конструкторы могут создаваться самим пользователем.
О Идентификация объектов. Язык предоставляет возможность специфицировать способ уникальной идентификации всех создаваемых в базе данных объектов. Кроме того, предполагается, что система, поддерживающая SQL, также должна иметь собственный встроенный механизм идентификации объектов.
О Определяемые пользователем методы. Приписываемые к определяемым типам данных методы позволяют специфицировать поведение объектов этих типов. Методы позволяют определять множество операций над объектами данного типа, которые предоставляют возможность раскрывать семантику самого объекта, а также поддерживать взаимодействие между объектами. Совокупность операций объекта образуют его интерфейс.
О Наследование. Механизм наследования позволяет строить новые типы данных с использованием данных и методов других типов. Это дает возможность некоторые общие свойства, характерные для многих типов данных, выражать в некотором общем для них типе данных. Иерархия наследования может быть многоуровневой.
О Инкапсуляция,. Внутренняя структура типов данных может быть скрыта от внешнего мира. Доступ к данным объектов того или иного типа производится только через интерфейсные методы и функции.
О Типизированные таблицы и представления. Столбцы или таблицы в целом могут определяться с указанием пользовательских типов данных. Таблицы и столбцы таблиц обладают методами своих типов. Таблицы, как и их типы, могут образовывать иерархию наследования. Столбцы таблицы могут содержать сложно структурированные данные и даже другие таблицы.
Все это придает SQL черты языка объектно-ориентированных данных. Описанные выше особенности будут кратко проанализированы в последующих разделах.
Большие объекты данных
SQL поддерживает два типа объектов больших размеров (LOB, large object): тип символьных больших объектов (CLOB) и тип двоичных больших объектов (BLOB). Первый из них предназначен для хранения больших символьных объектов, например текстов книг, а второй — для хранения таких больших объектов, как изображения, аудио- и видеоданные. Размеры этих типов могут достигать гигабайтов. Чтобы понять, зачем нужны объекты таких размеров, приведем в табл. 18.1 сведения о реальных размерах символьных и двоичных объектов.
Большие объекты хранятся в базе данных, а не в отдельных файлах операционной системы, что позволяет применять к ним различные операции и непосредственно использовать в SQL. Эти типы присваиваются столбцам таблицы и при
этом их размеры могут указываться в килобайтах (К), мегабайтах (М) и гигабайтах (G), как показано в примере:
CREATE TABLE BOOKTABLE (
Title VARCHAR(200),
Bookid INTEGER,
Summary CL0B(32K),
Book_text CL0B(20M),
Movie BLOB(2G))
Таблица 18.1. Типичные размеры данных различных типов
ОбъектРазмер
Страница текста4-6 К
Небольшое изображение30-40 К
Большое изображение0,2-3 М
Большое цветное изображение20-40 М
с высоким разрешением
Рентгеновский снимок40-60 М
Видеофильм1 Г/час
Видеофильм с высоким разрешением 3 Г/час
Телевидение высокой четкости 200 М/сек
К большим объектам применимы некоторые предикаты, операции и функции, которые имеются для данных строкового типа. К ним, например, относятся:
О предикаты сравнения на равенство и неравенство с возможными квалификаторами ALL и SOME, предикаты LIKE, SIMILAR, EXISTS;
О операции вставки, замены, удаления и поиска значений в таблице;
О операция конкатенации строк;
О функции SUBSTRING, LENGTH, POSITION, NULLIF/COALESCE, TRIM, OVERLAY.
Вот как, например, может выглядеть использование функции POSITION:
SELECT POSITIONS Глава Г IN Book_text) INTO 1nt_variable
FROM BOOKTABLE
WHERE UPPER(Title) - 'ЭНЦИКЛОПЕДИЯ SQL'
Однако имеются ограничения на использование больших объектов. Например, они не могут использоваться в следующих конструкциях SQL:
О предикатах, отличающихся от тех, которые упомянуты выше;
О аргументах агрегатных функций;
О фразах GROUP BY и ORDER BY;
О ограничениях целостности PRIMARY KEY, UNIQUE, FOREIGN KEY;
О списке фразы SELECT, когда там присутствует ключевое слово DISTINCT;
О множественных операциях UNION, INTERSECT, EXCEPT.
^ПРИМЕЧАНИЕ Будьте внимательны при использовании больших объектов в конкретной СУБД, так как она может иметь существенные специфические особенности работы с ними.
Большие объекты могут оказаться неуправляемыми в прикладных программах. Для размещения таких объектов в программе могут потребоваться буферы очень больших размеров. Для достижения управляемого доступа к большим объектам в SQL введено понятие локатора. Локатор — это объект сеанса связи с SQL, который используется для ссылки на большой объект.
ПРИМЕЧАНИЕ В SQL локаторы используются для ссылки не только на большие объекты, но и на массивы, мультимножества и определяемые пользователями типы.
Для работы с большим объектом приложение может объявить переменную-локатор, присвоить ей значение конкретного большого объекта (вернее присваивается ссылка на него) и затем работать с этим значением. Локатор может использоваться в SQL там же, где допустимо использование большого объекта. Локаторам можно присваивать значения выражений над большими объектами. Такие выражения могут содержать столбцы и функции соответствующего типа и даже ссылки на другие локаторы. В приводимом далее примере с локатором ассоциируется первая глава книги:
SELECT SUBSTRING(book_text, POSITION'Глава Г IN Book_text),х
POSITIONC Глава 2' IN Book_text) - POSITIONC'Глава Г IN Book_text))
INTO chapterILocator
FROM. BOOKTABLE
WHERE UPPER(Title) = 'ЭНЦИКЛОПЕДИЯ SQL'
Локатор может быть действительным или недействительным. В момент создания локатора он становится действительным. В таком состоянии он остается до завершения транзакции (по COMMIT или ROLLBACK), в которой он был создан, или до выполнения предложения освобождения локатора (см. далее). По завершении транзакции он становится недействительным. Однако имеется возможность сохранить действительность локатора после нормального завершения транзакции с тем, чтобы можно было далее использовать значение локатора. Для этого применяется предложение HOLD LOCATOR следующего формата:
HOLD LOCATOR список_локаторов
Сохраняемый локатор становится недействительным либо при откате транзакции (ROLLBACK), либо по предложению FREE LOCATOR, которое может располагаться за пределами транзакции, в которой локатор был создан. В приводимом далее примере в теле транзакции мы указываем на необходимость сохранения действительности локатора, затем завершаем транзакцию и уже вне транзакции используем локатор для запоминания его значения в другой таблице.
SELECT Book_text INTO bookLocator
FROM BOOKTABLE WHERE UPPER(Title) = ’ЭНЦИКЛОПЕДИЯ SQL'
HOLD LOCATOR bookLocator
COMMIT
INSERT INTO MY_FAVOURITE_BOOKS
VALUES (.... bookLocator, ...)
Конструируемые типы данных
SQL поддерживает три класса типов данных: предопределенные, конструируемые и пользовательские. Предопределенные типы SQL, или, как их еще называют, встроенные типы данных были рассмотрены в первом уроке. Здесь мы рассмотрим те два класса типов данных, которые используются в объектно-ориентированном SQL.
К конструируемым типам данных в SQL относятся типы строк, ссылок, массивов и мультимножеств. Конструируемые типы специфицируются в SQL с помощью конструкторов типов данных ROW, REF, ARRAY, MULTISET. Типы массивов и мультимножеств в совокупности также называют типами коллекций. Тип ссылок мы рассмотрим в разделе, посвященном пользовательским типам данных. Все остальные конструируемые типы будут кратко проанализированы в следующих разделах.
Тип строк
Тип строк — это последовательность пар (имя_поля тип_данных), которые называются полями. Наиболее естественным использованием типа строк является его применение для представления строк таблицы. В этом случае каждый столбец строки соответствует полю, которое имеет тот же тип и расположение в типе строки, что и соответствующий столбец в таблице.
Тип строки Т2 является подтипом типа строки Т1, если Т1 и Т2 имеют одинаковое количество полей, поля в одинаковых позициях имеют совпадающие имена и для каждой такой пары строк тип поля второй строки является подтипом поля первой строки. Значение одного типа строки может быть присвоено значению другого типа строки, если они имеют равное количество полей и каждая пара полей, расположенных в одинаковых позициях обоих типов, такова, что тип первого поля является присваиваемым типу второго поля. Значения двух типов строк являются сравнимыми, если эти типы имеют равное количество полей и каждая пара полей, расположенных в одинаковых позициях обоих типов, такова, что их типы являются сравнимыми.
Тип строк определяется следующим образом:
ROW(HMB_nonfl тип_данных[, имя_поля тип_данных]...)
Вот как можно было бы определить столбец Location, который содержит составляющие адреса:
Location ROW(Street CHAROO). City CHAR(20), Region CHARC2). Postcode INTEGER).
Конструктор значения типа строки задается ключевым словом ROW, за которым в круглых скобках следует перечень значений полей. Например:
ROW('Теремковская', 'Киев', 'Киевская', 03187)
В качестве значений полей могут выступать имена столбцов таблицы, как это показано в следующем примере:
SELECT Price, R0W(Rooms, Size, Location)
FROM PROPERTIES
Наконец, конструктором строковых значений также является строковый подзапрос, то есть подзапрос, который возвращает одну строку таблицы. Табличный подзапрос, то есть подзапрос, возвращающий множество строк таблицы, считается конструктором, формирующим множество строковых объектов. Например, корректным будет следующий предикат, который может встретиться во фразе WHERE запроса:
ROW('Теремковская1, 'Киев', 'Киевская*, 03187) IN
(SELECT Street, City, Region. Postcode FROM PERSONS WHERE Years > 50)
Типы коллекций
Коллекция — это составное значение, содержащее ноль или более элементов, принадлежащих некоторому типу данных. Если элементы коллекции принадлежат типу данных Т, говорят, что это коллекция Т, например коллекция целых чисел, коллекция адресов и т. д. Количество элементов в коллекции называется ее размером (кардиналъностъю\ В стандарте SQL определено два вида коллекций: массивы (ARRAY) и мультимножества (MULTISET).
Определение коллекции включает указание типа ее элементов и, собственно, вида коллекции. Определение массивов также содержит факультативное указание максимально допустимого размера. Элементами коллекции могут быть значения указанного типа или его подтипов. Тип коллекции Т2 является подтипом типа коллекции Т1 (или Т1 является супертипом Т2), если они одного вида (массивы или мультимножества) и тип элементов Т2 является подтипом типа элементов Т1. Две коллекции сравнимы, если они одного вида и их типы элементов сравнимы. Значение одной коллекции можно присвоить переменной второй коллекции, если они одного вида и тип элементов первой коллекции является присваиваемым типу элементов второй коллекции. Для коллекций определена числовая функция, возвращающая количество элементов в коллекции, которая имеет вид CARDINALITY(коллекция).
Массивы
Массив — это коллекция упорядоченных элементов. Если размер массива равен N, каждый элемент массива имеет порядковый номер в интервале 1-N. Массив может иметь максимально допустимый размер, который ограничивает количество элементов в массиве.
Два массива являются идентичными, если они имеют одинаковый размер и их элементы в одних и тех же позициях идентичны. Один массив является подмассивом второго массива, если элементы первого массива идентичны элементам второго массива начиная с некоторого элемента второго массива.
Тип массива указывается следующим образом: тип_злементов АКНАУ[[максимально_допустимый_размер]1
ПРИМЕЧАНИЕПРИМЕЧАНИЕВ приведенном выше определении синтаксиса типа массива внешние квадратные скобки указывают на факультативность содержащейся в них конструкции, а внутренние квадратные скобки являются элементами синтаксиса этого определения.
ПРИМЕЧАНИЕ
ПРИМЕЧАНИЕ
Приведем пример использования типа массива в определении столбца таблицы.
CREATE TABLE REPORTS (
Num INTEGER,
Authors VARCHAR(15) ARRAY[20],
Title VARCHAR(IOO))
Здесь столбец Authors определен как массив (размером не более 20 элементов) строк переменной длины (ограниченных по размеру 15 символами).
Имеется два способа задания литералов типа массива. Можно указать ключевое слово ARRAY, за которым в квадратных скобках перечисляются его элементы, как это показано в следующем примере:
INSERT INTO REPORTS (Num, Authors. Title)
VALUES (10. ARRAYE’Иванов'. 'Петров'], 'Дедуктивные БД')
Литерал типа массива также можно получить в результате выполнения запроса. Для этого используется выражение следующего вида:
ARRAY(запрос [фраза_упорядочения])
Например, следующий литерал фактически представляет таблицу REPORTS в виде массива:
ARRAY(SELECT * FROM REPORTS ORDER BY Num)
Выбор элемента массива производится с помощью ссылки на элемент массива, которая, например, для столбца Authors имеет вид Authors [nJ, где п — порядковый номер элемента, на который делается ссылка. Приведем пример:
SELECT Num, AuthorsEU AS Name FROM REPORTS
Над массивами с одинаковым типом элементов определена операция конкатенации (||), которая приписывает к элементам первого массива элементы второго массива. Например, если в определении таблицы имеются столбцы:
Authors VARCHAR(15) ARRAY[20]
Editors VARCHAR(15) ARRAY[5]
то выражение Authors 11 Editors дает массив co списком всех авторов и редакторов.
Имеется возможность преобразовать коллекции (массивы и мультимножества) в таблицы. Для этого используется оператор UNNEST, который имеет следующий вид:
UNNESKколлекция) [WITH ORDINALITY]
Например, запрос:
SELECT * FROM UNNEST(ARRAY['а'. *b'])
приводит к созданию таблицы, состоящей из одного столбца и двух строк, содержащих значения ’а' и 'Ь'. Фраза WITH ORDINALITY (применяемая только к массивам) указывает, что в конце списка формируемых столбцов таблицы добавляется еще один, который содержит порядковые номера элементов массива. Например, запрос:
SELECT * FROM UNNEST(ARRAY['а'. *b’]) WITH ORDINALITY
приводит к созданию таблицы, подобной следующей:
?? | ??
а | 1 b | 2
Обратите внимание, что в данном случае формируемая таблица не имеет имен столбцов. В связи с этим допускается указывать синоним таблицы, который содержит не только имя таблицы, но и имена ее столбцов, как это показано в следующем примере:
SELECT *
FROM UNNEST(ARRAY[’a*. 'b']) AS t(fl. f2) WITH ORDINALITY
fl | f2
a I 1
b | 2
Результирующая таблица получает имя t, а ее столбцы — имена fl и f2. Приведем еще один пример использования UNNEST:
SELECT г.Num. a.Name
FROM REPORTS AS г, UNNESH r .Authors) AS a(Name)
Обратите внимание, что здесь во фразе FROM указываются две таблицы, причем вторая получается посредством применения UNNEST к столбцу-массиву первой таблицы. При этом условие соединения этих двух таблиц не задано. В таком виде записывается так называемая операция линеаризации. Чтобы объяснить ее суть, рассмотрим более сложный пример таблицы:
CREATE TABLE REPORTS (
Num INTEGER.
Authors R0W(Name VARCHAR(15). Post VARCHAR(15)) ARRAY[20].
Title VARCHAR(IOO)
Создадим две строки этой таблицы:
INSERT INTO REPORTS (Num. Authors. Title)
VALUES (10. ARRAY[ROW('Иванов *. 'с.н.с.'). ROW('Петров*. 'н.с.')]. 'Дедуктивные БД*)
INSERT INTO REPORTS (Num. Authors, Title)
VALUES (11. ARRAY[ROW('Игнатов *, 'в.н.с.'). ROW('Захарова*. 'н.с.'),
ROW('Сидоров* . 'м.н.с.'], 'Темпоральные БД*)
В результате мы получим следующую таблицу:
Num
Authors
Title
Name
Post
10
Иванов
с.н.с.
Дедуктивные БД
Петров
н.с.
11
Игнатов
в.н.с.
Темпоральные БД
Захарова
н.с
Сидоров
м.н.с.
Теперь после выполнения запроса:
SELECT *-
FROM REPORTS AS г, UNNEST(r.Authors) AS a(Name, Post)
мы получим следующую линеаризованную таблицу:
Num
а
Title
Name
Post
10
Иванов
с.н.с.
Дедуктивные БД
10
Петров
н.с.
Дедуктивные БД
И
Игнатов
в.н.с.
Темпоральные БД
11
Захарова
н.с
Темпоральные БД
и
Сидоров
м.н.с.
Темпоральные БД
Мультимножества
Мультимножество — это неупорядоченная коллекция элементов, имеющих определенный тип. Мультимножество допускает наличие одинаковых элементов. Два мультимножества идентичны, если:
О они имеют одинаковое количество элементов;
О из того, что некоторый элемент принадлежит первому мультимножеству, следует, что он также принадлежит и второму мультимножеству и наоборот, причем в обоих мультимножествах количество элементов, идентичных данному, одинаковое.
Одно мультимножество Ml является подмультимножеством другого мультимножества М2, если любой элемент х, содержащийся в Ml, также содержится в М2, причем количество элементов, идентичных х в Ml меньше или равно количеству элементов, идентичных х в М2.
Тип мультимножества указывается следующим образом:
тип_злемента MULTISET
Пример:
CREATE TABLE TEST (
Cl INTEGER.
С2 INTEGER MULTISET,
СЗ ROWCFl INT, F2 CHAR(IO)) MULTISET)
Конструкторы значений мультимножества
Для создания пустЬго мультимножества используется конструкция MULTISET(). Тип элементов определяется по контексту. Значение мультимножества может конструироваться путем явного перечисления его элементов, как это показано в следующем примере:
MULTISETS. 3, 5, 7)
MULTISET(ROW('Иванов*, 'с.н.с.'), ROW('Петров*, *н.с.*))
Существует конструктор значения мультимножества на основании результата выполнения запроса, который имеет следующий вид:
MULTISET(запрос)
Например:
MULTISET(SELECT Title FROM REPORTS WHERE Num > 5)
В этом случае стандарт SQL требует, чтобы запрос возвращал только один столбец, тип которого является типом элементов созданного мультимножества. Если необходимо, чтобы мультимножество формировалось на основании выполнения запроса, дающего в результате более одного столбца, следует воспользоваться конструктором создания табличного значения мультимножества, имеющего такой вид:
TABLE(запрос)
Приведем пример:
TABLE(SELECT Num, Authors FROM REPORTS WHERE Num > 5)
В этом случае столбцы из списка фразы SELECT объединяются в тип ROW, который дает тип элементов результирующего мультимножества. То есть если запрос возвращает значения п столбцов, выражение TABLE(запрос) равносильно следующему выражению:
MULTISET(SELECT ROWCC1Cn) FROM (запрос) AS Т(С1Сп))
Операции над мультимножествами
Если мультимножество состоит из одного элемента, к нему применима операция ELEMENT(мультимножество), которая возвращает этот единственный элемент. По сути, эта операция равносильна следующему скалярному запросу (напомним, что скалярным называется запрос, возвращающий одно значение):
SELECT М.Е FROM UNNEST(мультимножество) AS М(Е)
Операция SET(мультимножество) возвращает мультимножество, полученное из аргумента путем удаления дубликатов его элементов. Операция UNNEST преобразует коллекцию в таблицу, представляя элементы коллекции в виде строк таблицы. Например, следующий запрос приведет к выдаче числа 17:
SELECT SUM(t.с)
FROM UNNEST(MULTISET(2, 3. 5. 7)) AS t(c)
Над мультимножествами, как и над обычными таблицами, применимы множественные операции объединения, пересечения и разности, которые в данном случае имеют следующий вид:
мультимножество MULTISET {UNION | INTERSECT | EXCEPT} [ALL | DISTINCT] мультимножество
Если модификатор ALL/DISTINCT отсутствует, предполагается ALL. Если один из операндов NULL, то и результат NULL. Приведенное выше определение операций над мультимножествами может быть представлено следующим образом через обычные Операции UNION, INTERSECT и EXCEPT:
MULTISETCSELECT Tl.V FROM UNNEST(мyльтимнoжecтвo_l) AS T1(V)
{UNION | INTERSECT | EXCEPT} [ALL | DISTINCT]
SELECT T2.V FROM UNNEST(мyльтимнoжecтвo_2) AS T2(V))
Агрегатные функции над мультимножествами
В стандарте SQL определен ряд агрегатных функций, которые используют в качестве аргумента мультимножество и/или возвращают мультимножество в качестве своего результата.
Агрегатная функция FUSS I ON использует в качестве аргумента множество мультимножеств и возвращает в качестве своего результата также мультимножество, которое представляет собой объединение всех элементов мультимножеств аргумента. При этом количество дубликатов любого элемента результирующего мультимножества равно сумме дубликатов этого элемента во всех мультимножествах аргумента. Приведем пример:
FUSSION(MULTISET(1. 1, 2). MULTISETCI. 2, 3), MULTISETCI. 2. 3. 4)) = MULTISETCI. 1, 1. 1. 1. 2. 2. 2. 3. 3. 4)
Агрегатная функция INTERSECTION использует в качестве аргумента множество мультимножеств и возвращает в качестве своего результата также мультимножество, которое представляет собой специфическое пересечение элементов мультимножеств аргумента. Суть этого пересечения в следующем: элемент входит в результирующее мультимножество в таком количестве дубликатов, которое равно минимальному количеству этого элемента среди всех мультимножеств аргумента. Приведем пример:
FUSSIONCMULTISETC1, 1. 2, 3). MULTISETCI. 1, 1, 2. 2. 4). MULTISETd, 1. 1. 1, 2. 3. 4)) = MULTISETCI. 1. 2)
Наконец, агрегатная функция COLLECT преобразует в мультимножество множество значений аргумента произвольного типа. Функция COLLECT(X) эквивалентна FU- SION(MULTISETCX))."
Предикаты над мультимножествами
Среди бинарных операторов сравнения над мультимножествами определены только равенство (=) и неравенство (<>). Кроме того, определены также специальные предикаты.
Предикат принадлежности (непринадлежности) элемента мультимножеству имеет следующий вид:
элемент [NOT] MEMBER [OF] мультимножество
где элемент должен соответствовать типу элементов мультимножества. Предикат MEMBER имеет такую семантику:
О если элемент или мультимножество равно NULL, предикат равен UNKNOWN;
О если мультимножество является пустым, предикат равен FALSE;
О если элемент равен одному из элементов мультимножества, предикат равен TRUE;
О если элемент не равен ни одному из элементов мультимножества, предикат равен FALSE.
Предикат NOT MEMBER имеет противоположный смысл и формально выражается через MEMBER следующим образом:
элемент NOT MEMBER [OF] мультимножество = NOT (элемент MEMBER [OF] мультимножество)
Предикат вхождения (невхождения) одного мультимножества в другое имеет такой вид:
мультимножество [NOT] SUBMULTISET [OF] мультимножество
Типы элементов обоих мультимножеств должны быть сравнимыми. Предикат SUB - MULTISET имеет следующую семантику:
О если одно из мультимножеств равно NULL, предикат равен UNKNOWN;
О если первое мультимножество пустое или каждый элемент первого мультимножества входит во второе мультимножество, предикат равен TRUE;
О если первое мультимножество содержит элемент, который не входит во второе мультимножество, предикат равен FALSE.
Предикат NOT SUBMULTISET имеет противоположный смысл и формально выражается через SUBMULTISET таким образом:*
мулыимножество_1 NOT SUBMULTISET [OF] мультимножество_2 =
NOT (мультимножество_1 SUBMULTISET [OF] мультимножество_2)
Предикат наличия дубликатов является унарным. Его синтаксис следующий: мультимножество IS [NOT] A SET
Предикат IS A SET принимает значение TRUE, если мультимножество не содержит дубликатов элементов, и FALSE — в противном случае. Он эквивалентен такому предикату:
CARDINALITY(мyльтимнoжecтвo) = САР0^АЕ1ТУ(5ЕТ(мультимножество))
Предикат IS NOT A SET имеет противоположный смысл и выражается через IS A SET следующим образом:
мультимножество IS NOT A SET = NOT (мультимножество IS A SET)
Пользовательские типы данных
Механизм определения типов данных пользователем позволяет существенно расширить возможность по структурированию данных предметной области. Стандарт SQL выделяет два вида определяемых пользователем типов (далее ОПТ): О индивидуальный тип;
О структурный тип.
Индивидуальные типы
Индивидуальным является такой тип, который определяется через единственный предопределенный тип, называемый в данном случае исходным типом. Примером могут служить следующие определения индивидуальных типов:
CREATE TYPE MONEY AS DECIMALS. 2)
CREATE TYPE BITMAP AS BLOB
CREATE TYPE TEXT AS CLOB(20K)
В связи с этим определением может возникнуть вопрос, зачем определять новый тип, если он внешне идентичен одному из предопределенных типов? Дело в том, что для предопределенных типов невозможно выдержать принцип строгой типизации. В связи с этим логически несовместимым столбцам можно присваивать значения друг друга. Объясним это на примере. Пусть определена следующая таблица с использованием предопределенных типов:
CREATE TABLE ROOMTABLE (
RoomID CHAR(IO),
RoomLength INTEGER.
RoomWIdth INTEGER.
RoomArea INTEGER,
RoomPerimeter INTEGER)
При таком определении мы можем присвоить площади значение длины комнаты:
UPDATE ROOMTABLE SET RoomArea - RoomLength
Теперь, если мы определим такие типы:
CREATE TYPE ROOMTYPE AS CHAR(IO)
CREATE TYPE METERS AS INTEGER
CREATE TYPE SQUAREMETERS AS INTEGER
и создадим таблицу с их использованием:
CREATE TABLE ROOMTABLE (
RoomID ROOMTYPE.
RoomLength METERS.
RoomWIdth METERS.
RoomPerimeter METERS.
RoomArea SQUAREMETERS)
то, учитывая принцип строгой типизации, поддерживаемый в объектно-ориентированном SQL, мы уже не сможем записать приведенное выше присваивание площади комнаты значения ее длины. Однако можно свободно оперировать со столбцами одного типа данных:
UPDATE ROOMTABLE SET RoomLength = RoomWIdth
Индивидуальные типы обладают многими свойствами ОПТ, которые мы рассмотрим далее, за исключением наследования, то есть построения иерархии типов.
Структурные типы
Наиболее фундаментальным средством SQL, поддерживающим объектную ориентацию, являются структурные пользовательские типы. Структурные типы имеют ряд характеристик, наиболее важными из которых являются следующие:
О они могут определяться с одним или более атрибутами, каждый из которых может иметь любой допустимый в SQL тип, включая и другие структурные типы.
О все аспекты их поведения характеризуются методами;
О их атрибуты инкапсулированы и доступны только лишь через автоматически создаваемые методы наблюдения (observer) и изменения (mutator);
О сравнение их значений выполняется только через определяемые пользователями функции;,
О они могут участвовать в иерархии типов.
Далее мы рассмотрим эти свойства структурных типов.
Определение структурных типов
Структурные типы позволяют представлять типы, которые включают в свое определение перечень членов этого типа. Член типа - это обычное определение атрибутов в виде их имен с типами, например:
CREATE TYPE ADDRESS AS (
Street CHAR(30).
City CHARC20), State CHAR(2).
Zip INTEGER)
Здесь Street, City, State и Zip являются членами (атрибутами) определяемого типа ADDRESS. Членами структурного типа могут быть предопределенные типы, как это показано выше, а также другие ОПТ, как это показано на следующем примере описания типа недвижимости.
CREATE TYPE REAL_ESTATE AS (
PriceMONEY,
RoomsINTEGER,
SizeDECIMALS,2),
Location ADDRESS,
Text-description TEXT,
Front_view_image BITMAP)
Здесь использованы четыре ОПТ (MONEY, BITMAP, TEXT, ADDRESS), из которых первые три являются индивидуальными, а последний — структурным. Структурные типы могут использоваться везде, где и предопределенные типы данных, а именно в качестве:
О атрибутов других структурных типов;
О параметров функций, методов и процедур;
О переменных SQL;
О доменов и столбцов таблицы.
Более того, структурные типы могут использоваться для определения таблиц и представлений. Вот как выглядит определение таблицы с использованием структурного типа nearest ate:
CREATE TABLE PROPERTIES OF REAL_ESTATE
Такие таблицы называются типизированными. Типизированными могут быть только базовые таблицы. Они содержат один столбец для каждого атрибута определяющего структурного типа. Строки таблицы являются экземплярами типа. Функции, методы и процедуры, определенные для оперирования экземплярами типа, применимы к строкам такой таблицы.
Методы
Метод — это вызываемая из SQL функция, которая прикреплена к ОПТ. Функции-методы отличаются от обычных функций следующим:
О методы тесно привязаны к одному пользовательскому типу данных;
О они имеют неявно задаваемый параметр SELF (называемый предметным параметром), который ссылается на экземпляр типа;
О процесс создания метода состоит из двух шагов: определение сигнатуры и тела, специфицируемых отдельно;
О методы должны храниться в той же схеме, где и определение структурного типа, с которым они связаны;
О методы имеют другой стиль обращения к ним — 0ПТ_значение.метод().
При определении типа задается только спецификация метода, а он сам определяется отдельным предложением. Приведем пример определения типа с методом:
CREATE TYPE EMPLOEE AS (
Name CHAR(40).
Base_salary DECIMAL(9, 2),
Bonus DECIMALS, 2)) INSTANTIABLE NOT FINAL
METHOD SalaryO RETURNS DECIMALS, 2)
CREATE METHOD SalaryO FOR EMPLOEE
BEGIN
END:
Имеется два вида методов. Оригинальные методы приписываются собственно типу. Подменяемые методы заменяют методы, которые были приписаны супертипам в иерархии типов. Сигнатура подменяемого метода должна соответствовать сигнатуре оригинального метода, за исключением предметного параметра. Приведем пример:
CREATE TYPE EMPLOEE AS (’
Name CHAR(40),
Base_salary DECIMALS. 2),
Bonus DECIMALS, 2)) INSTANTIABLE NOT FINAL
METHOD SalaryO RETURNS DECIMAL(9, 2)
CREATE TYPE MANAGER UNDER EMPLOEE AS (
Stockoption INTEGER) INSTANTIABLE NOT FINAL
OVERRIDING METHOD Sal агу О RETURNS DECIMALO. 2), -- подменяемый
METHOD Vested 0 RETURNS INTEGER-- оригинальный
Методы вызываются с использованием точечного синтаксиса. Например, если таблица DEP имеет столбец Mgr, определенный на типе MANAGER, представленном выше, то можно записать:
SELECT Mgr.Sal агуО FROM DEP
Если метод не имеет параметров, круглые скобки можно опускать:
SELECT Mgr.Sal ary FROM DEP
Инкапсуляция атрибутов типа
Доступ и изменение значений атрибутов типа производится только через автоматически создаваемые методы наблюдения (observer) и изменения (mutator). Тем самым достигается инкапсуляция значений атрибутов. Так, например, обращение к атрибутам Location таблицы PROPERTIES выглядит следующим образом:
Location.StreetO, Location.CityO, Location.StateO. ...
Приведем пример запроса с использованием методов доступа к атрибутам.
SELECT Location.StreetO, Location. City О. Location.StateO
FROM PROPERTIES
WHERE Price < 100000
Точечная нотация может быть многоуровневой, что позволяет производить навигационный доступ в многоуровневой структуре типа. В следующем примере демонстрируется определение переменной типа REAL ESTATE и возможные варианты ее использования:
DECLARE г real_estate
SET г.Size = 2540.50-- равносильно r.Size(2540.50)
SET ... = г. Location. State -- равносильно = r.LocationO .StateO
SET r.Location.City = 'Киев* -- равносильно г.Location.C1ty('Киев')
Подтипы и наследование типов
На структурных типах можно определять иерархию типов (супертип/подтип), которая использует наследование. Подтип наследует структуру (атрибуты) супертипа и его поведение (методы). В стандарте SQL допускается единственное наследование, то есть подтип может наследовать атрибуты и методы только одного супертипа.
В связи с иерархией наследования для типа определено свойство, разрешается ли ему иметь подтипы или нет. Это достигается с помощью ключевых слов NOT FINAL/FINAL, которые располагаются вслед за описанием членов типа. Наследование подтипом супертипа указывается с помощью фразы UNDER, как это показано в следующем примере:
CREATE TYPE ADDRESS AS
(Street CHAR(30), City CHAR(20), State CHAR(2). Zip INTEGER) NOT FINAL
CREATE TYPE GERMAN_ADDR UNDER ADDRESS AS
(Family name VARCHAR(30)) NOT FINAL
CREATE TYPE BRASILIAN_ADDR UNDER ADDRESS AS (Neighborhood VARCHAROO)) NOT FINAL
CREATE TYPE US_ADDR UNDER ADDRESS AS
(Area_code INTEGER. Phone INTEGER) NOT FINAL
CREATE TYPE US_BUS_ADDR UNDER ADDRESS AS
(Bus_area_code INTEGER. Bus_phone INTEGER) NOT FINAL
Приведенное выше определение типов означает наследование, показанное на рис 18.1.
Рис. 18.1. Структура наследования
Создание экземпляра структурного типа
Относительно структурного типа можно указать, допускает ли он создание экземпляров или нет. Для этого используются ключевые слова INSTANTIABLE и NOT INSTANTIABLE. Невозможность создания экземпляров эквивалентна абстрактному классу в объектно-ориентированных языках программирования. Для таких классов не создаются конструкторы (см. далее). Типы, не имеющие экземпляров, используются только для определения их подтипов, которые уже могут иметь экземпляры. По умолчанию структурные типы допускают создание экземпляров, а индивидуальные типы всегда имеют экземпляры. Приведем пример.
CREATE TYPE person AS (
Name VARCHARC30),
Address ADDRESS.
Sex CHAR(D) NOT INSTANTIABLE NOT FINAL
Если тип допускает создание экземпляров, для этого существует два способа. Во-первых, с каждым типом автоматически ассоциируется функция-конструктор, имеющая имя типа данных. При этом атрибуты инициализируются значениями по умолчанию. Атрибуты изменяются (производится их дальнейшая инициализация) с помощью метода изменения. Покажем это на примере.
DECLARE re REAL_ESTATE -- объявляем переменную типа REAL_ESTATE
SET re = real_estate() -- создаем новый экземпляр
SET re.Rooms =12-- инициализируем атрибут Rooms
SET re.Size = 2500-- инициализируем атрибут Size
To же самое можно записать следующим образом:
DECLARE re real_estate
SET re = real estateO .Rooms (12) .Si ze( 2500)
Во-вторых, можно определить множество методов инициализации и обращаться к ним с помощью оператора NEW, который создает экземпляр объекта соответствующего типа, как это показано в следующем примере.
CREATE TYPE REAL_ESTATE AS (...)
METHOD Real_estate(r INTEGER, s DECIMALS, 2)) RETURNS real_estate
CREATE METHOD REAL_ESTATE(r INTEGER, s DECIMAK8, 2)) RETURNS real_estate
BEGIN
SET self.Rooms = r
SET self.Size = s
RETURN re
END
BEGIN
DECLARE re real_estate
SET re = NEW real_estate(12, 2500) -- как и выше
END
Манипулирование экземплярами структурных типов
Манипулирование экземплярами структурных типов производится посредством вызова определенных для них методов и функций. Обращение к ним можно производить в тех местах, где SQL допускает использовать скалярные значения. Приведем несколько примеров использования структурных типов:
INSERT INTO PROPERTIES
VALUES (US_DOLLAR(300000). 15. 4650.
NEW ADDRESS(*2225 Coral Drive', 'San Jose', 'CA', 95125), ...):
UPDATE PROPERTIES
SET Price = US_D0LLAR(0.9 * amount(Price))
WHERE Location.StateO = 'CA*;
SELECT D_mark(Price), Location.CityO
FROM PROPERTIES
WHERE Location.ZipO = 95453
Ссылочные типы и типизированные таблицы
Любой структурный тип имеет так называемый ссылочный тип. Ссылочный тип - это тип, значения которого позволяют ссылаться на экземпляры этого структурного типа. Структурный тип может иметь один из трех вариантов ссылочного типа, которые определяют способ формирования значений ссылочного типа.
О Пользовательский ссылочный тип. В этом случае тип значений ссылочного типа указывается явно при определении структурного типа. В качестве такого типа можно использовать только предопределенные типы SQL. Синтаксис определения этого варианта ссылочного типа следующий:
REF USING предварительно_определенный_тип
О Определяемый системой ссылочный тип. Тип значений ссылочного типа определяется системой, поддерживающей SQL. Синтаксис определения этого варианта ссылочного типа такой:
REF IS SYSTEM GENERATED
О Выводимый из атрибутов ссылочный тип. Тип значений ссылочного типа выводится на основании значений указанных атрибутов структурного типа. Синтаксис определения этого варианта ссылочного типа следующий:
REF (список_атрибутов_структурного_типа)
По умолчанию предполагается определяемый системой ссылочный тип. Вариант ссылочного типа указывается после определения атрибутов структурного типа, как это демонстрируется в следующих примерах:
CREATE TYPE student AS (...)
NOT FINAL REF USING INTEGER
CREATE TYPE person AS (ssn.INTEGER, name CHAR(30), ...)
NOT FINAL REF(ssn)
CREATE TYPE employee AS (...)
REF IS SYSTEM GENERATED
Структурный тип с помощью одного из своих атрибутов может ссылаться на другой структурный тип. Для этого соответствующий атрибут должен иметь тип REF с указанием имени структурного типа, на который производится ссылка. Приведем пример:"
CREATE TYPE REAL_ESTATE AS (owner REF(person), ...)
NOT FINAL REF USING INTEGER
Здесь структурный тип REAL_ESTATE посредством атрибута owner ссылается на другой структурный тип person..
При определении типизированной таблицы можно указать свойства ее столбцов, которые, в частности, включают указание области видимости ссылки, а также определить так называемый сомоссътаюгцийся столбец. Приведем пример такого определения:
CREATE TABLE people OF person (...)
CREATE TABLE PROPERTIES OF real„estate
(owner WITH OPTIONS SCOPE people, REF IS old USER GENERATED)
Здесь мы указали, что в таблице PROPERTIES столбец owner, являющийся ссылкой, будет ссылаться на строки таблицы person. Тем самым мы указали область видимости этой ссылки. Кроме того, мы добавили к таблице еще один столбец, old, который будет содержать значения ссылок на строки данной таблицы.
Типизированные таблицы могут формировать иерархию таблиц согласно иерархии их типов данных. Подтаблицы в этой иерархии наследуют столбцы, ограничения целостности, триггеры и другие свойства супертаблиц. В следующем примере определяются две типизированные таблицы, являющиеся подтаблицами таблицы PROPERTIES:
CREATE TABLE CONDOS OF CONDO UNDER PROPERTIES
CREATE TABLE HOUSES OF HOUSE UNDER PROPERTIES
Запросы, сформулированные относительно таблицы, предполагают поиск и по всем ее подтаблицам. Например, следующий запрос приведет к выбору строк из таблиц PROPERTIES, CONDOS и HOUSES:
SELECT Price. Locat1on.C1tv. Location.State FROM PROPERTIES
Однако в случае иерархии таблиц имеется возможность ограничить поиск только в пределах указанной таблицы. Для этого можно использовать две возможности.
Во-первых, можно воспользоваться предикатом проверки принадлежности (или непринадлежности) указанному типу IS [NOT] OF, который имеет такой синтаксис: значение IS [NOT] OF (список_пользовательских_типов)
Тогда следующий запрос приведет к выборке только тех строк таблицы PROPERTIES, которые относятся к типу HOUSE (здесь мы воспользовались оператором разрешения ссылок DEREF, позволяющим получить значение, на которое делается ссылка в его аргументе):
SELECT Price, Location.City, Location.State
FROM PROPERTIES
WHERE DEREF(oid) IS OF (house)
Во-вторых, можно воспользоваться модификатором ONLY при имени таблицы, который указывает на необходимость выбора только тех строк, типы которых соответствуют типу указанной типизированной таблицы. Например, в следующем запросе указывается, что выбирать следует только те строки таблицы PROPERTIES, которые имеют тип именно этой таблицы:
SELECT Price, Location.City, Location.State
FROM ONLY(PROPERTIES)
Ссылки с областью видимости могут применяться для перехода по ним с целью получения значений атрибутов из таблиц, на которые производятся ссылки. Для этого используется оператор перехода по ссылке ->, который вместе с его аргументами образует выражение пути. В следующем примере выводится значение столбца Price из таблицы PROPERTIES, а также значение столбца Name из таблицы PEOPLE с заданием условия на таблицу PEOPLE. Доступ до значений необходимых атрибутов таблицы people из таблицы PROPERTIES производится по ссылке, которая представляется атрибутом owner:
SELECT р.Price, p.Owner->Name FROM PROPERTIES p
WHERE p.Owner->Address.City = 'Киев*
Ссылки также могут использоваться для вызова методов соответствующего структурного типа:
SELECT р.Price, р.Owner->Income(1998)
FROM PROPERTIES p’
Здесь предполагается, что тип person типизированной таблицы реор! е, на которую производится ссылка из типизированной таблицы PROPERTIES, имеет метод income.
Как мы уже отметили, оператор DEREF позволяет получить значение структурного типа, на которое имеется ссылка. В следующем примере выводится цена недвижимого имущества, а также вся информация о владельцах:
SELECT р.Price, DEREF(р.Owner)
FROM PROPERTIES p
Сравнение значений
Предложение CREATE ORDERING специфицирует, какие именно операторы сравнения допустимы для определяемого пользователем типа, а также каким образом
производится такое сравнение. Это предложение определяет так называемые форму, категорию и функцию упорядочения.
Имеется две формы упорядочения: EQUALS ONLY и ORDER FULL. Первая из них предполагает, что значения типа могут сравниваться только на равенство и неравенство (=, <>), а вторая допускает использовать все операторы сравнения.
Также имеется три категории упорядочения, которые определяют характер используемой при сравнении функции. Категория STATE подразумевает, что неявно создается функция с двумя параметрами, имеющими значения типа ОПТ, которая возвращает логическое значение. Эта функция производит попарное сравнение атрибутов значений, указанных в качестве параметров. Категория RELATIVE предполагает явную спецификацию функции упорядочения с двумя параметрами, имеющими значения типа ОПТ, которая возвращает значение 0 типа INTEGER при равенстве, положительное целое число при выполнении соотношения > и отрицательное целое число при выполнении соотношения <. Категория МАР предполагает явную спецификацию пользователем функции упорядочения с одним параметром, имеющим значение типа ОПТ. Эта функция возвращает значение предопределенного типа, которое используется для сравнения с другим ОПТ.
Приведем примеры использования предложения CREATE ORDERING:
CREATE ORDERING FOR employee
EQUALS ONLY BY STATE
CREATE ORDERING FOR complex
ORDER FULL BY RELATIVE
WITH FUNCTION complex_order(complex, complex)
Правила использования форм и категорий упорядочения таковы:
О для индивидуальных типов нельзя указывать категорию STATE;
О категории STATE и RELATIVE должны специфицироваться для максимально необходимого супертипа в иерархии типов;
О категория МАР может специфицироваться для более чем одного типа в иерархии типов, однако все такие типы должны иметь одну и ту же форму упорядочения;
О категория STATE допустима только для формы упорядочения EQUALS ONLY;
О если специфицирована форма упорядочения ORDER FULL, допускаются только категории RELATIVE или МАР.
Если для типа не определен механизм сравнения его значений, используется механизм сравнения значений самого ближайшего к нему супертипа, для которого он (механизм сравнения) определен. Значения двух различных типов являются сравнимыми, если эти типы имеют общий супертип, а также их категории сравнения совпадают (то есть STATE, RELATIVE или МАР). По умолчанию для индивидуальных типов применимы все операции сравнения, которые базируются на сравнении значений их исходных типов. В свою очередь, для структурных типов по умолчанию отсутствуют какие-либо операторы сравнения.
Определяемое пользователем приведение типов
Стандарт SQL предоставляет возможность описать правила преобразования значений одного типа в значения другого типа. Это производится с помощью предложения CREATE CAST, имеющего следующий синтаксис:
CREATE СА5Т(исходный_тип AS результирующий_тип)
WITH функция_приведения_типов [AS ASSIGNMENT]
В определяемом пользователем приведении типов хотя бы один из типов должен быть определяемым пользователем типом или типом ссылки. После описания правила приведения типов можно использовать функцию CAST для выполнения необходимого преобразования типа:
CASTCисходное_значение AS резулыирующий_тип)
Приведем пример:
CREATE CASTCtl AS t2) WITH FUNCTION tltot2(tl)
SELECT CASTCcl AS t2) FROM TABI
Здесь с помощью предложения CREATE CAST указывается, что для приведения типа tl в тип t2 следует использовать функцию tltot2. После этого в предложении SELECT производится явное преобразование значения cl типа tl в необходимое значение типа t2.
Факультативная фраза AS ASSIGNMENT указывает, что указанное правило приведения типов будет неявно использоваться при выполнении оператора присваивания. Таким образом, если мы запишем:
CREATE CASTCtl AS t2) WITH FUNCTION tltot2(tl) AS ASSIGNMENT '
то становится действительным следующее присвоение:
DECLARE vl tl, v2 t2
SET V2 = VI
Самостоятельная работа
Напишите определение таблицы, в которой использовались бы типы данных CLOB и BLOB.
Напишите определение столбца таблицы, который имеет тип ROW со следующими полями: Author CHARC20), Title CHARC4O), Year INTEGER. Напишите произвольный литерал этого столбца.
Напишите определение столбца, который представляет собой массив значений того же типа ROW, что определен в предыдущем задании.
Пусть таблица PERSON содержит столбец Article, имеющий тип ARRAY. Напишите запрос, согласно которому выводится третий по порядку элемент массива.
Приведите определение столбца, который имеет тип мультимножества элементов типа ROWCName CHAR(IO), Address CHARC4O)). Напишите литерал этого типа. Напишите выражение, которое преобразует ваш литерал в мультимножество без повторяющихся элементов.
Определите индивидуальный тип Myjmage, который соответствует типу BLOB(2M), а также тип My_text с типом СЮВ(200К).
Создайте структурный тип данных MY WORK, в котором помимо других атрибутов присутствуют и определенные на созданных согласно предыдущему заданию индивидуальных типах, а также атрибут, который вы создали во втором задании. Создайте таблицу на типе данных MY_WORK.
Создайте на основе супертипа MY_WORK подтип, который имеет дополнительные атрибуты.
Для типа MY_WORK укажите, что он имеет определяемый системой ссылочный тип, а также дополните тип MY_WORK атрибутом, который ссылается на тип MY_JOB.
Подведение итогов
Усвоив материал этого урока, вы научились:
0 работать с большими объектами данных;
Q создавать и использовать объекты типа строк;
0 создавать и использовать объекты типа массивов;
0 создавать и использовать объекты типа мультимножеств;
0 определять и использовать индивидуальные типы данных;
0 определять и использовать структурные типы данных.
УРОК SQL/ХМLУРОК SQL/ХМL
УРОК SQL/ХМL
УРОК SQL/ХМL
XML — одна из самых важных технологий представления и обмена структурированными данными в Интернете. С возникновением этого языка как носителя данных встал вопрос об организации интегрированного хранения и обработки документов XML, то есть вопрос о создании баз данных, поддерживающих структуры данных XML. Одним из путей решения данного вопроса является интегрирование данных XML в реляционные СУБД. В настоящее время многие промышленные СУБД поддерживают структуры данных XML. Кроме того, стандарт SQL предлагает вариант расширения языка, который позволяет представлять данные из реляционных таблиц в виде документов XML.
XML и базы данных
В этом разделе мы рассмотрим некоторые вопросы интеграции XML с базами данных, а именно: черты баз данных в XML, особенности документов XML, которые влияют на способ их представления в базах данных, способы реализации баз данных XML.
Сходство и отличие
Технология XML обладает многими чертами, которые характерны для баз данных. Во-первых документы XML содержат данные, структурированные подобно иерархическим базам данных, появившимся в начале развития баз данных. Во-вторых, эта технология предлагает множество функций, присущих базам данных, а именно описание структуры данных (например, языки DTD и XML Schema), хранение данных (в виде документов XML), языки запросов (XQL, XML-QL, QUILT и другие), интерфейсы для языков программирования (SAX, DOM) и т. д. И наконец, самое главное, что объединяет эти технологии, — стремление сделать данные независимыми от программ, которые их используют. Однако многие функции, присущие классическим базам данных, все же отсутствуют. Это прежде всего касается интегрированного хранения данных, централизованного управления ими и совместного использования. Результатом этих принципиальных различий
является отсутствие в технологии XML таких важных функций СУБД, как оптимизация и эффективное хранение, индексация и методы доступа, обеспечение безопасности и защиты данных, обработка транзакций и поддержка целостности данных, многопользовательский доступ, поддержка триггеров, запросов ко многим документам и т. д.
Таким образом, хотя и допустимо использовать XML в качестве базы данных в тех средах, где нет больших объемов информации, большого количества пользователей и которые не требуют высокой производительности, он совершенно не подходит для многих реальных задач, предполагающих поддержку большого числа пользователей, жесткие требования к целостности данных и производительности.
Два вида документов XML
Документы XML подразделяются на два основных типа: документы, ориентированные на представление данных, и документы, ориентированные на представление документов. Для работы с документами этих типов, соответственно, предназначены средства обработки данных и средства обработки документов.
Документы, ориентированные на данные, характеризуются четко упорядоченной формализованной структурой, частым повторением одних и тех же структур данных. Кроме того, смешанного информационного наполнения в них нет либо оно присутствует в минимальном объеме. Порядок, в котором появляются однородные элементы, часто не имеет значения. Хорошим примером в данном случае являются документы XML, содержащие заказы на продажу товаров, графики полетов, меню ресторанов, протоколы научных исследований и т. д. Документы, ориентированные на данные, обычно создаются для машинной обработки. Возможности XML используются здесь в минимальной степени — он является лишь средством для транспортировки данных. Документ, ориентированный на данные, может выглядеть, например, следующим образом:
<SalesOrder S0Number="12345">
Customer CustNumber="543">
Си51Мате>Компания ABB</CustName>
<51гее>Главная, 1</Street>
City>KMeB</City>
CostCode>03187</PostCode>
</Customer>
<OrderDate>14-08-2005</OrderDate>
<Item ItemNumber="l">
Cart PartNumber="123">
<Мате>гаечный ключ</Мате>
Cr1ce>9.95</Pr1ce>
</Part>
<Quantity>10</Quantity>
</Item>
<Item ItemNumber="2">
Cart PartNumber="456">
<Name>cenapaiop</Name>
Cri ce>13.27</Pr1 ce>
</Part>
<Quant1ty>5</Quantity>
</Item>
</SalesOrder>
Следует обратить внимание, что многие документы XML, содержащие большой объем текстовой информации, ориентированы на данные. Так, например, страница на Amazon.com, где приводится информация о книге, содержит в основном текст, при этом имеет весьма жесткую структуру. Большая часть текста повторяется во всех аналогичных страницах, объем текста, приходящегося на каждую страницу, строго ограничен.
Документы, ориентированные на документы, не имеют жесткой структуры, не отличаются глубиной проработки, кроме того, они характеризуются большим объемом смешанного информационного наполнения. Порядок, в котором возникают однородные элементы, почти всегда важен. Вот примеры подобного документа:
<FlightInfo>
Авиакомпания <А1г11пе>Авиалинии Киева</А1rl1пе> осуществляет
в неделю <Count>Tpn</Count> беспосадочных полета из
<Ог1д1п>Киева</Ог1д1п> в <Destination>Hbro-№pK</Destinat1on>.
Время отравления в <0ау>понеделькик</0ау> в
<Departure>09:15</Depdrture>, в <Оау>среду</Оау> в
<Departure>ll:15</Departure> и в <0ау>пятницу</0ау> в
<Departure>13:15</Departure>. Время прибытия - через 9 часов после отправления.
</FlightInfo>’
<Product>
<Intro>
<ProductName>rae4HbM ключ</ProductName> фирмы
<0еуе1орег>Киевский завод металлоизделий</0еуе1орег> подобен
<5иттагу>разводному гаечному ключу, но меньшего размера.</Summary>
</Intro>
<Description>
<Рага>Гаечный ключ производится в <1>двух ориентациях</1>, изготовлен из <Ь>высококачественной нержавеющей стали</Ь>. Ручка имеет резиновый наконечник для удобства работы.<Рага> <Рага>Вы можете:</Рага>
<L1st>
<Item><L1nk URL="Order.html">3аказать гаечный ключ</11пк>
</Item>
<Item><Link URL-'Wenches.Ь1пГ>Получить дополнительную информацию</11пк>
</Item>
<Item><L1nk URL="Catalog.zlp">3arpy3MTb каталог</Ипк>
</Item>
</L1st>
<Рага>Ключ будет стоить вам <Ь>всего 19,99 долларов</Ь> и если вы закажете его прямо сейчас, то получите <Ь>молоток </Ь> в подарок.</Рага>
</Descript1on>
</Product>
На практике далеко не всегда возможно провести четкую границу между разными типами документов. Документы, по сути являющиеся ориентированными на данные, такие как счет-фактура, могут содержать неструктурированные данные с небольшой глубиной проработки, например описание товаров. Напротив, документы, которые ориентированы на документы, например руководство пользователя,
могут содержать данные с четкой структурой, например название руководства, сведения об организации, в которой написано руководство, данные об авторах, ключевые слова, УДК, дата и т. д. И все же, охарактеризовав документы как ориентированные на данные или на документы, легче понять, с чем придется работать - с данными или документами, а следовательно, существенно упростить решение вопроса о том, как документы XML должны быть представлены в базе данных.
Разновидности баз данных XML
Существует много подходов к реализации баз данных XML. Мы опишем в общих чертах три из них: на основе двумерных файлов, собственные базы данных и реляционные базы данных XML.
Базы данных XML на основе двумерных файлов
Базы данных XML (БД XML) на основе двумерных файлов представляют собой иерархический доступ к данным, предусматривающий прохождение сначала по структуре каталогов файловой системы, а затем по структуре элементов документа XML. Двумерный файл предоставляет наиболее простой механизм хранения документов XML.
Преимущества БД XML на основе двумерных файлов заключаются в том, что она является небольшой, удобной в создании и сопровождении, а также обеспечивает доступ с помощью других инструментальных средств. Недостатки такого подхода заключаются в том, что в этом случае совсем не поддерживаются или поддерживаются на недостаточном уровне основные функции баз данных. Двумерными файлами следует пользоваться в том случае, когда вы имеете дело с простыми, слабо структурированными документами и функции СУБД не являются существенными для хранения и манипулирования документами.
При разработке БД XML на основе двумерных файлов следует четко определить, какие компоненты документов будут представлены в виде структуры каталогов операционной системы, а какие — в виде структуры документа XML. Одной из крайностей является вариант, когда вся информация представлена в структуре каталогов, а файлы содержат только отдельные простейшие фрагменты документов XML. В данном случае говорят о БД XML на основе двумерных файлов с высокой степенью детализации, поскольку данные в ней весьма детализированы и представлены в виде многочисленных мелких фрагментов (рис. 19.1).
Другой крайностью является создание единственного документа XML, содержащего всю базу данных. Это так называемая БД XML на основе двумерных файлов с низкой степенью детализации, поскольку данные в ней практически не структурированы и представлены в одном крупном фрагменте, то есть в одном файле. К таким данным можно легко обращаться с помощью всевозможных текстовых редакторов, различных инструментальных средств XML, а также с помощью любого языка программирования. Однако наиболее взвешенный подход заключается в выборе промежуточного варианта, который называется вариантом со средней степенью детализации (рис. 19.2).
Рис. 19.1. База данных на основе двумерных файлов с высокой степенью детализацииРис. 19.1. База данных на основе двумерных файлов с высокой степенью детализации» 8й t» 8й t
Рис. 19.1. База данных на основе двумерных файлов с высокой степенью детализации
Рис. 19.1. База данных на основе двумерных файлов с высокой степенью детализации
» 8й t
» 8й t
Й subject2.xmlЙ subject2.xmlПапки
Й subject2.xml
Й subject2.xml
63 ^5 lecturedb
^ lectures
S3 subjects
^3 teachers
Рис. 19.2. База данных на основе двумерных файлов со средней степенью детализации
Если БД XML разбивается на фрагменты с целью ее детализации, очень важным является вопрос нахождения так называемых точек разбиения. Точки разбиения могут использоваться для фрагментации документов не только для файловых систем, но и при хранении документов в реляционных базах данных.
Собственные базы данных XML
Собственные базы данных XML (native XML databases) — это такие базы данных, которые разрабатываются специально для хранения и манипулирования документами XML. Для таких баз данных существует понятие модели документа XML (логической), на основе которой осуществляется определение, хранение, манипулирование и поиск документов. Внешний интерфейс таких баз данных ориентирован именно на документы XML. Как и другие базы данных (системы управления базами данных), собственные БД XML поддерживают все характерные для баз данных функции: защиту, целостность, резервное копирование и восстановление, языки запросов, транзакции, триггеры, многопользовательский доступ и т. д. Собственные БД XML наиболее полезны для хранения и обработки документов XML, ориентированных на представление документов. Именно собственные БД XML поддерживают все характерные для документов XML особенности, такие как упорядоченность внутри документа, комментарии, разделы CDATA и т. д., которые, как правило, не поддерживают СУБД с другими моделями данных, но
расширенные для поддержки XML. Собственные БД XML поддерживают языки запросов XML, позволяя задавать, например, такие запросы: «Вывести документы, в которых третий абзац каждой главы содержит текст, выделенный жирным шрифтом». Очевидно, что запросы подобного рода невозможно формулировать в SQL. Существуют две широкие категории собственных БД XML: ориентированные на текст (текстовые БД XML) и ориентированные на модель (модельные БД XML). Текстовые БД XML хранят документы XML в виде текстов. Характерным для всех ориентированных на текст собственных БД XML является наличие индексов, которые позволяют механизму поиска легко и быстро переходить в любую точку документа XML, что существенно увеличивает скорость поиска документов или их фрагментов. Текстовые БД XML подобны иерархическим БД в том смысле, что обе существенно превосходят реляционную БД с точки зрения производительности в том случае, когда логика поиска и выдачи данных соответствует предопределенной иерархической структуре. Если же логика поискового выражения и форма выдачи данных не соответствуют иерархической структуре документа (например, когда следует вывести документ в инвертированном виде), то текстовые БД XML, как и иерархические БД, значительно проигрывают реляционным БД.
Второй категорией собственных БД XML являются те, которые ориентированны на модельное представление документов XML. В этом случае документ XML представляется во внутренней объектной модели и именно в таком виде он запоминается. Каким именно образом хранится выбранная модель документов XML, зависит от специфики реализации БД XML. Некоторые из БД XML запоминают документы выбранной модели в реляционных или объектно-ориентированных БД. Например, хранение DOM в реляционной БД может привести к построению таких таблиц, как Elements, Attributes, PCDATA, Entities и EntityReferences. Другие ориентированные на модель собственные БД XML используют свои физические структуры, специально разработанные для оптимального хранения и манипулирования выбранной моделью документа XML.
Базы данных XML на основе других баз данных
Реализация БД XML на основе существующих традиционных баз данных, например реляционных, представляет значительный интерес в связи с тем, что в таких базах данных реализованы все необходимые функции по поддержке баз данных, и для создания на их основе БД XML следует сконцентрироваться только на специфических для таких БД аспектах. БД XML на основе других баз данных можно создавать для поддержки обоих типов документов XML — ориентированных на данные и на документы. Однако такой подход наиболее приемлем для реализации БД XML, ориентированных на данные. При разработке БД XML на основе других баз данных принципиально важными являются следующие вопросы.
О Отображение между объектами XML и базы данных. Должен быть решен вопрос по описанию отображения между различными понятиями, характерными для XML, и выбранной СУБД. Причем это отображение должно поддерживаться в обе стороны. Такое отображение прежде всего должно касаться схемы документов XML (DTD, XML Schemas и т. д.) с одной стороны, и схемы базы данных с другой.
О Ввод документов XML в базу данных. Необходимо предоставлять возможность вводить в базу данных документы XML в таком виде, как они есть, не зависимо от того, как они будут храниться и использоваться.
О Хранение документов XML в базе данных. СУБД должна предоставлять средства эффективного хранения документов XML. Документы могут храниться либо в своем исходном виде, либо представляться в виде, наиболее подходящем для выбранной СУБД.
О Поиск и вывод документов XML. Независимо от способа хранения документов, должны предоставляться средства организации их поиска и вывода.
В оставшихся разделах этого урока мы рассмотрим некоторые из них по отношению к реляционным базам данных. Сначала изучим возможности стандарта SQL по описанию отображений между SQL и XML, а также по представлению данных в базах данных в виде документов XML. К сожалению, по состоянию на настоящий день стандарт SQL специфицирует только возможности представления значений, хранящихся в базе данных, в виде значений XML. Второй важный аспект баз данных XML, связанный с обратным процессом, а именно вводом документов XML в базу данных и их хранением, стандарт не рассматривает, в связи с чем эта составляющая баз данных XML будет кратко рассмотрена на примере Oracle.
Отображения между SQL и XML
Стандарт SQL специфицирует отображения между объектами SQL и XML. Эта спецификация в основном направлена на представление в XML объектов SQL, но в некоторых случаях описываются отображения и в обратную сторону. Стандарт SQL специфицирует следующие отображения:
О наборов символов SQL в Unicode;
О идентификаторов SQL в XML;
О типов данных SQL в XML;
О значений SQL в значения XML;
О таблиц SQL в XML;
О определений таблиц SQL в XML Schema.
Эти отображения кратко рассматриваются далее.
Отображение наборов символов SQL в Unicode
SQL допускает использование одного или более именованных наборов символов. Выбор того или иного набора и их внутреннее представление зависят от реализации, то есть предоставляется право решать этот вопрос разработчикам СУБД. В документах XML должен использоваться набор символов Unicode. Таким образом, в каждом конкретном продукте, поддерживающем SQL/XML, должна самостоятельно решаться проблема отображения символов в обоих направлениях.
Отображение идентификаторов SQL в имена XML и наоборот
Диапазон допустимых в идентификаторах SQL символов намного шире, чем набор допустимых символов в именах XML. С другой стороны, в XML либо существуют ограничения на использование в именах тех или иных символов или набора символов (например, имена не могут начинаться с xml в виде любой комбинации прописных и строчных букв), либо некоторые символы используются специальным образом (например, символ : используется для отделения префикса пространства имен). В связи с этим в стандарте SQL/XML специфицируются правила преобразования символов в идентификаторах SQL при их отображении в имена XML.
О Если символы идентификатора являются допустимыми в именах XML, они не преобразуются.
О Если символ идентификатора является недопустимым, он преобразуется в последовательность шестнадцатеричных цифр, взятых из кодировки этого символа в Unicode, которым предшествуют символы _х и за которыми ставится символ _.
О При отображении символов xml в начале идентификатора и символа : допускаются так называемые полное и частичное отображения. При полном отображении символ :, располагающийся не в начале идентификатора, отображается в _х003А_, а символы xml, располагающиеся в начале идентификатора, отображаются в _x0078_ml и _x0058_ML соответственно. При частичном отображении никакие замены относительно символов : и xml не предпринимаются.
Обратное отображение имен XML в идентификаторы SQL является прямо противоположным описанному выше отображению.
Отображение в XML типов данных SQL
В XML Schema определены простые типы данных и лексическое представление их значений. SQL/XML предоставляет механизм отображения любого скалярного типа данных SQL в тип данных XML Schema. Суть этого отображения заключается в выборе для типа SQL наиболее близкого типа. Под понятием наиболее близкий подразумевается, что тип данных XML Schema позволяет представлять все возможные значения соответствующего типа SQL и как можно меньше значений, которые не являются значениями SQL. Чтобы ограничить допустимые значения XML теми, которые являются допустимыми в SQL, используются фасеты XML Schema. Например, тип INTEGER SQL отображается в тип INTEGER XML Schema. При этом используются фасеты mi nlncl usi ve и maxlnclusive для указания минимально и максимально допустимых значений этого типа, устанавливаемые той или иной реализацией SQL. Кроме того, отображение SQL/XML использует механизм аннотаций XML Schema для сохранения информации о типе данных SQL, которая иначе теряется. Использование аннотаций не является обязательным в описании отображения SQL/XML, поэтому те или иные реализации отображения могут аннотацию не использовать.
Мы не будем вдаваться в подробности описания всех нюансов отображений типов данных, а приведем ряд примеров, предполагая, что они дадут читателю общее
представление об этих механизмах. В приводимых примерах xsd является префиксом пространства имен XML Schema, sql xml — префиксом пространства имен SQL/XML, xsd:annotation является именем элемента, определенного в XML Schema, a sql xml: sql type — именем элемента, определенного в SQL/XML для метаданных, специфических для SQL.
Приведем пример отображения типа данных CHAR (10) (здесь и далее символ => означает отображение):
CHAR(IO) CHARACTER SET LATIN1 COLLATION DEUTSCH =>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="10,7>
<xsd:annotation>
<sqlxm1:sql type name="CHAR" length* 40"
characterSetName="LATINl" col 1 at1on="DEUTSCH"/>
</xsd:annotation>
</xsd:restriction>
</xsd:simpleType>
Пример того же отображения без аннотации:
CHAR(IO) CHARACTER SET LATIN1 COLLATION DEUTSCH =>
<xsd:simpleType>
<xsd:restriction base="xsd:string,,>
<xsd:length value=40'7>
</xsd:restriction>
</xsd:simpleType>
Пример отображения типа данных INTEGER:
INTEGER =>
<xsd:simpleType>
<xsd:restriction base="xsd:integer">
<xsd:maxlnclusive va1ue="2157483647"/>
<xsd:mi nlnclusi ve value="-2157483648"!>
<xsd:annotation>
<sqlxml .-sqltype name="INTEGER,7>
</xsd:annotation>
</xsd:restriction>'
</xsd:simpleType>
Пример отображения типа данных DECIMALS, 2):
DECIMALS, 2) =>
<xsd:simpleType>
<xsd:restrict!on base="xsd:decimal">
<xsd:precision value="8,7>
<xsd:scale value="2'7>
<xsd:annotation>
<sqlxml:sqltype name=HDECIMAL" userPrec1s1on=”8" sca1e="2'7> </xsd:annotation>
</xsd:restriction>
</xsd:simpleType>
Пример отображения типа данных REAL:
REAL =>
<xsd:simpleType>
<xsd: restri cti on base="xsd: fl oat ">
<xsd:annotation>
<sqlxml:sqltype name^'REAL" preci si on=,,24Mmi nExponent="-149" maxExponent="104"/>
</xsd:annotation>
</xsd:restriction>
</xsd:simpleType>
Пример отображения типа данных INTERVAL YEAR(4) TO MONTH:
INTERVAL YEAR(4) TO MONTH =>
<xsd:simpleType>
<xsd:restri ction base="xsd:ti meDuration">
<xsd:pattern value= M-?P\p{Nd}{1.4}Y\p{Nd}{2}M,7>
<xsd:annotation>
<sq1 xml:sqltype name="INTERVAL YEAR TO MONTH"
1eadingPreci sion="4"/>
</xsd:annotation>
</xsd:restriction>
</xsd:simpleType>
ПРИМЕЧАНИЕ В текущем стандарте SQL отсутствует описание отображения поль- зовательских типов данных и конструируемых типов данных.
Отображение значений SQL в значения XML
Для каждого типа SQL существует отображение его значений в пространство значений соответствующего типа XML Schema. Это отображение в основном определяется отображением типов данных. Что касается отображения значений NULL, то предоставляется возможность выбора между отсутствием соответствующего элемента или заменой NULL на элемент, отмеченный как xsi :nil="true". В табл. 19.1 приводятся примеры отображения значений.
Таблица 19.1. Отображение значений SQL и XML
Тип данных SQL
Значение SQL
Значение XML
VARCHAR(IO)
'Smith'
Smith
INTEGER
10
10
DECIMAL(5, 2)
99.52
99.52
TIME
TIME '12;30:00*
12:30:00
INTERVAL HOUR TO MINUTE
INTERVAL '2:15'
PT02H15M
Отображение таблиц SQL в XML
Это отображение позволяет представлять отдельные таблицы или множество таблиц в документы XML. Отображать можно только базовые таблицы или их представления. Отображение производится от имени конкретного пользователя,
поэтому он может отобразить только те столбцы таблицы, которые являются доступными ему для чтения.
Предоставляется два варианта отображения. В первом случае таблицы SQL отображаются во множество элементов XML (лес элементов XML), в котором имена элементов самого верхнего уровня наследуют имя таблицы и каждый из таких элементов содержит множество элементов, соответствующих строке таблицы. Во втором варианте таблица отображается в документ XML с единственным корневым элементом, имеющим имя таблицы, а каждая строка таблицы отображается в элемент под именем <row>, содержащим множество элементов, соответствующих значениям строки таблицы. Для отображения значений NULL предоставляется возможность выбрать один из двух вариантов, рассмотренных выше. Приведем примеры. Первый вариант отображения таблицы SUBJECT выглядит следующим образом:
<SUBJECT>
<SBJPK>1</SBJPR>
<МАМЕ>операционные системы</МАМЕ>
</SUBJECT>
<SUBJECT>
<SBJPK>2</SBJPR>
<МАМЕ>проектирование компыотеров</МАМЕ>
</SUBJECT>
Второй вариант отображения этой же таблицы даст следующий документ XML:
<SUBJECT>
<row>
<SBJPK>1</SBJPR>
<МАМЕ>операционные системы</МАМЕ>
</row>
<row>
<SBJPK>2</SBJPR>
<МАМЕ>проектирование компьютеров</МАМЕ>
</row>
</SUBJECT>
Если для отображения значения NULL был выбран вариант использования атрибута xsl: nl 1 ■"true", тогда при отображении очередной строки таблицы SUBJECT, у которой отсутствует значение столбца NAME, строка примет такой вид:
<row>
<SBJPK>3</SBJPR>
<NAME xs1 inil^true" />
</row>
Если же выбран второй вариант, то есть отсутствие элемента такого столбца, получим следующий результат отображения строки:
<row>
<SBJPK>3</SBJPR>
</row>
Отображение в XML определений таблиц SQL
Среди множества возможных вариантов отображения в XML определений таблиц SQL комитет по стандартизации SQL выбрал вариант, при котором производится построение глобально именованных типов данных XML Schema для каждого из типов, используемых для описания отображаемой таблицы. Мы не будем приводить сложных формальных определений такого отображения, а покажем его использование на конкретном примере. Вот как выглядит XML Schema, созданная для таблицы FACULTY:
<xsd:schema>
<xsd:simpleType name "INTEGER">
<xsd:restriction base="xsd:integer"/>
</xsd:simpleType>
<xsd:simpleType name="VARCHAR_30">
<xsd:restriction base="xsd:string”>
<xsd:length value="30*7>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="VARCHAR_20">
<xsd:restriction base="xsd:string">
<xsd:length value="20V>
</xsd:restriction>
</xsd:simpleType>
<xsd: simpleType name=,,CHAR_5">
<xsd:restriction base="xsd:string">
<xsd:length value=M5*7>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="DECIMAL_7_2">
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="9,7>
<xsd:fractionDigits value="2"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="RowType.FACULTY">
<xsd:sequence>
<xsd:element name="FACPK" type="INTEGER*7>
<xsd:element name="NAME" type="VARCHAR_30"/>
<xsd:element пате="ОЕАМ" type="VARCHAR_20"/>
<xsd:element name="BUILDING" type="CHAR_5'7>
<xsd:element name="FUND" type=”DECIMAL_7_2" nillable="true,7>
</xsd.sequence>
</xsd:complexType>
<xsd:complexType name="TableType.FACULTY">
<xsd:sequence>
<xsd:element name="row" type="RowType.FACULTY" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="FACULTY" type="TableType.FACULTY"/>
</xsd:schema>
Сначала мы создали именованные типы данных XML Schema для всех типов данных, которые используются при определении столбцов таблицы FACULTY. Далее эти имена используются в определении элементов, соответствующих каждому из столбцов таблицы. Выбранные в стандарте SQL правила формирования имен типов данных XML Schema, которые соответствуют скалярным типам данных SQL, довольно просты. Приведем несколько дополнительных примеров в табл. 19.2.
Таблица 19.2. Примеры формирования имен XML Schema
Тип данных SQL
Имя XML Schema
CHARACTERS)
CHAR_5
CHARACTERS) CHARACTER SET LATIN1
CHAR_5
INTEGER
INTEGER
TIMESTAMPS)
TIMESTAMP_6
TIMESTAMP(O) WITH TIME ZONE
TIMESTAMP_WTZ_O
INTERVAL HOUR TO SECOND (1)
INTERVAL_HOUR_2_SECOND_1
Любой тип данных SQL включается в XML Schema один раз не зависимо от того, сколько столбцов таблицы имеют этот тип. Например, если в таблице несколько столбцов имеют тип DECIMAL(9, 2), в XML Schema будет включен только один тип данных DECIMAL_9_2. Все столбцы, имеющие, например, тип данных CHAR(6), будут отображаться в единственный тип данных XML Schema CHAR 6 не зависимо от того, какой набор символов они используют. Это объясняется тем, что тип данных XML Schema xsd:string состоит только из наборов символов Unicode. Далее создается именованный тип данных XML Schema, представляющий строки таблицы и затем создается тип таблицы в целом. Имя типа строк таблицы формируется путем соединения строки "RowType" с именем таблицы через символ точки (.). Имя типа таблицы имеет префикс "ТаЫеТуре". Наконец, создается элемент FACULTY с типом таблицы.
Обратите внимание, что при определении элемента FUND способ представления значений NULL выбран гп 1. Если бы необходимо было указать способ «отсутствует», следовало бы записать следующим образом:
<xsd:element name="FUND" type="DECIMAL_7_2" min0ccurs="0,7>
Функции и предикаты XML
В стандарте SQL определен тип данных XML, который соответствует правильно определенному значению XML. Значение типа XML называется значением XML. Значения XML не сравнимы. SQL содержит ряд функций, которые позволяют формировать значения XML на основании значений таблиц базы данных. Эти
функции получили название функций публикаций XML. К этим функциям относятся следующие:
О XMLElementО - создает элемент XML с указанием его имени;
О XMLAttributesC) - создает атрибуты XML на основании столбцов таблицы, используя имя столбца в качестве имени атрибута;
О XMLRootO — создает корневую вершину документа XML;
О XMLCommentO — создает комментарий XML;
О XMLP1 () — создает инструкцию XML по обработке;
О XMLParseO - производит синтаксический анализ строки символов и возвращает структуру XML;
О XMLForestO — создает элементы XML из столбцов таблицы, используя имена каждого из столбцов в качестве имен соответствующих элементов;
О XMLConcatO — производит конкатенацию списка отдельных значений XML с построением единственного значения XML;
О XMLAgg () - объединяет совокупность строк, каждая из которых содержит единственное значение XML, в одно значение XML.
Кроме того, имеется еще одна функция, которая формирует строку символов на основании значения XML — это функция XMLSerlal ize. Далее мы кратко рассмотрим эти функции.
Функция XMLElement
Эта функция создает элемент XML из задаваемого выражения. В простейшем виде она имеет следующий синтаксис:
XMLElement(NAME имя_злемента, имя_столбца)
С помощью фразы NAME задается имя элемента, а второй аргумент указывает, на основании значения какого столбца формируется элемент XML. Приведем пример:
SELECT XMLElement(NAME "TchName", t.Name)
FROM TEACHER t
WHERE t.TchPK = 1;
XMLELEMENT(NAME"TCHNAME".T.NAME)
<ТсМНате>Вибровский</ТсЬНате>
Вместо столбца может использоваться выражение над столбцами:
SELECT XMLElement(NAME "Total Sal ary", t.Salary + t.Rise)
FROM TEACHER t
WHERE t.TchPK = 1;
XMLELEMENT(NAME"TOTALSALARY", T.SALARY+T.RISE)
<TotalSalary>740</TotalSalary>
Если столбец принимает значение NULL, формируемый из него элемент не будет содержать своего контента, как это видно из следующего примера:
SELECT XMLElement(NAME "Name", t.Name) AS "TchName", XMLElement(NAME "DepID", t.DepFK) AS "TchDep"
FROM TEACHER t
WHERE LOWER(t.Post) = 'профессор':
TchDepTchDepTchName
TchDep
TchDep
<Нате>Сидоров</Н^те> <DepID>2</DepID>
<Name>Pe3BaH</Name> <DepID>2</DepID>
<Name>AxpoMeeB</Name> <DepID></DepID>
Как видно, в третьей строке элемент DepID кафедры не содержит значения.
Функцию XMLElement можно вкладывать, создавая тем самым вложенную структуру элементов XML. Вложение производится путем использования списка функций XMLElement вместо второго аргумента, как это показано в следующем примере:
SELECT XMLElement("Teh",
XMLElement("Name". t.Name),
XMLElementCHDate", t.HDate)) AS "RESULT"
FROM TEACHER t*
WHERE t.TchPK = 3 OR t.TchPK = 4;
RESULT
<Tch><Name>BoponaeB</Name><HDate>2002-09-02</HDate></Tch>
<ТсЬхНате>Рамишевский</НатехНОа1е>1998-09-09</НПа1ех/ТсЬ>
Таким образом можно создавать элементы XML с произвольной глубиной вложенности. В следующем примере элементы имеют глубину вложенности 3:
SELECT XMLElementCtch",
XMLElementCmainlnfo",
XMLElementCname", t.Name),
XMLElementCpost", t.Post)),
XMLElementCadditionlnfo".
XMLE1ement("sal ary", t.sal ary),
XMLElementC’rise", t.Rise))) AS "RESULT"
FROM TEACHER t
WHERE t.TchPK = 7 OR t.TchPK = 14;
RESULT
<tch>
<mainlnfo>
<name>HeKapb</name><post>floueHT</post>
</mainInfo>
<additionlnfo>
<sal ary>890</sal aryxri se>440</ri se>
</additionInfo>
</tch>
<tch>
<mainlnfo>
<name>HayMOB</namexpost>floueHT</post>
</mainInfo>
<additionlnfo>
<salary>770</salary><rise>350</rise>
</addition!nfo>
</tch>
>> ^ПРИМЕЧАНИЕ SQL возвращает значение XML в виде одной строки. Для того чтобы такое значение можно было лучше визуально воспринимать, мы иногда будем разбивать их на множество строк с указанием иерархической вложенности их элементов, как мы это сделали в предыдущем примере.
Можно также создавать вложенные элементы со смешанным контентом, как это делается в следующем примере:
SELECT t.TchPK.
XMLELEMENT
(NAME "tch".
'Преподаватель*.
XMLELEMENT (NAME "name". t.Name), ' был принят на работу *.
XMLELEMENT (NAME "hd". t.HireDate)
) AS "Result"
FROM TEACHER t
WHERE LOWER(t.Post) = 'профессор':
TCHPK Result
16 <tch>
Преподаватель<пате>Сидоров</пате> был принят на работу <hd>1992-09-01</hd>
</tch>
10 <tch>
Преподаватель<пате>Резван</пате> был принят на работу <hd>2000-ll-ll</hd>
</tch>
13 <tch>
Преподаватель<пате>Ахромеев</пате> был принят на работу <hd>1998-05-05</hd>
</tch>
Функция XMLAttributes
Функция XMLAttributes используется для указания атрибутов элемента. Она может использоваться только в составе функции XMLElement и имеет следующий синтаксис:
XMLAttributes(cTon6eu [AS имя_атрибута][, столбец [AS имя_атрибута]]...)
Список ее аргументов содержит имена столбцов (или выражений над столбцами) с возможными именами атрибутов. Если имена атрибутов отсутствуют, в их качестве используются имена столбцов.
SELECT t.TchPK,
XMLElement(NAME "Tch".
XMLAttributes(t.TchPK.
t.Name AS "Name", t.DepFK AS "DepID")
) AS "Result"
FROM TEACHER t
WHERE LOWER(t.Post) = 'доцент';
TCHPK Result
4 <Tch TCHPK="4" Нате="Рамишевский" DepID="2"></Tch>
6 <Tch TCHPK="6" №те="3авратинский" DepID="2"></Tch>
7 <Tch TCHPK="7" Нате="Лекарь" DepID="2"></Tch>
14 <Tch TCHPK="14" Name="HayMOB"></Tch>
Мы получили элементы с атрибутами, но без контента. Имя первого атрибута соответствует имени столбца, а имена двух других атрибутов указываются явно. Обратите внимание, что в четвертой строке атрибута DepID нет, так как в таблице отсутствует значение соответствующего столбца.
Документы XML очень часто используют пространства имен. Элемент с определенным пространством имен может быть создан с помощью функции XMLAttri - butes следующим образом:
XMLElementCNAME "hr:emp".
XMLAttributes ('http://www.hr.com/hr' AS "xmlns:hr")
)
Функция XMLForest
Создает значение XML co списком элементов XML. Каждый из аргументов этой функции создает отдельный элемент. Упрощенный синтаксис функции следующий:
XMLForest(столбец [AS имя_злемента][, столбец [AS имя^злемента]]...)
Как и в функции XMLAttributes может явно указываться имя элемента, в противном случае в качестве имени элемента используется имя столбца. Приведем пример:
SELECT t.TchPK. XMLForest(t.Name. t.HireDate AS "hire". t.Post) AS "Result"
FROM TEACHER t
WHERE t.Chief = 4;
TCHPK Result
<NAME>XopeHKo</NAME>
<hi re>2001-10-10</hire>
<Р05Т>преподаватель</Р0$Т>
<NAME>Boponaee</NAME>
<hire>2002-09-02</hire>
<Р05Т>ассистент</Р0$Т>
<МАМЕ>Кузинцев</НАМЕ>
<hire>1991-01-01</hire>
<Р05Т>преподаватель</Р05Т>
По сути функция XMLForest заменяет несколько подряд расположенных функций XMLElement.
Функция XMLConcat
Эта функция производит конкатенацию (сцепление) значений XML, заданных в аргументах функции. Синтаксис функции следующий:
XMLConcat(список_ХМЕ_значений)
Аргументы, принимающие значение NULL, не включаются в результат. Если все аргументы принимают значение NULL, то результат функции — значение NULL. Приведем пример:
SELECT XMLConcat
(XMLElement(NAME "name", f.Name),.
XMLForest (f.Dean AS "dean". f.Fund AS "fund") ) AS "Result"
FROM FACULTY f;
Result
<name>HH$opMaTHKa</name><dean>CMflopoB</dean><fund>25000</fund> <name>Kv\6epHeiv\Ka</name><dean>neipoB</dean><fund>2700(^
<name>MaTeMaTHKa</name><dean>HrHaTOB</dean><fund>23000</fund>
Функция XMLAgg
Функция XMLAgg относится к классу агрегатных функций SQL. На вход к ней подается множество строк одной из выделенных групп таблицы. По каждой из таких строк формируется значение XML согласно аргументу функции. И затем эти значения XML сцепляются в одно значение XML. Синтаксис функции следующий:
ХМЕАдд(ХМЕ_значение [ORDER BY порядок_сортировки])
Приведем пример:
SELECT XMLElement
(NAME "post".
XMLAttributes (t.Post AS "name").
XMLAgg(XMLElement(NAME "tch". t.Name )) ) AS "postjist"
FROM TEACHER t
WHERE t.DepFK = 2 GROUP BY t.Post:
post_l1 st
<post пате="ассистент">
<tch>Bn6pOBCKMH</tch><tch>BoponaeB</tch>
<tch>MapibiH0B</tch><tch>K03nyTMH</tch>
</post>
<post пате="доцент">
<tch>Paмишeвcкий</tch><tch>Зaвpaтинcкий</tch><tch>Лeкapь</tch>
</post>
<post пате="преподаватель">.
<tch>XopeHKO</tch><tch>HefleBefleeB</tch><tch>Ky3HHueB</tch>
</post>
<post пате="профессор">
<tch>CnflopOB</tch><tch>Pe3BdH</tch>
</post>
В этом запросе для каждой группы преподавателей, объединенных по занимаемой должности, сначала формируется элемент с именем post, который содержит атрибут с названием должности. Затем с помощью функции XMLAgg по каждой строке группы формируются элементы XML, содержащие фамилии преподавателей, и затем все эти элементы объединяются в одно значение XML. При необходимости перед объединением элементов в одно значение они могут быть отсортированы согласно фразе ORDER BY. Так, например, в предыдущем примере для сортировки преподавателей в алфавитном порядке в пределах созданных групп необходимо записать функцию XMLAgg следующим образом:
XMLAgg(XMLElement(NAME "tch". t.Name) ORDER BY t.Name)
Имеется еще один вариант использования функции XMLAgg, когда создается подзапрос, формирующий множество строк. Во всех функциях XML, где согласно синтаксису должно стоять значение XML, можно использовать предложение SELECT, возвращающее в качестве своего значения значение XML. Однако такое предложение должно возвращать именно единственное значение XML, в противном случае вы получите сообщение об ошибке. Если же запрос возвращает множество строк, то с помощью функции XMLAgg они могут быть преобразованы в одно значение XML.
В следующем примере во внешнем запросе выбираются строки из таблицы FACULTY и по ним формируются элементы XML с атрибутами и вложенными элементами названий факультетов и фамилий их деканов. В подзапросе выбираются строки кафедр, которые принадлежат текущему факультету, из внешнего запроса. По каждой кафедре формируется значение XML, содержащее элемент кафедры с атрибутом и вложенными элементами — названием кафедры и фамилией заведующего кафедры. Наконец все полученные значения XML кафедр объединяются функцией XMLAgg в одно значение XML.
SELECT XMLElement(NAME "faculty",
XMLAttributes(f.FacPK AS "ID").
XMLForest(f.Name AS "name", f.Dean AS "dean").
XMLElement(NAME "departments”.
(SELECT XMLAgg(XmlElement(NAME "department".XMLAttributes(d.DepPK AS "ID").
XMLForest (d.Name AS "name". d.Head AS "head")))
FROM DEPARTMENT d
WHERE d.FacFK = f.FacPK))) AS "FACULTY-DEPARTMENTS"
FROM FACULTY f;
FACULTY-DEPARTMENTS
<faculty 10="Г><пате>информатика</пате><иеап>Сидоров</иеап>
<departments>
department ID="1">
<пате>базы flaHHMX</name><head>CoKonoB</head>
</department>
department ID="3">
<пате>интернет</пате><Ьеаи>Стрельцов</Ьеаи>
</department
department ID="2">
<пате>программирование</пате><Ьеаи>Федоров</Меаи>
</department>
</departments>
</faculty>
<faculty 10="2"><пате>кибернетика</патехйеап>Петров</иеап> department s>
department ID="6">
<пате>базы данных</пате><Неаи>Тараненко</Ьеаи>
</department
department ID="5">
<name>nMHrBHCTHKa</name><head>Kopo6oB</head>
</depa rtment
. department ID="4">
<пате>теория fl3biKOB</name><head>rлyщeнкo</head>
</department>
</departments>
</faculty>
<faculty ID=,,3"><name>MaTeMaTHKa</name>dean>MrHaTOB</dean> depa rtment s></depa rtments>
</faculty>
Функция XMLRoot
Эта функция используется для добавления свойств VERSION и STANDALONE к элементу корневой информации значения XML. Она имеет следующий синтаксис:
ХМЕР00Т(ХМЕ_значение. VERSION (строка | NO VALUE}[. STANDALONE [YES | NO | NO VALUE}]
Сначала вычисляется значение XML, а затем указанные свойства (VERSION, STANDALONE) и их значения добавляются к новому прологу. Если значение XML оказывается равным NULL, функция возвращает NULL. Пример:
SELECT XMLRoot (XMLElementC NAME "TchName", t.Name),
VERSION *1.0*, STANDALONE YES) AS RESULT
FROM TEACHER t
WHERE t.TchPK - 3 OR t.TchPK - 4;
RESULT
<?xml version”"1.0" standalone="yes"?>
<TchName>BoponaeB</TchName>
<?xml vers1on="1.0" standalone="yes"?>
<ТсМНате>Рамишевский</ТсЬМате>
Функция XMLComment
Эта функция возвращает значение XML в виде комментария. Синтаксис функции следующий:
XMLComment(строка)
Функция вычисляет строковое выражение аргумента, и полученная строка представляется в виде комментария XML. Если построенный комментарий XML оказывается недопустимым с точки зрения синтаксиса XML (например, текст
комментария содержит символы --), выдается сообщение об ошибке. Если вычисленное выражение оказывается равным NULL, формируется пустой комментарий XML (то есть <!>). Приведем пример:
SELECT XMLComment('3TO пример комментария') AS КОММЕНТАРИЙ
FROM DUAL;
КОММЕНТАРИЙ
<!--Это пример комментария-^
Функция XMLPi
Эта функция создает инструкцию по обработке XML. Она имеет следующий синтаксис:
XMLPi(NAME идентификаторе, строка])
К идентификатору, заданному первым аргументом, присоединяется через пробел строка символов, заданная вторым аргументом. Затем полученное выражение заключается между символами <? и ?> для создания инструкции по обработке. Строка второго аргумента может быть пустой. Если эта строка равна NULL, функция возвращает NULL. Если сформированное результирующее выражение не является допустимой инструкцией по обработке (например, идентификатор равен слову xml прописными или строчными буквами или второй аргумент содержит символ ?), выдается сообщение об ошибке. Приведем пример:
SELECT XMLPKNAME "OrderAnalysisComp", 'imported, reconfigured’)
AS "Пример функции XMLPi" FROM DUAL:
Пример функции XMLPi
<?0rderAnalysisComp imported, reconfigured?>
SELECT XMLPKNAME "OrderAnalysisComp")
AS "Пример функции XMLPi" FROM DUAL;
Пример функции XMLPi
<?OrderAnalysisComp?>
SELECT XMLPKNAME "xml", 'second argument')
AS "Пример функции XMLPi" FROM DUAL;
ERROR:
ORA-19042: Охватывающий тэг xml не должен являться частью xml ни в одной из комбинаций регистров
Функция XMLParse
Функция XMLParse используется для выполнения грамматического разбора строкового выражения, содержащего выражение XML, и преобразования этой строки в выражение типа XML. Синтаксис функции следующий:
XMLParse({DOCUMENT | CONTENT} строка [{PRESERVE | STRIP} WHITESPACE])
Если используется ключевое слово DOCUMENT, строка должна соответствовать правильно построенному документу XML, содержащему один корень. При использовании ключевого слова CONTENT аргумент должен соответствовать правильно построенному фрагменту XML, то есть он не обязательно должен иметь один корень. Если аргумент функции равен NULL, функция возвращает NULL. Фраза WHITESPACE указывает, что делать с пробельными символами (пробелы, символы табуляции и пустой строки) в результате построения значения XML. Фраза PRESERVE WHITESPACE указывает, что они должны быть сохранены, a STRIP WHITESPACE — их следует удалить. Второй вариант выбирается по умолчанию в случае отсутствия этой фразы. Приведем пример:
SELECT XMLParse(CONTENT
'124 <purchaseOrder poNo="12435">
<customerName> Acme Enterprises</customerName>
<1temNo>32987457</1temNo>
</purchaseOrder>') AS "XMLParse Example"
FROM DUAL:
XMLParse Example
124 <purchaseOrder poNo="12435">
<customerName> Acme Enterprises</customerName>
<1temNo>32987457</1temNo>
</purchaseOrder>
Функция XMLSerialize
Если все предыдущие функции возвращали значение типа XML, эта функция возвращает значение строкового типа на основании значения XML, заданного аргументом. Синтаксис функции следующий:
XMLSerial1ze((DOCUMENT | CONTENT) ХМЕ_значение AS тип_данных)
Функция вычисляет значение XML и преобразует его в указанный тип данных (в Oracle это могут быть, VARCHAR или CLOB). Если указано ключевое слово DOCUMENT, вычисленное значение XML должно быть правильно построенным документом XML (например, оно должно иметь один корень). В противном случае выдается сообщение об ошибке. Если указано ключевое слово CONTENT, полученное значение XML не проверяется на правильность с точки зрения документа XML. Если значение XML равно NULL или пустой строке (* *), функция возвращает значение NULL. Приведем пример:
SELECT XMLSerial 1ze(D0CUMENT XMLElemenKNAME "name". f.Name) AS CLOB)
AS "Пример XMLSerialize"
FROM FACULTY f;
Пример XMLSerialize
<пате>информатика</пате>
<пате>кибернетика</пате>
<пате>математика</пате>
Предикат IS DOCUMENT
Предикат IS [NOT] DOCUMENT проверяет, является проверяемое значение XML документом XML. Его формат следующий:
ХМ1_значение IS [NOT] DOCUMENT
Предикат IS NOT DOCUMENT является отрицанием к IS DOCUMENT.
Ввод, выбор и обновление документов XML
Как мы уже отмечали, стандарт SQL не специфицирует механизма ввода и хранения документов XML в базе данных SQL. В связи с этим мы кратко опишем эти возможности в Oracle.
Ввод документов XML
В Oracle определен тип данных XMLType для естественного оперирования документами XML в базе данных. Он обладает следующими возможностями:
О позволяет представлять в базе данных документы XML;
О имеет встроенные конструкторы и методы для работы с содержимым документов XML, например, можно создавать значения типа XMLType, извлекать и индексировать значения XML;
О может использоваться как тип данных столбца, таблицы или представления. Предоставляется два способа запоминания в базе данных значений типа XMLType: О в виде большого объекта, когда весь документ сохраняется как единое целое с его оригинальными особенностями, включая пробельные символы;
О в виде структурированного документа, при котором создаются внутренние таблицы и представления.
Для того чтобы запоминать в базе данных документы XML следует создать либо столбец таблицы типа XMLType, либо таблицу типа XMLType. Это делается следующим образом:
CREATE TABLE mytablel (
key_column VARCHAR(IO) PRIMARY KEY.
xml_column XMLType);
Таблица создана.
CREATE TABLE mytable2 OF XMLType;
Таблица создана.
Для загрузки документа XML в базу данных можно воспользоваться обычной командой SQL INSERT. Прежде чем сохранить документ в виде значения столбца или таблицы типа XMLType, он должен быть преобразован в значение типа XMLType с помощью имеющихся конструкторов. Конструкторы XMLType позволяют создавать значения типа XMLType из различных источников, включая значения типа VARCHAR, CLOB, а также их файлов (значения типа BFILE). Конструктору можно указать дополнительные параметры, например, можно отключить проверку на правильность
исходного документа XML, если он является действительно правильным документом XML. Если документ XML берется из файла, следует предварительно определить так называемый каталог SQL, который указывает путь к тому каталогу операционной системы, где располагается требуемый файл:
CREATE DIRECTORY xmldir AS 'D:\SQL_Manual\*
Каталог создан.
После этого можно следующим образом ввести требуемый документ XML в таблицу типа XMLType:
INSERT INTO mytable2
VALUES (XMETypeCbfilenameCXMLOIR*, *purchaseOrder.xml'), nls_charset_id('AL32UTF8*)));
строка создана.
Значение, передаваемое в функцию nls_charset_1d(), указывает, что файл представлен в кодировке UTF-8.
Oracle позволяет запоминать не только документ XML, но и схемы документов, представленные на языке XML Schema. Наличие схемы документов позволяет проверять документы на их соответствие схеме, а также облегчает и расширяет возможности по поддержке отображений SQL/XML. Прежде, чем использовать схему, ее следует зарегистрировать с помощью соответствующей процедуры. Регистрация предполагает указание URL схемы XML, исходного документа и способа его кодирования. При определении столбца типа XMLType или таблицы типа XMLType можно указать на их соответствие определенной XML Schema.
В таблицах или столбцах типа XMLType можно запоминать только правильно построенные документы XML. Кроме того, если такие столбцы или таблицы также ограничены определенной схемой XML, можно запоминать только документы, соответствующее этой схеме.
Выбор документов XML и их фрагментов
Для таблицы типа XMLType, которая состоит из единственного столбца, с помощью псевдостолбца OBJECT VALUE можно обратиться к значению XML. При этом выбирается документ XML целиком, например:
SELECT OBJECT_VALUE
FROM mytable2
OBJECT_VALUE
<PurchaseOrder
xml ns:xsi=http://www.w3.org/2001/XMLSchema-i nstance
xsi:noNamespaceSchemaLocati on=
"http://1ocalhost:8080/source/schemas/poSource/xsd/
purchaseOrder.xsd">
<Reference>SBELL-2002100912333601PDT</Reference>
<Act1ons>
<Act1on>
<User>SVOLLMAN</User>
</Action>
</Act1ons>
<Reject/>
<Requestor>Sarah J. Bell</Requestor>
<User>SBELL</User>
<CostCenter>S30</CostCenter>
<Sh1ppinglnstructions>
<name>Sarah J. Bell</name>
<address>400 Oracle Parkway
Redwood Shores
CA
94065
USA</address>
<telephone>650 506 7400</telephone>
«/Shi ppi nglnstructi ons>
<Special Instruct!ons>Air Mai1</Spec1al Instruct!ons>
<lineltems>
<LineItem ItemNumber=,,l,,>
<Description>A Night to Remember</Description>
<Part Id="715515009058M UnitPrice="39.95" Quantity»”2"/>
</L1neItem>
<L1neItem ItemNumber="2">
<Description>
The Unbearable Lightness Of Being
</Description>
<Part Id-"37429140222" Unit Price-" 29.95" Quantity="2,,/>
</LineItem>
<LineItem ItemNumber="3">
<Descri pti on>Sisters</Description>
<Part №"715515011020" UnitPr1ce»,,29.95" Quantity="4"/>
</L1neItem>
</LineItems>
</PurchaseOrder>
Oracle предлагает функцию EXTRACTO, которая возвращает вершины документа XML, соответствующие заданному выражению XPath. Результатом функции может быть весь документ или только его фрагмент. В следующем запросе из документа выбирается элемент Reference.
SELECT EXTRACT(OBJECT_VALUE. '/PurchaseOrder/Reference*)
FROM mytable2;
EXTRACT(OBJECT_VALUE,1/PURCHASEORDER/REFERENCE*)
<Reference>SBELL-2002100912333601PDT</Reference>
В следующем запросе выбирается первый элемент Lineitem в коллекции Lineitems:
SELECT EXTRACT(OBJECT_VALUE. */PurchaseOrder/L1neItems/L1neItem[l]*)
FROM irytable2;
EXTRACT(OBJECT_VALUE,*/PURCHASEORDER/LINEITEMS/LINEITEM[1]*)
<LineItem ItemNumber="l">
<Description>A Night to Remember</Description>
<Part Id="715515009058,, Un1tPr1ce=,,39.95" Quantity=,,2"/>
</L1neItem>
Наконец, в следующем примере выводятся три элемента Description, соответствующие заданному выражению XPath. Эти элементы выводятся в виде вершин,
поэтому результирующее значение XMLType не имеет единственного корня, то есть является фрагментом документа XML:
SELECT EXTRACT(OBJECT_VALUE, */PurchaseOrder/Lineltems/Lineltem/Description*) AS RESULT
FROM mytable2;
RESULT
<Description>A Night to Remember</Description>
<Description>The Unbearable Lightness Of Being</Description>
<Description>Sisters</Description>
Oracle предлагает еще ряд функций и предикатов, которые расширяют возможности выбора документов XML и их частей.
Обновление документов XML
Oracle предоставляет возможности по обновлению документов XML. Операции обновления позволяют либо обновить все содержимое документа, либо только его отдельные части. Такое частичное обновление является весьма полезным свойством при необходимости выполнения небольших изменений в очень больших документах.
Функция updateXML позволяет производить частичное обновление документов XML, хранящихся как значения типа XMLType. Она позволяет произвести множество изменений в документе за одну операцию обновления. Выражение XPath идентифицирует вершину, которую следует обновить, а также новое значение изменяемой вершины. В следующем примере с помощью функции updateXML производится обновление вершины, связанной с элементом User.
UPDATE mytable2
SET OBJECT_VALUE = updateXML(OBJECTJ/ALUE, ’/PurchaseOrder/User/textO'. 'SKING') WHERE existsNode(OBJECT_VALUE,
.1/Purchaseorder[Reference=,,SBELL-2002100912333601PDT,,],) - 1;
строка обновлена.
Здесь во фразе WHERE мы использовали функцию existsNode, которая возвращает 1 в том случае, когда документ содержит вершину, совпадающую с заданным выражением XPath. В следующем примере производится замена всего элемента документа XML. Выражение XPath ссылается на обновляемый элемент. Новое значение формируется с помощью конструктора типа XMLType.
UPDATE mytable2
SET OBJECT_VALUE = updateXML(OBJECT_VALUE. ,/PurchaseOrder/LineIteпls/LineItem[l],.
XMLTypeC'<LineItem ItemNumber="r*>
<Description>The Lady Vanishes</Description>
<Part Id="37429122129" UnitPrice»"39.95" Quantity»"Г7> </LineItem>*))
WHERE existsNode(OBJECT_VALUE.’/PurchaseOrder[Reference»,,SBELL-2002100912333601PDT"]') = 1;
строка обновлена.
Самостоятельная работа
Приведите пример отображения типа данных DECIMAL(5, 4) в XML.
Приведите два варианта отображения таблицы FACULTY в XML.
Опишите XML Schema для определения таблицы DEPARTMENT.
Напишите запрос, который выводит значения столбца Post таблицы TEACHER в виде элементов XML.
Напишите запрос, который выводит названия факультетов и фамилии деканов в качестве атрибутов элементов XML.
Напишите запрос, который на основании таблицы FACULTY формирует документ XML, содержащий для каждого корпуса содержит следующие элементы: <bu1ld1ng пит="номер корпуса">
<Тас>название_факулыета</Тас>
<беап>фамилия_декана</беап>
</building>
Создайте в Oracle таблицу TESTTABLE, которая имеет тип XMLType.
Сформируйте простейший документ XML в тестовом файле и вставьте его в таблицу TESTTABLE.
Подведение итогов
Усвоив материал этого урока, вы научились:
Q отображать конструкции SQL в конструкции XML;
использовать функции и предикаты XML для представления содержимого базы данных в виде документов XML и их частей;
производить ввод, обновление и выборку документов XML из базы данных.
^О) УРОК Системный каталог
Для того чтобы поддерживать базу данных, СУБД должна следить за описанием всех объектов, которые создаются пользователями: базовыми таблицами и представлениями, индексами, прописанными в системе пользователями, их правами доступа, триггерами и т. д. Ясно, что наиболее логичный и эффективный способ поддержки такой информации — использовать для этого такие же таблицы, как и те, которые используются для создания и ведения пользовательских данных. Это дает возможность СУБД разметать и управлять необходимой ей информацией, используя те же самые структуры хранения и процедуры, которые она использует для размещения и управления создаваемыми пользователем данными. Набор таких таблиц обычно называют системным каталогом. Иногда их также называют словарем данных или просто системными таблицами. Далее мы рассмотрим основные идеи, которые лежат в основе системных каталогов, предложения стандарта SQL по их поддержке и конкретный пример их использования в Oracle.
Что такое системный каталог
Системный каталог — это совокупность специальных таблиц базы данных, в которых хранится информация о свойствах всех созданных объектов базы данных. Такие системные таблицы создаются автоматически при создании базы данных, и их ведение производится системой также автоматически по мере создания, обновления и удаления пользователями тех или иных объектов базы данных. Таблицы каталога не могут быть подвергнуты непосредственным изменениям пользователем с помощью команд INSERT, UPDATE, DELETE, однако это делается им косвенно через команды CRATE, ALTER, DROP, GRANT, REVOKE и другие.
Таблицы системного каталога напоминают обычные таблицы SQL: те же строки и столбцы данных. Например, одна таблица каталога обычно содержит информацию о таблицах существующих в базе данных, по одной строке на каждую таблицу базы данных; другая содержит информацию о различных столбцах таблиц, по одной строке на столбец, и т. д.
В большинстве СУБД пользователи могут обратиться к системному каталогу с целью получения информации об их содержимом. Это очень полезно, так как дает возможность узнать кое-что о базе данных, которую вы используете. Очевидно, вся информация не всегда доступна всем пользователям. Подобно другим таблицам, доступ к системному каталогу ограничен соответствующими правами доступа. Обычно правами предоставления доступа к каталогу распоряжается администратор баз данных или системный администратор. Кроме того, некоторые полномочия могут предоставляться пользователям автоматически.
Пользователи, системные инженеры и администраторы базы данных используют системный каталог, даже не подозревая об этом. Доступ к нему может быть непосредственный или косвенный. Пользователи, для которых создается база данных, получают доступ к каталогу косвенно. Когда пользователь пытается получить разрешение на вход в базу данных, СУБД обращается к каталогу для проверки, зарегистрирован ли пользователь с указанным именем и паролем и имеет ли он право подключиться к базе данных. Кроме того, проверяется, имеет ли пользователь те или иные права доступа к данным базы данных.
Проектировщики прикладных систем, системные аналитики, системные инженеры являются теми пользователями базы данных, которые занимаются проектированием, разработкой и сопровождением баз данных и прикладных систем. Эти лица используют каталог непосредственно для управления процессом разработки и сопровождения прикладных систем. Эти пользователи работают с теми составными частями каталога, которые имеют отношение к объектам базы данных, ролям, полномочиям и статистике использования базы данных.
Администраторы базы данных в наибольшей мере непосредственно используют системный каталог. Непосредственный доступ к каталогу является составной частью их ежедневной работы. Они могут выполнять эту функцию с помощью построения запросов в SQL или используя специальные средства администрирования. Администратор баз данных использует каталог для определения пользователей и ролей, предоставления им прав доступа к системе и данным, управления ресурсами системы, настройки базы данных и т. д.
Системный каталог в стандарте SQL
Стандарт SQL рассматривает системный каталог как совокупность схемы определения и информационной схемы.
О Схема определения — это базовые таблицы системного каталога. Полнота определения этих таблиц определяется возможностями SQL. Единственная цель схемы определения — обеспечить модель данных для поддержки информационной схемы, а также обеспечить понимание того, где и как хранятся данные системного каталога. Спецификация схемы определения не подразумевает, что конкретные реализации SQL будут предоставлять функциональные возможности по хранению и доступу к данным системного каталога именно так, как это определено в схеме определения. Главное, чтобы схема определения могла хранить всю информацию об описаниях объектов базы данных, поддерживать требуемую целостность по отношению к ним, а также предоставляла
возможность построения представлений информационной схемы. Стандарт SQL специфицирует более 60 таблиц схемы определения, которые, в частности, позволяют хранить информацию об определении таких объектов базы данных, как таблицы, столбцы, представления, пользователи, права доступа, утверждения, домены, ограничения целостности, триггеры и многие другие. О Информационная схема — это представления, определенные на основе базовых таблиц схемы определения. Доступ к представлениям производится как и к обычным таблицам. Информационная схема предназначена для обычных пользователей. Поэтому удаление и изменение строк таблиц-представлений не разрешено. Однако использование предложения SELECT по отношению к представлениям информационной схемы имеет полномочие PUBLIC WITH GRANT OPTION. Это значит, что любой зарегистрированный пользователь имеет право просматривать содержимое этих представлений и, более того, привилегия SELECT может быть далее передана любым другим представлениям, которые ссылаются на представления информационной схемы. Информационная схема также содержит определение нескольких доменов, которые используются в некоторых столбцах схемы определения. Полномочия по использованию этих доменов определены как PUBLIC WITH GRANT OPTION, поэтому они могут использоваться любым пользователем. Стандарт SQL допускает дальнейшее развитие информационной схемы или специфическую ее интерпретацию в конкретных реализациях. Стандарт SQL предлагает более 70 представлений информационной схемы.
Большинство развитых коммерческих СУБД поддерживают концепцию стандарта SQL по представлению системного каталога в виде базовых отношений каталога и множества таблиц-представлений, основывающихся на базовых отношениях. Структура системных каталогов большинства СУБД очень близка к предложениям стандарта SQL. Мы рассмотрим некоторые из возможностей системного каталога Oracle, которые представляют особый интерес для пользователей.
Системный каталог Oracle
Так как каждая таблица должна иметь своего владельца, владельцем системных таблиц в Oracle является специальный пользователь, который относится к группе администрирования. Таблицы каталога в Oracle подразделяются на три основные категории: представления, доступные пользователям, представления администратора базы данных и динамические таблицы производительности, которые также доступны через представления. Обратите внимание, что доступ к базовым таблицам каталога производится через представления.
Представления, доступные пользователям, позволяют им опрашивать каталог относительно информации, имеющей в той или иной мере отношение именно к ним, например их права и полномочия, доступные им таблицы и другие объекты базы данных. Представления администратора базы данных оказывают ему содействие в выполнении его функциональных обязанностей. Динамические таблицы производительности также используются администратором для получения более глубокой информации, необходимой для отслеживания и настройки эффективной работы с базой данных.
Далее рассмотрим только некоторые из тех системных представлений, которые имеют отношение к пользователям. Пользовательские представления системного каталога являются общими для всех пользователей. Для обращения к ним необходимо системное полномочие CREATE SESSION, то есть иметь возможность обращения к Oracle. Имена всех пользовательских представлений начинаются с префикса user.
Информация о себе
Прежде чем приступить к анализу содержимого каталога, вы, возможно, хотели бы узнать, кто вы в базе данных и что вам разрешено делать. В системном каталоге содержится информация обо всех зарегистрированных пользователях, их паролях и многой другой информации. Для получения этой информации имеются описываемые далее два представления. С их помощью можно получить информацию о себе и обо всех тех, кто имеет доступ к базе данных.
Представление USER_USERS как раз предназначено для выдачи информации о текущем пользователе. Среди имеющихся в представлении столбцов наиболее важными являются: имя пользователя (Username), идентификатор пользователя (User_ID), дата регистрации (Created) и состояние учетной записи (Account status). Следующий запрос позволяет получить информацию из всех этих столбцов:
SELECT Username. User_ID, Created, Account-Status
FROM USER_USERS;
В результате вы могли бы получить следующую информацию:
USERNAME USER_ID CREATED ACCOUNT-STATUS
VALERY 55 04.02.06 OPEN
Воспользовавшись символом * во фразе SELECT, вы могли бы получить развернутую информацию о себе.
Представление ALL_USERS дает возможность получить список всех пользователей, которые являются видимыми текущему пользователю. Оно содержит только три столбца: Username, User_ID, Created, имеющих тот же смысл, что и предыдущее представление. Вот что можно получить из системного каталога по этому представлению:
SELECT *
FROM ALL_USERS;
USERNAME
USER_ID CREATED
scon
54 30.08.05
MGMT_VIEW
53 30.08.05
VALERY
55 04.02.06
MDDATA
50 30.08.05
SYSMAN
51 30.08.05
MDSYS
46 30.08.05
SI-INFORMTN-SCHEMA
45 30.08.05
ORDPLUGINS
44 30.08.05
ORDSYS
43 30.08.05
OLAPSYS
47 30.08.05
ANONYMOUS
39 30.08.05
XDB
38 30.08.05
CTXSYS
36 30.08.05
EXFSYS
34 30.08.05
WMSYS
25 30.08.05
DBSNMP
24 30.08.05
TSMSYS
21 30.08.05
DMSYS
35 30.08.05
DIP
19 30.08.05
OUTLN
11 30.08.05
SYSTEM
5 30.08.05
SYS
0 30.08.05
Обратите внимание, что все перечисленные пользователи (за исключением valery) были созданы в процессе установки Oracle.
Свои привилегии
Итак, вы узнали, кто вы такой в системе, и сейчас было бы неплохо узнать, что вы можете делать. Ряд представлений позволяют получить такую информацию.
Представление USER_SYS_PRIVS позволяет получить ваши системные полномочия. Системными являются такие полномочия, которые позволяют выполнять некоторые действия над базой данных в целом, а не по отношению к конкретным объектам базы данных. Это представление содержит столбцы с именем пользователя (Username), названием привилегии (Privilege) и с признаком наличия полномочий по администрированию данной системной привилегией (Admin Option).
SELECT
*
FROM
USER_SYS_PRIVS;
USERNAME PRIVILEGE
ADMIN_OPTION
VALERY
CREATE SEQUENCE
NO
VALERY
CREATE ROLE
NO
VALERY
CREATE TRIGGER
NO
VALERY
CREATE TABLE
NO
VALERY
CREATE USER
NO
VALERY
CREATE SESSION
NO
VALERY
ALTER SESSION
NO
Пользователю VALERY непосредственно предоставлены семь системных полномочий: создавать последовательности, роли, триггеры, таблицы, пользователей, инициировать сеанс связи с Oracle и изменять характеристики своего сеанса работы с Oracle. Обратим внимание на полномочие CREATE SESSION, содержащейся также в стандартной роли CONNECT, которая будет приведена в следующем примере. Значение NO в столбце Admin Option указывает, что пользователь не может администрировать этими привилегиями.
Представление USER ROLE PRIVS предоставляет информацию о тех ролях, которые вам предоставлены в базе данных. Роль создается как пользователь, и затем ей передаются привилегии. После этого роль может быть приписана тому или иному пользователю, который получает все имеющиеся у роли привилегии. Обратим
ваше внимание, что роль может содержать как системные привилегии, так и привилегии на уровне объектов базы данных.
SELECT *
FROM USER_ROLE_PRIVS:
В результате вы можете получить следующий ответ:
USERNAME GRANTED_ROLE ADMIN_OPTION DEFAULT_ROLE OS_GRANTED
VALERY CONNECT NOYESNO
VALERY RESOURCE NOYESNO
Как мы уже отметили, роль CONNECT содержит системное полномочие CREATE SESSION, а также другие полномочия. Вы также можете видеть, что пользователь не имеет прав администрирования этими полномочиями, обе роли назначены как роли по умолчанию (DEFAULT_ROLE/YES) и что эти роли не были переданы из операционной системы (OS_GRANTED/NO).
Доступ к данным
Вы уже знаете, кто вы есть в системе и какие ваши системные полномочия. Теперь вас может заинтересовать, к каким данным вы имеете доступ. Вы можете получить ответ на этот вопрос, просматривая различные пользовательские представления системного каталога. Здесь мы приведем некоторые из них.
Представление USER CATALOG по всей вероятности, является наиболее важным. Оно выводит список таблиц, представлений и некоторых других объектов базы данных, владельцем которых является пользователь, инициировавший этот запрос.
SELECT *
FROM USER_CATALOG;
Результат мог бы выглядеть следующим образом:
TABLE_NAME
TABLEJYPE
DEPARTMENT
TABLE
FACULTY
TABLE
TEACHER
TABLE
SGROUP
TABLE
ROOM
TABLE
SUBJECT
TABLE
LECTURE
TABLE
DEP_POST_STAT
VIEW
DEP ID-SEQ
SEQUENCE
FAC_ID_SEQ
SEQUENCE
Представление ALL CATALOG, в свою очередь, позволяет просмотреть объекты базы данных, владельцами которых являются другие пользователи, но к которым вы также имеете право доступа. Выполните показанный запрос, чтобы получить эту информацию:
SELECT *
FROM ALL CATALOG:
Представление USERJBJECTS предоставляет информацию о тех объектах базы данных, которыми вы владеете, включая информацию об индексах. Например, запрос:
SELECT OBJECTJYPE, OBJECT JAME, CREATED, STATUS
FROM USER_OBJECTS
ORDER BY OBJECTJYPE:
может привести к следующему выводу:
OBJECTJYPE OBJECT JAME
CREATED STATUS
INDEX
FACJRK
04.02.06 VALID
INDEX
FACJNQJAM
04.02.06 VALID
INDEX
LECJNQ3
04.02.06 VALID
INDEX
LECJNQ2
04.02.06 VALID
INDEX
LECJNQ1
04.02.06 VALID
INDEX
SBJJRK
04.02.06 VALID
INDEX
ROM_UNQJUM_BLD
04.02.06 VALID
INDEX
ROMJRK
04.02.06 VALID
INDEX
GRPJNQJUMJARJEP
04.02.06 VALID
INDEX
GRPJRK
04.02.06 VALID
INDEX
TCHJRK
04.02.06 VALID
INDEX
DEPJNQJAMJRK
04.02.06 VALID
INDEX
DEPJRK
04.02.06 VALID
INDEX
FAC_UNQ_DEN
04.02.06 VALID
SEQUENCE
FAC_ID_SEQ
26.02.06 VALID
SEQUENCE
DEPJDJEQ
26.02.06 VALID
TABLE
TEACHER
04.02.06 VALID
TABLE
SGROUP
04.02.06 VALID
TABLE
ROOM
04.02.06 VALID
TABLE
DEPARTMENT
04.02.06 VALID
TABLE
LECTURE
04.02.06 VALID
TABLE
FACULTY
04.02.06 VALID
TABLE
SUBJECT
04.02.06 VALID
TRIGGER
LOGSALUPDATE
26.02.06 INVALID
TYPE
PPRS1
07.02.06 INVALID
VIEW
DEP POST STAT
21.02.06 VALID
Обратите внимание, Oracle автоматически строит индексы по всем столбцам, имеющим ограничения целостности первичного или уникального ключей.
Таблицы, представления и столбцы
Намного больше информации можно получить из представления USERJABLES. Оно предоставляет около 50 характеристик способов хранения и использования таблиц, которыми владеет пользователь. Простейшим примером может быть следующий запрос:
SELECT Table Jame, In1tial_Extent, Status
FROM USERJABLES;*
TABLE JAME INITIAL_EXTENT STATUS
DEPARTMENT FACULTY TEACHER SGROUPDEPARTMENT FACULTY TEACHER SGROUP65536 VALID65536 VALID65536 VALID65536 VALID65536 VALID65536 VALID65536 VALID65536 VALID
DEPARTMENT FACULTY TEACHER SGROUP
DEPARTMENT FACULTY TEACHER SGROUP
65536 VALID
65536 VALID
65536 VALID
65536 VALID
65536 VALID
65536 VALID
65536 VALID
65536 VALID
ROOM65536VALID
SUBJECT65536VALID
LECTURE65536VALID
Здесь вы получили информацию об именах всех используемых пользователем таблицах вместе с размером начальной выделенной памяти под них и состоянием таблиц. Обычно из этого представления наиболее часто пользователями используется только столбец имен таблиц.
Представление ALL_TABLES предоставляет ту же информацию, что и USER_TABLES, но уже относительно всех тех таблиц текущего пользователя, к которым он имеет доступ, а не просто владеет ими (аналогично ALL_CATALOG и USER_CATALOG).
Представление USER_VI EWS позволяет получить информацию о всех представлениях, которыми владеет пользователь. Наиболее интересными столбцами этого представления являются View_Name (имя представления) и Text (текст представления). Вот как может выглядеть запрос к этому представлению:
SELECT V1ew_Name, Text
FROM USER-VIEWS
VIEW-NAME TEXT
DEP_POST_STAT SELECT COALESCE(DepFK, 999) DepNo, Post. COUNT(*). SUM(Salary) . SUM(Rise) FROM TEACHER
GROUP BY COALESCE(DepFK. 999). Post
Представление ALL_VIEWS дает информацию о всех представлениях, к которым имеет доступ пользователь.
Для получения информации о столбцах таблиц, которыми владеет пользователь, следует воспользоваться представлением USER_TAB_COLS. Наиболее важными его столбцами являются следующие:
О TABLE_NAME - имя таблицы;
О COLUMN_NAME — имя столбца;
О DATATYPE — тип данных столбца;
О DATA_LENGTH — длина столбца;
О DATA_PRECISION — точность столбца (количество цифр до десятичной точки);
О DATA SCALE — масштаб числа (количество цифр после десятичной точки);
О NULLABLE — может ли принимать значение NULL;
О DATA_DEFAULT — значение по умолчанию.
Посмотрим, как выглядят столбцы таблицы TEACHER.
SELECT TABLE_NAME AS TNAME. COLUMNJAME AS CNAME.
DATA_TYPE AS TYPE. DATA_LENGTH AS LENGTH.
■DATA_PRECISION AS PREC. DATA_SCALE AS SCAL.
NULLABLE AS N. DATA_DEFAULT AS DEF
FROM USER_TAB_COLS
WHERE TABLE_NAME = 'TEACHER*;
TNAME CNAME TYPE LENGTH PREC SCAL N DEF
TEACHER TCHPK NUMBER 22ON
TEACHER
DEPFK
NUMBER
22
0 Y
TEACHER
NAME
VARCHAR
30
N
TEACHER
IDCODE
CHAR
10
Y
TEACHER
POST
VARCHAR
20
Y
TEACHER
TEL
CHAR
7
Y
TEACHER
SALARY
NUMBER
22
62 Y 0
TEACHER
RISE
NUMBER
22
62 Y 0
TEACHER
HIREDATE
DATE
7
Y
TEACHER
CHIEF
NUMBER
22
0 Y
Для получения информации о столбцах всех таблиц, к которым имеет доступ пользователь, следует воспользоваться представлением ALL_TAB_COLS.
Ограничения целостности
Представление USER_CONSTRAI NTS дает возможность посмотреть ограничения, определенные в таблицах, владельцем которых является пользователь. Перечислим наиболее важные столбцы этого представления.
О CONSTRAINT_NAME — имя ограничения целостности.
О CONSTRAI NT_TYPE - тип ограничения целостности: С - CHECK; Р — первичный ключ; U — уникальный ключ; R — внешний ключ; V — WITH СНЕСК_OPTION для представлений; 0 - WITH READ ONLY для представлений).
О TABLE_NAME — имя таблицы, с которой ассоциируется ограничение.
О SEARCH_CONDITION - текст ограничения CHECK.;
О DELETE_RULE — правило удаления для внешнего ключа.
Посмотрим, как выглядят ограничения CHECK в таблице SGROUP.
CONSTRAINT-NAME
TABLE_NAME
SEARCH-CONDITION
SYS_C005187
SGROUP
"NUM" IS NOT NULL
SYS_C005188
SGROUP
"YEAR" IS NOT NULL
GRP_CHK_YAR
SGROUP
Year IN (1, 2, 3. 4, 5, 6)
GRP CHK-QTY
SGROUP
Quantity BETWEEN 1 AND 50
GRP_CHK_RAT
SGROUP
Rating BETWEEN 0 AND 100
SELECT CONSTRAINT-NAME, TABLE_NAME, SEARCH-CONDITION
FROM USER-CONSTRAINTS
WHERE CONSTRAINTJYPE = 'C AND TABLE-NAME = 'SGROUP';
Представление ALL-CONSTRAINTS дает ту же информацию, но по всем таблицам, к которым имеется доступ у пользователя.
Представление USER_CONS_COLUMNS описывает те столбцы, владельцем которых является пользователь и которые имеют ограничения целостности.
SELECT OWNER, CONSTRAINT-NAME. TABLE_NAME. COLUMN_NAME
FROM USER_CONS_COLUMNS
WHERE TABLE_NAME = 'DEPARTMENT';
OWNER CONSTRAINT-NAME TABLE_NAME COLUMN_NAME
VALERY DEP_FRK_FAC DEPARTMENT FACFK
VALERY DEP_UNQ_NAM_FRK DEPARTMENT FACFK
VALERY DEP UNO NAM FRK DEPARTMENT NAME
VALERY DEP_PRKVALERY DEP_CHK_FNDVALERY SYS-C005172VALERY SYS_C005171VALERY DEP_PRKVALERY DEP_CHK_FNDVALERY SYS-C005172VALERY SYS_C005171DEPARTMENT DEPPKDEPARTMENT FUNDDEPARTMENT NAMEDEPARTMENT FACFKDEPARTMENT DEPPKDEPARTMENT FUNDDEPARTMENT NAMEDEPARTMENT FACFK
VALERY DEP_PRK
VALERY DEP_CHK_FND
VALERY SYS-C005172
VALERY SYS_C005171
VALERY DEP_PRK
VALERY DEP_CHK_FND
VALERY SYS-C005172
VALERY SYS_C005171
DEPARTMENT DEPPK
DEPARTMENT FUND
DEPARTMENT NAME
DEPARTMENT FACFK
DEPARTMENT DEPPK
DEPARTMENT FUND
DEPARTMENT NAME
DEPARTMENT FACFK
Ограничения SYS_C005172 и SYS_C005171 - это ограничения NOT NULL, которые описаны для столбцов NAME и FACFK и которым не было явно присвоено имя. Представление ALL_CONS_COLUMNS содержит ту же информацию, но только по всем тем столбцам, к которым имеет доступ пользователь.
В заключение следует отметить, что по всем объектам базы данных можно получить информацию из системного каталога. Для всех них существуют свои представления.
Подведение итогов
На этом уроке вы научились:
0 пользоваться системным каталогом;
0 получать из системного каталога информацию о себе, о своих привилегиях;
0 получать из системного каталога информацию об имеющихся таблицах, индексах, представлениях, последовательностях и других объектах базы данных;
И получать информацию об ограничениях целостности.
Приложение А
Демонстрационные материалы
В этом приложении описывается база данных, которая используется в большинстве примеров, приведенных в этой книге, а также содержимое документа XML, который используется в уроке 19 для демонстрации работы SQL с XML.
Учебная база данных
База данных построена для приложения, имеющего отношение к расписанию занятий в вузе. Расписание упрощено, оно не содержит многих нюансов, например проведения занятий в подгруппах и потоках, возможности преподавания дисциплины многими преподавателями в течение семестра и другие. Мы специально упростили базу данных, чтобы на простых примерах можно было легко объяснять возможности языка SQL.
Учебная база данных состоит из следующих семи таблиц.
О FACULTY. Содержит информацию о факультетах вуза. Факультет может включать в себя одну или более кафедр.
О DEPARTMENT. Содержит информацию о кафедрах вуза. Каждая кафедра обязательно входит в состав одного факультета и может иметь в своем составе одг ного или более преподавателей, а также одну или более групп.
О TEACHER. Содержит информацию о преподавателях вуза. Каждый преподаватель может работать на одной кафедре, иметь множество лекционных занятий и быть куратором более чем одной группы.
О SGROUP. Содержит информацию о группах. Каждая группа входит в состав одной кафедры и присутствует в расписании занятий. Группа обязательно имеет одного куратора.
О ROOM. Содержит информацию об аудиториях. Аудитории могут использоваться для проведения занятий.
О SUBJECT. Содержит информацию о дисциплинах. Любой из предметов может преподаваться на различных занятиях.
О LECTURE. Содержит информацию о занятиях. Каждое лекционное занятие, помимо собственных атрибутов, связано с одним преподавателем, одной группой, одной аудиторией и одной дисциплиной.
Описанная выше база данных может быть представлена графически, как это показано на рис. АЛ.
Графическое представление структуры базы данных менее подробно, но более наглядно. В этом рисунке мы использовали единственный тип связи, окончания которой обозначают следующее:
О единственная линия указывает, что экземпляр сущности с противоположной стороны связи ассоциируется с одним экземпляром сущности, находящейся возле данного окончания;
О три расходящиеся линии указывают, что экземпляр сущности с противоположной стороны связи ассоциируется со многими экземплярами сущности, находящейся возле данного окончания;
О штриховая линия указывает, что экземпляры располагающейся возле него сущности могут существовать самостоятельно, то есть без каких-либо ассоциаций с экземплярами сущности с противоположной стороны;
О сплошная линия указывает, что экземпляры располагающейся возле него сущности обязательно должны ассоциироваться с экземплярами сущности с противоположной стороны.
В табл. А.1 приводится содержательное описание столбцов таблиц базы данных.
Таблица А.1. Описание столбцов таблиц базы данных
Столбец
Описание
Таблица FACULTY
FacPK
Уникальный идентификатор факультета. Является первичным ключом
Name
Название факультета. Является уникальным в таблице
Dean
Фамилия декана факультета
Building
Корпус, в котором располагается факультет (деканат факультета)
Fund
Фонд финансирования факультета
Таблица DEPARTMENT
DepPK
Уникальный идентификатор кафедры. Является первичным ключом
FacFK
Уникальный идентификатор факультета, которому принадлежит кафедра. Является внешним ключом
Name
Название кафедры. Является уникальным в пределах факультета, но может повторяться в таблице
Head
Фамилия заведующего кафедрой
Building
Корпус, в котором располагается кафедра
Fund
Фонд финансирования кафедры
Таблица TEACHER .
TchPK
Уникальный идентификатор преподавателя. Является первичным ключом
DepFK
Уникальный идентификатор кафедры, на которой работает преподаватель. Является внешним ключом
Name
Фамилия преподавателя
IDCode
Идентификационный код. Является уникальным для преподавателя
Post
Должность
Tel
Телефон
Salary
Ставка
Rise
Надбавка (ставка и надбавка в сумме дает зарплату)
Hi reDate
Дата приема на работу
Chief
Уникальный идентификатор преподавателя, которому подчиняется данный преподаватель. Является внешним ключом
Таблица SGROUP
GrpPK
Уникальный идентификатор группы. Является первичным ключом
DepFK
Уникальный идентификатор кафедры, которой принадлежит группа. Является внешним ключом
Num
Номер группы. Является уникальным на кафедре в пределах курса
Year
Номер курса
Quantity
Количество студентов в группе
Rating
Рейтинг группы
CurFK
Уникальный идентификатор куратора группы. Является внешним ключом
СтолбецОписание
Таблица ROOM
RomPKУникальный идентификатор аудитории. Является первичным ключом
NumНомер аудитории. Является уникальным в пределах корпуса
F1 оогЭтаж, на котором располагается аудитория
BuildingКорпус, в котором располагается аудитория
SeatsКоличество мест в аудитории
Таблица SUBJECT
SbjPK Уникальный идентификатор предмета. Является первичным ключом
NameНазвание предмета. Является уникальным в таблице Таблица LECTURE
TchFK Уникальный идентификатор преподавателя, проводящего занятие.
Является внешним ключом
GrpFK Уникальный идентификатор группы, для которой проводится занятие. Является внешним ключом
SbjFK Уникальный идентификатор предмета, по которому проводится занятие. Является внешним ключом
RomFK Уникальный идентификатор аудитории, в которой проводится занятие. Является внешним ключом
Туре Тип занятия (лекция, лабораторная, семинар и т. д.)
Week Неделя, в которою проводится занятие. Предполагается, что расписание занятий в четную и нечетную недели может различаться
DayДень недели
LessonПорядковый номер занятия в течение дня
Сделаем ряд замечаний относительно приведенного выше описания. Согласно реляционной модели данных каждая таблица должна иметь столбец или совокупность столбцов, которые уникально идентифицируют строки таблицы. Например, совокупность названия кафедры и факультета уникально идентифицируют кафедры в вузе, Номер аудитории вместе с номером корпуса уникально идентифицируют аудиторию и т. д. Такие столбцы выполняют роль первичных ключей таблиц. Однако в большинстве случаев использовать такие столбцы в качестве первичных ключей не целесообразно. Это объясняется следующими факторами.
Во-первых, желательно, чтобы первичные ключи никогда не изменяли своих значений на период существования соответствующих им строк. Однако если в качестве первичных ключей выбираются столбцы, имеющие семантическую нагрузку, то возможно изменение значений первичных ключей. Могут меняться правила нумерации аудиторий и корпусов, названия кафедр и факультетов и т. д.
Во-вторых, желательно, чтобы первичные ключи были минимальными по размеру. Это объясняется тем, что они используются для ссылок на них с помощью внешних ключей из других таблиц. Представьте себе, что первичный ключ таблицы состоит из трех, четырех или более столбцов и на эту таблицу имеются ссылки
из многих других таблиц. При этом становится тяжело управлять такими ссылками и, более того, будет неэффективно использоваться память. В связи с этим вполне оправданно будет искусственное введение в таблицу одного специального столбца, который играет роль первичного ключа. Такими искусственными столбцами в учебной базе данных являются те, которые имеют название вида хххРК (FacPK, DepPK и т. д.). В реальной предметной области такие атрибуты отсутствуют. Таблица LECTURE не содержит первичного ключа, так как в нашем случае нет необходимости его объявлять явно. Дело в том, что на эту таблицу нет ссылок из других таблиц. Однако среди определенных для таблицы столбцов имеется несколько их групп, которые выполняют роль уникальных идентификаторов по сути. Например, в роли первичных ключей могут выступать следующие группы столбцов:
О TchFK, Week, Day, Lesson — в одно и то же время преподаватель не может вести несколько занятий;
О GrpFK, Week, Day, Lesson — в одно и то же время группа не может находиться на нескольких занятиях;
О RomFK, Week, Day, Lesson — в одно и то же время в аудитории не может проводиться несколько занятий.
Этот факт отражен в определении таблиц приданием этим совокупностям столбцов ограничений UNIQUE и NOT NULL.
Ниже приводится текст SQL для создания описанных выше таблиц с помощью предложений CREATE TABLE.
CREATE TABLE FACULTY
(FacPK INTEGER
CONSTRAINT fac_prk PRIMARY KEY, NOT NULL CONSTRAINT fac_unq_nam UNIQUE, CONSTRAINT fac_unq_den UNIQUE,
CONSTRAINT fac_chk_fnd CHECK (Fund > 0)):
Name VARCHAROO)
Dean VARCHAROO)
Building CHAR(5),
Fund NUMBER(7, 2)
CREATE TABLE DEPARTMENT (DepPKINTEGER
FacFKINTEGER
CONSTRAINT dep_prk PRIMARY KEY.
NOT NULL CONSTRAINT dep_frk_fac REFERENCES FACULTY(FacPK)
NameVARCHAROO)
HeadVARCHAROO).
Building CHAR(5).
FundNUMBER(7. 2)
ON DELETE CASCADE, NOT NULL,
CONSTRAINT dep_chk_fnd CHECK (Fund > 0).
CONSTRAINT dep_unq_nam_frk UNIQUE (Name, FacFK));
CREATE TABLE TEACHER
(TchPK
INTEGER
CONSTRAINT tch_prk PRIMARY KEY,
DepFK
INTEGER
CONSTRAINT tch frk dep REFERENCES DEPARTMENT(DepPK),
Name
VARCHAROO)
NOT NULL.
IDCode
CHAR(IO),
Post
VARCHAROO)
CONSTRAINT tch_chk_pst CHECK
(Post IN ('профессор'. 'доцент', 'преподаватель', 'ассистент'))
Tel
CHAR(7),
Salary
NUMBER(6. 2)
DEFAULT 0 CONSTRAINT tch_chk_sal CHECK (Salary >= 0).
Rise
NUMBERO, 2)
DEFAULT 0 CONSTRAINT tch_chk_ris CHECK (Rise >= 0).
Hi reDate
DATE
CONSTRAINT tch_chk_hdt CHECK
(Hiredate >= TO DATE('01.01.1990*, 'DD.MM.YYYY')).
Chief INTEGER CONSTRAINT tch_frk_tch REFERENCES TEACHER(TchPK).
CONSTRAINT tch_chk_sal_risl CHECK (2 * Rise <= Salary),
CONSTRAINT tch_chk_sal_ris2 CHECK (Salary + Rise < 4000)):
CREATE TABLE SGROUP
(GrpPKINTEGERCONSTRAINTgrp_prk PRIMARY KEY,
DepFK INTEGER CONSTRAINT grp_frk_dep REFERENCES DEPARTMENT(DepPK).
NumNUMBER(3)NOT NULL,
YearNUMBER(l)NOT NULL CONSTRAINT grp_chk_yarCHECK(YearIN(1,2.3. 4. 5)),
Quantity NUMBER(2)CONSTRAINTgrp_chk_qty CHECK (QuantityBETWEEN1AND 50).
Rating NUMBER(3) DEFAULT 0 CONSTRAINT grp_chk_rat CHECK (Rating BETWEEN 0 AND 100), CurFK INTEGER CONSTRAINT grp_frk_tch REFERENCES TEACHER(TchPK), CONSTRAINT grp_unq_num_yar_dep UNIQUE (Num, Year, DepFK));
CREATE TABLE ROOM
(RomPKINTEGER CONSTRAINT rom_prk PRIMARY KEY,
NumNUMBER(3) NOT NULL,
Floor NUMBER(2) CONSTRAINT rom_chk_flr CHECK (Floor BETWEEN 1 AND 16),
Building CHAR(5) NOT NULL,
Seats NUMBER(3) CONSTRAINT rom_chk_set CHECK (Seats BETWEEN 1 AND 300), CONSTRAINT rom_unq_num_bld UNIQUE (Num, Building));
CREATE TABLE SUBJECT
(SbjPKINTEGERCONSTRAINT sbj_prk PRIMARY KEY,
NameVARCHAR(50) NOT NULL UNIQUE);
CREATE TABLE LECTURE
NOT NULL CONSTRAINT lec_frk_tch REFERENCES TEACHER(TchPK) ON DELETE SET NULL,
NOT NULL CONSTRAINT lec_frk_grp REFERENCES SGROUP(GrpPK)
ON DELETE CASCADE.~
(TchFK
GrpFK
INTEGER
INTEGER
SbjFK
INTEGER
NOT NULL CONSTRAINT lecjrk_sbj REFERENCES SUBJECT(SbjPK) ON DELETE SET NULL..
RomFK
INTEGER
NOT NULL CONSTRAINT lec_frk_rom REFERENCES ROOM(RomPK)
ON DELETE SET NULL.
Type
VARCHAR(15)
NOT NULL CONSTRAINT lec_chk_typ CHECK (Type IN ('лекц', 'лаб*, 'сем*, 'практ')).
Week
NUMBER(l)
NOT NULL CONSTRAINT lec_chk_wek CHECK (Week = 1 OR Week = 2)
Day
CHAR(3)
NOT NULL CONSTRAINT lec_chk_day CHECK
(Day IN ('пнд'. *втр*, 'срд', 'чтв', "птн". 'суб*, 'вое')).
Lesson
NUMBER(l)
CONSTRAINT lec_chk_les CHECK (Lesson BETWEEN 1 AND 8).
CONSTRAINT lec_unql UNIQUE (TchFK, Week, Day. Lesson). CONSTRAINT lec_unq2 UNIQUE (GrpFK. Week, Day. Lesson), CONSTRAINT lec_unq3 UNIQUE (RomFK. Week. Day. lesson));
Далее мы приводим содержимое учебной базы данных. Почти все запросы, указанные в книге, выполнялись именно над этими данными, и их полное перечисление поможет вам проанализировать путь получения результатов.
Таблица FACULTY
FACPK
NAME
DEAN
BUILDING
FUND
1
информатика
Сидоров
6
25000
2
кибернетика
Петров
5
27000
3
математика
Игнатов
3
23000
Таблица DEPARTMENT
DEPPK,
FACFK
NAME
HEAD
BUILDING
FUND
1
1
базы данных
Соколов
6
26000
2
1
программирование
Федоров
6
12000
3
1
интернет
Стрельцов
3
10000
4
2
теория языков
Глущенко
3
10000
5
2
лингвистика
Коробов
3
14100
6
2
базы данных
Тараненко
5
27000
Таблица TEACHER
TCHPK
DEPFK
NAME
IDCODE
POST
TEL
SALARY
RISE
HIREDATE
CHIEF
16
2
Сидоров
0123456789
профессор
1070
470
01.09.1992
4
2
Рамишевский
4567890123
доцент
4567890
830
370
09.09.1998
16
2
2
Хоренко
1234567890
преподаватель
670
230
10.10.2001
4
1
2
Вибровский
2345678901
ассистент
570
170
01.09.2003
2
3
2
Воропаев
ассистент
570
150
02.09.2002
4
5
2
Кузинцев
5678901234
преподаватель
4567890
630
270
01.01.1991
4
6
2
Завратинский
3456789012
доцент
770
341
01.02.1996
16
8
2
Козлутин
6789012345
ассистент
1234567
530
220
04.07.2001
6
7
2
Лекарь
3456789012
доцент
1234567
890
440
03.06.1991
16
9
2
Мартынов
7890123456
ассистент
1234567
530
220
22.10.2002
5
10
2
Резван
профессор
1234567
1100
470
11.11.2000
16
11
2
Недередеев
преподаватель
1234567
570
230
22.07.1999
7
13
Ахромеев
профессор
2345678
1050
500
05.05.1998
14
Наумов
доцент
2345678
770
350
01.09.1994
15
Дараганов
преподаватель
3456789
570
250
07.11.1998
Таблица SGROUP
GRPPK
DEPFK
NUM
YEAR
QUANTITY
RATING
CURFK
1
2
505
5
27
67
7
2
2
504
5
31
55
6
3
1
307
3
33
48
5
4
1
408
4
27
56
5
5
3
201
2
35
43
Таблица ROOM
ROMPK
NUM
FLOOR
BUILDING
SEATS
1
311
3
6
17
2
201
2
6
80
3
201
2
5
60
4
202
2
4
70
5
225
2
7
95
6
104
1
6
25
7
110
1
6
40
Таблица SUBJECT
SBJPK
NAME
1
операционные системы
2
проектирование компьютеров
3
базы данных
4
охрана труда
5
теория алгоритмов
6
нейрокомпьютеры
7
теория права
Таблица LECTURE
TCHFK
GRPFK
SBJFK
ROMFK
TYPE
WEEK
DAY
LESSON
1
1
1
1
лаб
1
пнд
1
2
1
1
2
лекц
1
пнд
2
3
1
2
1
лаб
1
втр
3
4
1
2
2
лекц
1
втр
4
5
1
3
2
лекц
1
срд
3
6
1
4
3
лекц
1
срд
4
7
1
5
4
лекц
1
НТВ
2
8
1
4
5
практ
1
НТВ
3
9
1
3
1
лаб
1
НТВ
4
10
1
6
2
лекц
1
птн
1
11
1
5
6
лаб
1
птн
4
2
1
1
2
лекц
2
пнд
2
15
1
7
2
лекц
2
пнд
3
11
1
5
1
лаб
2
втр
2
5
1
3
2
лекц
2
втр
3
4
1
2
2
лекц
2
втр
4
1
1
1
6
лаб
2
срд
2
9
1
3
1
лаб
2
срд
3
15
1
7
7
лаб
2
НТВ
1
7
1
5
2
лекц
2
чтв
2
10
1
6
2
лекц
2
птн
1
3
1
2
1
лаб
2
птн
3
Документ XML
Далее приводится документ XML, который используется для демонстрации возможностей взаимодействия SQL и XML.
<PurchaseOrder
xmlns:xsi=
xsi: noNamespaceSchemaLocati" on=
"http://1ocalhost:8080/source/schemas/poSource/xsd/ purchaseOrder.xsd">
<Reference>SBELL-2002100912333601PDT</Reference>
<Actions>
<Action>
<User>SVOLLMAN</User>
</Action>
</Actions>
<Reject/>
<Requestor>Sarah J. Bell</Requestor>
<User>SBELL</User>
<CostCenter>S30</CostCenter>
<Sh1ppingInstruct1ons>
<name>Sarah J. Bell</name>
<address>400 Oracle Parkway
Redwood Shores
CA
94065
USA</address>
<telephone>650 506 7400</telephone>
</Shippinglnstructions>
<Special Instruct!ons>Air Mai 1</Speci al Instruct!ons>
<LineItems>
<LineItem ItemNumber=,,l,,>
<Description>A Night to Remember</Description>
<Part Id=”715515009058" UnitPrice=,,39.95M Quant ity-"2’7>
</LineItem>
<L1neItem ItemNumber="2">
<Description>The Unbearable Lightness Of Being
</Description>
<Part Id="37429140222" UnitPrice=”29.95" Quantity=”2’7>
</L1neItem>
<LineItem ItemNumber=,,3">
<Descri pti on>Si sters</Descri pti on>
<Part Id="715515011020" UnitPrice=,,29.95” Quantity="4’7>
</LineItem>
</LineItems>
</PurchaseOrder>
Приложение Б Инструментальное средство SQL* Plus
В этом приложении мы кратко опишем то инструментальное средство Oracle, которое использовалось в этом учебнике для демонстрации запросов SQL. Мы опишем его в объеме, достаточном для того, чтобы вы смогли самостоятельно выполнить имеющиеся в книге запросы.
Запуск SQL* Plus
Для запуска SQL*Plus необходимо иметь зарегистрированные имя и пароль, которые используются для подключения к схеме базы данных Oracle и определяют ваши полномочия. Для получения имени и пароля обратитесь к администратору Oracle. Он также предоставит вам необходимые полномочия. Для работы с базой данных в рамках учебного пособия вам необходимы полномочия на создание сеанса связи с Oracle (по сути говоря, это полномочие на вход в Oracle), а также на создание таблиц. Кроме того, вы должны узнать у администратора имя базы данных, в которой вам разрешено работать.
После запуска SQL*Plus открывается окно, в котором нужно указать назначенные имя, пароль, а также имя базы данных (рис. Б.1).
Рис. БД. Окно входа в SQL*Plus
После установления связи с Oracle программа SQL*Plus выводит свое главное окно, в котором происходит вся дальнейшая работа (рис. Б.2). Внизу окна вы видите приглашение SQL>, свидетельствующее о том, что SQL*Plus находится в ожидании ввода очередной команды. Для выхода из SQL*Plus следует ввести команду EXIT или QUIT; также можно выбрать команду Выход в меню Файл.
>^ i^u?.- П^К»^ <VW <ЛР«КО>^ i^u?.- П^К»^ <VW <ЛР«КО
>^ i^u?.- П^К»^ <VW <ЛР«КО
>^ i^u?.- П^К»^ <VW <ЛР«КО
hSQL*Plus: Release 16.2.0.1.0 - Production on Вт Фев 28 10:31:07 2006 g
^Copyright (c) 1982, 2005, Oracle. All rights reserved.
^Присоединен к:
^Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
^With the Partitioning, OLAP and Data Mining options
;SQL>
Рис. Б.2. Главное окно SQL*Plus
Ввод и выполнение команд
Для выполнения команды следует ввести ее в строке приглашения и нажать клавишу Enter. Имеется три вида команд:
О команды SQL для работы с базой данных;
О команды PL/SQL для работы с базой данных;
О команды для настройки SQL*Plus, форматирования результатов выполнения запросов, редактирования и сохранения команд SQL.
Команды PL/SQL далее мы описывать не будем. Команды SQL*Plus, как и команды SQL, не чувствительны к регистру текста. Способы использования для ввода команд дополнительных строк, завершения и выполнения команды зависят о типа выполняемой команды.
Буфер SQL
Последняя введенная команда SQL (но не команда SQL*Plus) сохраняется в буфере. Просмотреть содержимое буфера можно с помощью команды LIST (команда SQL*Plus). Способы редактирования содержимого буфера кратко описаны ниже. Команду, находящуюся в буфере, можно выполнить с использованием команды RUN или введя символ /. Команда RUN перед выполнением команды буфера выводит ее на экран, а команда / выполняет команду буфера без ее вывода на экран.
Ввод и выполнение команд SQL
Команду SQL можно ввести в нескольких строках. После приглашения SQL*Plus введите первую строку команды SQL, например:
SQL> SELECT Name. Dean
и нажмите клавишу Enter. SQL*Plus выведет приглашение 2, указывающее на необходимость ввода следующей строки команды SQL. Введете, например, следующую строку:
FROM FACULTY'
и снова нажмите клавишу Enter. Появится приглашение 3, свидетельствующее о необходимости ввода третьей строки команды. Так будет продолжаться до тех пор, пока вы не завершите очередную строку символом ;, который указывает за завершение ввода команды:
WHERE FacPK = 1;
SQL*Plus передаст сформулированный запрос Oracle и затем выведет полученный от Oracle результат:
NAME DEAN
информатика Сидоров
строка выбрана.
После вывода результирующей таблицы и указания количества найденных строк (последнее мы в книге опускали) SQL*Plus выведет приглашение для ввода следующей команды. Если вы сделали ошибку и получили сообщение об этом, введите исправленную команду.
Заголовок результирующей таблицы в выводе может повторяться. Это зависит от значения переменной SQL*Plus PAGESIZE, которая указывает размер выводимой страницы. Строка результирующей таблицы может быть выведена в нескольких экранных строках, если она не помещается по ширине. В этом случае следует воспользоваться переменной LINESIZE, с помощью которой устанавливается ширина страницы в символах. Будет ли выводиться сообщение, указывающее количество найденных строк, зависит от установки переменной FEEDBACK.
Вы можете разделять вводимую команду на отдельные строки, используя следующее единственное правило: при переносе нельзя разделять отдельные слова команды. Так, например, приведенная выше команда SQL может быть введена следующим образом:
SQL> SELECT Name
. Dean FROM
FACULTY WHERE
FacPK =
1;
Мы рекомендуем вам разделять команды SQL таким образом, чтобы на каждой строке располагалась одна фраза SQL. Завершение ввода команды SQL указывается несколькими способами.
О Символ ; — в этом случае SQL*Plus запускает введенную команду на выполнение и запоминает ее в буфере. Точка с запятой вводится в конце последней строки команды. Если до ввода ; вы нажали клавишу Enter, SQL*Plus выведет приглашение для ввода следующей строки команды. Введите ; в этот момент и нажмите клавишу Enter.
О Символ / — этот символ также указывает завершение ввода команды и необходимость ее выполнения. Помните, что он должен вводиться в отдельной строке. Помимо выполнения, команда запоминается в буфере.
О Пустая строка. После завершения ввода команды нажмите клавишу Enter. При выводе приглашения для очередной строки команды, нажмите клавишу Enter еще раз. SQL*Plus запомнит команду в буфере, но не запустит ее на выполнение. При запоминании в буфере очередной команды, она заменяет предыдущую.
Ввод и выполнение команд SQL*Plus
SQL*Plus имеет собственные команды для манипулирования командами SQL, настройки своих переменных и форматирования выводимых результатов. Команды SQL*Plus имеют собственный синтаксис. Они не должны завершаться точкой с запятой — после ввода команды для ее выполнения следует лишь нажать клавишу Enter. Длинные команды SQL*Plus можно вводить в нескольких строках — для это в конце строки введите символ - и нажмите клавишу Enter. На возможность ввода очередной строки команды SQL*Plus указывает приглашение >, например:
SQL> COLUMN SALARY FORMAT $99,999 -
> HEADING 'MONTHLY SALARY'
Так как SQL*Plus рассматривает символ - в конце строки как продолжение, он игнорируется и при вводе предложения SQL.
Создание и выполнение скриптов
Вы можете создать отдельный текстовый файл, который будет содержать команды SQL и SQL*Plus, и затем выполнить их как единое целое. Такой подход оказывается особенно полезным в том случае, когда следует выполнить большое количество сложных команд или одну и ту же команду многократно. Такой файл называется скриптом. Скрипт можно формировать любым текстовым редактором. При создании скрипта для его выполнения SQL*Plus можно использовать те же синтаксические правила написания команд SQL и SQL*Plus, что и в самом SQL*Plus.
После создания скрипта выполнить его можно командой START. Эта команда имеет один параметр, который указывает путь и имя файла скрипта. Если файл скрипта имеет расширение .sql, его в команде START можно не указывать. Например:
START D:\SQL_Manual\myscript.txt
Скрипты могут вкладываться друг в друга — для этого команду START необходимо указать в самом скрипте. Например, для последовательного выполнения нескольких ранее созданных скриптов можно создать новый скрипт с командами START, запускающими на выполнение необходимые скрипты.
Работа с буфером SQL
Как правило, команды SQL формируются в отдельных файлах скриптов и запускаются из них. Тем не менее, SQL*Plus предоставляет ряд команд для работы с буфером, которые предоставляют возможность отредактировать содержащуюся
в нем команду SQL и запустить ее на выполнение. Все команды работы с буфером, за исключением команд LIST и DELETE, воздействуют только на одну строку в буфере, которая называется текущей строкой. Далее мы рассмотрим те команды, которые наиболее часто используются.
Вывод содержимого буфера
Команда LIST выводит содержимое буфера на экран. Введем следующее предложение SQL:
SQL> SELECT Dean, Name-
FROM FACULTY
WHERE FacPK - 3:
DEAN NAME
Игнатов математика
строка выбрана.
SQL*Plus выполнит запрос и одновременно сохранит его в буфере. Убедимся в этом с помощью команды LIST:
SQL> LIST
SELECT Dean, Name
FROM FACULTY
* WHERE FacPK = 3
^ПРИМЕЧАНИЕ Большинство команд SQL*Plus можно вводить в сокращенном виде. Например, команду LIST можно ввести как 1.
Каждая выведенная строка имеет номер. Номера строк в буфере важны, так как они позволяют ссылаться на конкретные строки. Обратите внимание на звездочку после номера в строке 3 — она указывает текущую строку.
Можно вывести и конкретную строку буфера, указав в команде 1 номер строки:
SQL> 12
* FROM FACULTY
Редактирование текущей строки
Чтобы указать любую строку буфера как текущую, следует использовать команду LIST с указанием номера строки. Кроме того, при выводе сообщения об ошибке текущей становится строка, в которой ошибка обнаружена.
Отредактировать текущую строку буфера позволяет команда CHANGE. Она имеет следующий синтаксис:
CEHANGE] /старая_строка[/новая_строка]
Первый параметр указывает, что именно в текущей строке нужно заменить, второй — на что. В примере синтаксиса в качестве разделителя используется косая черта, однако можно воспользоваться любым символом, не являющимся буквой или цифрой — главное, чтобы он не встречался в строках обоих параметров.
Регистр для символов первого параметра несущественен. Приведем пример использования этой команды. Например, вы решили выполнить следующий запрос.
SQL> SELECT Name. Dean
FROM DEPARTMENT
WHERE DepPK = 1;
SELECT Name. Dean * ошибка в строке 1: 0RA-OO9O4: "DEAN": недопустимый идентификатор
Сообщение свидетельствует, что в первой строке обнаружена ошибка, которая становится текущей. Звездочка под строкой указывает место обнаружения ошибки. Действительно, в таблице DEPARTMENT указанного столбца нет. Заменим его на Head. После выполнения команды измененная строка будет выведена.
SQL> CHANGE /dean/Head 1* SELECT Name, Head
Теперь можно запустить этот запрос на выполнение командой RUN (после ее выполнения текущей становится последняя введенная строка):
SQL> RUN
SELECT Name, Head
FROM DEPARTMENT
* WHERE DepPK = 1
NAME HEAD
базы данных Соколов
1 строка выбрана.
Покажем, как можно изменить этот запрос, чтобы был выведен фонд финансирования кафедры под номером 3.
SQL> CHANGE /1/3 3* WHERE DepPK = 3
SQL> LIST 1
1* SELECT Name, Head
SQL> CHANGE /Name. Head/Fund
1* SELECT Fund
SQL> RUN
SELECT Fund
FROM DEPARTMENT
* WHERE DepPK = 3
FUND
10000
строка выбрана.
Сначала мы сделали необходимую замену в третьей строке, затем с помощью команды LIST сделали текущей первую строку и также сделали в ней замену и, наконец, запустили на выполнение отредактированный запрос.
Команда CHANGE имеет сокращенный вариант - С. Второй параметр может отсутствовать. В этом случае в текущей строке удаляется та подстрока, которая указана первым параметром. Приведем пример:
SQL> 1 3
3* WHERE DepPK - 3
SQL> c /dep
3* WHERE PK = 3
SQL> c /pk/DepPK
3* WHERE DepPK - 3
Добавление текста к текущей строке
Команда APPEND добавляет указанный в ее параметре текст в конец текущей строки. Ее синтаксис следующий:
AEPPEND] текст
Для отделения пробелом присоединяемого текста от текста в текущей строке вставьте между командой и текстом два пробела. Если вставляемый текст должен завершаться символом :, расположите подряд эти два символа. Сокращенной формой команды APPEND является А.
Приведем пример. Сначала выведем содержимое буфера:
SQL> LIST
SELECT Fund
FROM DEPARTMENT
3* WHERE DepPK - 3
Изменим запрос таким образом, чтобы для кафедр 3 и 1 выводились названия и их фонды. Для этого следует добавить соответствующие тексты в первую и третью строки буфера:
SQL> A OR DepPK = 1
3* WHERE DepPK = 3 OR DepPK = 1
SQL> A . Name
* SELECT Fund, Name
SQL> RUN'
SELECT Fund. Name
FROM DEPARTMENT
* WHERE DepPK » 3 OR DepPK - 1
FUND NAME
26000 базы данных
10000 интернет
строк выбрано.
Вставка новых строк
Для вставки одной или более новых строк после текущей используйте команду INPUT. Ее синтаксис следующий:
IENPUT] [текст]
Для вставки одной строки введите ее текст вслед за командой INPUT, отделяя текст от команды пробелом. Для вставки двух или более строк введите команду INPUT и нажмите клавишу Enter. Появится приглашение команды INPUT на ввод строки. Введите ее и снова нажмите клавишу Enter. Для завершения ввода строк нажмите клавишу Enter после очередного приглашения. Приведем пример. Выведем содержимое буфера:
SQL> LIST
SELECT Fund. Name
FROM DEPARTMENT
3* WHERE DepPK = 3 OR DepPK = 1
Добавим после третьей строки (которая является текущей) фразу упорядочения результата по столбцу Fund и выполним обновленный запрос:
SQL> INPUT ORDER BY Fund
SQL> RUN
SELECT Fund. Name
FROM DEPARTMENT
WHERE DepPK = 3 OR DepPK = 1
* ORDER BY Fund
FUND NAME
10000 интернет
26000 базы данных
строк выбрано.
Удаление строк
Команда DEL используется для удаления строк из буфера. Она имеет несколько разновидностей параметров, наиболее используемыми являются следующие:
* или отсутствие параметра — удаление текущей строки;
LAST — удаление последней строки;
On — удаление n-й строки;
Опт — удаление строк с п по т.
Приведем пример. Посмотрим, что имеется в буфере:
SQL> LIST
SELECT Fund. Name
FROM DEPARTMENT
WHERE DepPK = 3 OR DepPK = 1
4* ORDER BY Fund
Удалим текущую строку (то есть четвертую), а затем вторую и посмотрим, что осталось:
SQL> DEL
SQL> DEL 2
SQL> LIST
SELECT Fund. Name
2* WHERE DepPK - 3 OR DepPK - 1
Форматирование результатов выполнения запросов
SQL*Plus предоставляет ряд возможностей по форматированию результатов выполнения запросов при их выводе на экран и сохранении в файлах. Некоторые из них рассматриваются в следующих разделах.
Изменение заголовков столбцов
SQL*Plus при выводе столбцов указывает их заголовки. По умолчанию заголовок соответствует названию столбца в таблице, выражению, формирующему столбец, или псевдониму, который приписан столбцу во фразе запроса AS. SQL*Plus предоставляет возможность изменить заголовок с помощью фразы HEADING команды COLUMN, имеющей следующий формат:
COLUMN имя_столбца HEADING заголовок_столбца
Рассмотрим пример:
SQL> COLUMN Name HEADING 'Фамилия преподавателя'
SQL> COLUMN Salary HEADING 'Зарплата за месяц'
SQL> SELECT Name, Salary
FROM TEACHER
WHERE LOWER(Post) - 'преподаватель';
Фамилия преподавателя Зарплата за месяц
Хоренко670
Кузинцев630
Недеведеев570
Дараганов570
строк выбрано.
Если заголовок состоит из двух или более слов, его следует заключать в одинарные или двойные кавычки. Для расположения заголовка в двух или более строках нужно воспользоваться символом | в тех местах заголовка, где следует перейти на новую строку. Приведем пример:
SQL> COLUMN Name HEADING 'Фамилия|преподавателя'
SQL> COLUMN Salary HEADING 'Зарплата,за месяц'
SQL> /
Фамилия Зарплата
преподавателя за месяц
Хоренко670
Кузинцев630
Недеведеев570
Дараганов570
строк выбрано.
Обратите внимание, что после двух команд COLUMN мы ввели команду /. Напомним — она, как и команда RUN, инициирует выполнение запроса, находящегося в буфере.
С помощью команды SET UNDERLINE можнс/изменить символ, который используется для подчеркивания заголовков. Приведем пример:
SQL> SET UNDERLINE =
SQL> SELECT Name, Salary FROM TEACHER WHERE Post = 'доцент1;
Фамилия Зарплата преподавателя за месяц
Рамишевский830
Завратинский770
Лекарь890
Наумов770
4 строк выбрано.
Вернем прежний символ подчеркивания заголовков:
SQL> SET UNDERLINE ’-*
Обратите внимание, что символ - заключен в одинарные кавычки. Иначе он будет воспринят SQL*Plus как признак перехода команды на другую строку.
Форматирование числовых столбцов
SQL*Plus использует встроенные правила форматирования значений столбцов всех типов, которые можно менять с помощью команды COLUMN. В этом разделе мы рассмотрим изменение форматирования числовых столбцов.
Форматирование столбца производится с использованием фразы FORMAT:
COLUMN имя_столбца FORMAT формат
Элемент формат предоставляет большие возможности по форматированию чисел, основные из которых приведены табл. Б.1.
SQL> COLUMN Name HEADING 'Фамилия(преподавателя*
SQL> COLUMN Salary HEADING ’Ставка]в месяц* FORMAT 9999.99
SQL> COLUMN Rise HEADING ‘Надбавка,за стаж' FORMAT 9999.99
SQL> COLUMN Total_Salary HEADING ’Зарплата* FORMAT 99,999.99
SQL> SELECT Name, Salary, Rise, Salary + Rise AS Total_Salary
FROM TEACHER
WHERE Salary * Rise > 1500;
Фамилия Ставка Надбавка
преподавателя в месяц за стаж Зарплата
Сидоров1070.00470.001,540.00
Резван1100.00470.001,570.00
Ахромеев1050.00500.001.550.00
3 строк выбрано.
Таблица Б.1. Основные элементы указания формата
ЭлементПримерОписание
99999Вывод цифры
,9.999Вывод запятойв указанном месте
Элемент
Пример
Описание
99.99
Указание расположения десятичной точки
0
0999
Вывод нулей в начале
0
9990
Вывод нулей в конце
Ширина числового столбца равна ширине его заголовка или ширине, определенной фразой FORMAT команды COLUMN, плюс один символ. Если фраза FORMAT не используется, ширину столбца можно указать с помощью переменной SQL*Plus под названием NUMWIDTH (ее значение устанавливается командой SET). Если число не помещается в отведенное для него место, дробная часть числа округляется. Если не помещается и целая часть — вместо значения числа выводятся символы -. По умолчанию числа выравниваются по правому краю отведенного для них места.
Форматирование текстовых столбцов
SQL*Plus использует для форматирования значений текстовых столбцов встроенные правила. В частности, по умолчанию ширина текстового столбца равна его ширине в базе данных; значения текстовых столбцов выводятся с выравниванием влево. Для изменения ширины текстового столбца во фразе FORMAT команды COLUMN необходимо указать Ап, где п — ширина столбца в символах. Приведем пример:
SQL> COLUMN Name FORMAT A5
SQL> /
Фамил Ставка Надбавка
препо в месяц за стаж Зарплата
Сидор 1070.00 470.00 1.540.00 ов
Резва 1100.00 470.00 1.570.00 н
Ахром 1050.00 500.00 1.550.00 еев
3 строк выбрано.
Обратите внимание, что заголовок столбца фамилий усекается, а значения фамилий переносятся. Если заголовок не помещаются по ширине столбца, он всегда усекается. Значения столбцов, которые не помещаются по ширине столбца, переносятся или усекаются в зависимости от переменной SQL*Plus под названием WRAP (ее значение устанавливается командой SET). Если переменная WRAP равна ON (установлено по умолчанию), значения всех текстовых столбцов переносятся на следующие строки, если же она установлена в OFF, значения усекаются, что показано в следующем примере:
SQL> SET WRAP OFF
SQL> /
Фамил Ставка Надбавка
препо в месяц за стаж Зарплата
Сидор 1070.00470.00 1.540.00
Резва 1100.00 470.00 1.570.00
Ахром 1050.00 500.00 1,550.00
3 строк выбрано.
Если необходимо указать перенос или усечения конкретного столбца, следует использовать команду COLUMN с указанием имени столбца и ключевыми словами WRAPPED (с переносом), WORD_WRAPPED (с переносом по словам) или TRUNCATED (с усечением). Приведем пример:
SQL> COLUMN Name WRAPPED
SQL> COLUMN Post FORMAT A5
SQL> SELECT Name, Post FROM Teacher WHERE TchPK = 1;
Фамил
прело POST
Вибро ассис вский
строка выбрана.
Здесь фамилия выведена в двух строках, так как мы явно указали, что фамилии следует выводить с переносом, а должность усечена, так как переменная WRAP имеет значение OFF.
ПРИМ ЕЧ АН И ЕСтолбцы таблиц базы данных, имеющие тип даты, выводятся как тек
стовые строки, и к ним применимы все правила форматирования текста.
Просмотр, приостановка и отмена форматирования
Чтобы посмотреть настройку форматирования столбца, используйте команду:
COLUMN имя_столбца
Например:
SQL> COLUMN Name
COLUMN Name ON
HEADING 'Фамилия|преподавателя* headsep *|'
FORMAT A5
WRAP
Чтобы приостановить определенное вами форматирование столбца, используйте следующую команду:
COLUMN имя_столбца OFF
При этом будет использоваться форматирование по умолчанию. Однако определенное вами форматирование не удаляется, его действие может быть восстановлено такой командой:
COLUMN имя_столбца ON
Для восстановления форматирования столбца по умолчанию с удалением определенного вами форматирования воспользуйтесь следующей командой:
COLUMN имя столбца CLEAR
Переменные SQL*Plus
Как уже упоминалось, SQL*Plus имеет собственные переменные, значения которых на период текущего сеанса работы с SQL*Plus можно устанавливать с помощью команды SET. Приведем переменные, которые представляют особый интерес. О FEEDBACK — после вывода результата запроса дополнительно может выводиться строка такого вида: 7 строк выбрано.
Переменная FEEDBACK позволяет включать и отключать вывод этой строки, атакже указывать, при выводе какого количества строк это сообщение должно появляться. Используйте следующий синтаксис:
SET FEEDEBACK] {n | ON | OFF)
где п — количество строк, при котором сообщение выводится, ON активирует, a OFF деактивирует вывод этой строки.
О ECHO — указывает, следует ли выводить на экран текст скрипта при его запуске командой START:
SET ECHO {ON | OFF}
Переменная ECHO не влияет на вывод результатов интерактивных команд.
О HEADING — включает и отключает вывод заголовков столбцов: SET HEAEDING] {ON | OFF}
О LINESIZE — устанавливает ширину в символах выводимых на экран строк: SET LINEESIZE] число
Увеличение ширины позволяет избежать нежелательного вывода одной строки данных в нескольких экранных строках.
О PAGESIZE — указывает размер страницы вывода данных:
SET PAGESEIZE] число
После вывода указанного количества строк инициируется вывод новой страницы, на которой, в частности, повторяются заголовки столбцов.
О TIME — выводит текущее время как часть приглашения SQL>: SET TIEME] {OFF | ON}
Формат вывода времени определяется установками Oracle и базовой операционной системы. Например:
SQL> SET TIME ON 17:44:07 SQL>
О NULL — устанавливает способ представления значения NULL: SET NULL текст
По умолчанию значения NULL представляются пустой строкой.
Мы привели всего несколько переменных рабочей среды SQL*Plus. Список всех переменных вместе с их текущими установками можно получить командой SHOW ALL. Наконец, значения всех переменных можно установить в диалоговом окне, открываемом командой меню Опции/Конфигурация.
Алфавитный указатель
(+), оператор, 77, 78
(т), оператор, 58
(т,), оператор, 58
(m,n), оператор, 58
*, оператор, 26, 58
—, комментарий, 30
-, оператор, 26
.., оператор, 298
/*, комментарий, 29
/, оператор, 26
?, оператор, 58
|, оператор, 58
||, оператор, 26, 332
+, оператор, 26, 58
<, оператор, 27
<■*, оператор, 27
<>, оператор, 27, 336
=, оператор, 27, 336
>, оператор, 27
>=, оператор, 27
>, оператор, 345
А
ALL, оператор, 27, 155
взаимозаменяемость с NOT IN, 158
взаимозаменяемость с SOME, 159
—замена на EXISTS, 156
замена на агрегатную функцию, 159
— использование равенства
и неравенства, 157
при отсутствии данных, 160
ALTER DOMAIN, предложение, 207
ALTER SEQUENCE, предложение, 218
ALTER TABLE, предложение, 209, 232
—добавление столбцов, 210
изменение определения столбцов, 210
— переименование таблицы, 212
удаление столбцов, 211
AND, оператор, 27, 44
ANY, оператор, 27, 153
ANY, функция, 93
AVG, функция, 90
В
BEGIN END, раздел, 295
BETWEEN, оператор, 27, 51
С
CARDINALITY, функция, 331
CASE, выражение, 161
CHECK, ограничение, 230
CLOSE, предложение, 286, 288
COALESCE, функция, 163
COLLECT, функция, 336
COMMIT, предложение, 309
CONNECT BY, фраза, 190
условие на глубину иерархии, 192
CONSTRAINT, фраза, 221
COUNT, функция, 87
CREATE ASSERTION, предложение, 233
CREATE CAST, предложение, 347
CREATE CHARACTER SET, предложение, 21
CREATE COLLATION, предложение, 21
CREATE DOMAIN, предложение, 206
CREATE INDEX, предложение, 214
CREATE ROLE, предложение, 273
CREATE SEQUENCE, предложение, 216
CREATE TABLE, предложение, 205
значение по умолчанию, 207
определение доменов, 206
определение столбцов, 205
CREATE TRANSLATION, предложение, 21
CREATE TRIGGER, предложение, 316
CREATE USER, предложение, 272
CREATE VIEW, предложение, 256
CROSS JOIN, оператор, 81
CURRVAL, функция, 217
D
DECLARE CURSOR, предложение, 284
DECLARE, раздел, 286, 293
DEFAULT, ключевое слово, 248
DEFFERABLE, фраза, 231
DELETE, предложение, 251
позиционное удаление, 286
удаление всех строк, 251
удаление запросом, 253
—удаление одной строки, 252
удаление по условию, 252
DEREF, оператор, 345
DISTINCT FROM, оператор, 27
DROP ASSERTION, предложение, 234
DROP DOMAIN, предложение, 207
DROP INDEX, предложение, 215
DROP SEQUENCE, предложение, 218
DROP TABLE, предложение, 212
DROP TRIGGER, предложение, 320
DROP USER, предложение, 273
DROP VIEW, предложение, 262
E
ELEMENT, оператор, 335
EVERY, функция, 93
EXCEPTION, раздел, 299
EXISTS, оператор, 27, 145
агрегатные функции в подзапросе, 149
в HAVING, 152
замена на COUNT, 150
замена на соединение, 150
комбинирование с соединением, 147
с коррелированными подзапросами, 146
с простыми подзапросами, 145
F
FALSE, значение, 27
FETCH, предложение, 285, 287
FOREIGN KEY, ограничение, 227
и неопределенные значения, 228
FREE LOCATOR, предложение, 329
FROM, фраза, 39
запрос в качестве имени таблицы, 39
переопределение имени таблицы, 39
FULL JOIN, оператор, 83
FULL OUTER JOIN, оператор, 83
FUSSION, функция, 336
G
GRANT, предложение, 274
GROUP BY CUBE, фраза, 199
GROUP BY GROUPING SET, фраза, 201
GROUP BY ROLLUP, фраза, 198
GROUP BY, фраза
вложение агрегатных функций, ИЗ
группировка по выражениям
над столбцами, 112
группировка по нескольким
столбцам, 111
—группировка по одному столбцу, 110
группировка строк, 109
-при NULL, 114
GROUPING, функция, 200
Н
HAVING, фраза
-без GROUP BY, 117
уникальность условия на группе, 115
условие отбора групп, 114
HOLD LOCATOR, предложение, 329
I
IF, предложение, 296
IN, оператор, 27, 48
INITIALLY DEFERRED, фраза, 232
INITIALLY IMMEDIATE, фраза, 232
INNER JOIN, оператор, 82
INSERT, предложение, 235, 302
вставка запросом, 240
вставка значений по умолчанию, 241
вставка строк, 236
INTERSECT, оператор, 175
замена другими операторами, 175
INTERSECTION, функция, 336
INTO, фраза, 302
IS A SET, оператор, 27, 337
IS DOCUMENT, оператор, 371
IS NORMALIZED, оператор, 27
IS NOT NULL, оператор, 59
IS NULL, оператор, 27, 59
IS OF, оператор, 27, 345
J
JOIN, оператор, 81, 82
L
LEFT JOIN, оператор, 83
LEFT OUTER JOIN, оператор, 83
LEVEL, псевдостолбец, 190
LIKE, оператор, 27, 54
LOOP, предложение, 288, 297
LOWER, функция, 42
M•
MATCH, оператор, 27
MATCH, фраза, 228
MAX, функция, 91
MEMBER, оператор, 27, 336
MERGE, предложение, 248
MIN, функция, 91
MINUS, оператор, 176
замена на NOT IN, 177
N
NATURAL JOIN, оператор, 81
NEXTVAL, функция, 217
NOT BETWEEN, оператор, 51
NOT IN, оператор, 48
NOT LIKE, оператор, 54
NOT SIMILAR TO, оператор, 57
NOT NULL, значение, 182
в GROUP BY, 114
в арифметических выражениях, 182
в логических связках, 184
в операторах сравнения, 183
в функциях, 184
использование замены на определенное значение, 164
при выводе на экран и печать, 185
при сортировке, 185
функции обработки, 185
NOT NULL, ограничение, 221
NOT, оператор, 27, 46
NULLIF, функция, 164
О
OPEN, предложение, 285, 287
OR, оператор, 27, 45
ORDER BY, фраза, 285
направление сортировки, 121
определение упорядоченности символов, 124
сортировка значения NULL, 121
сортировка и группировка, 123
сортировка по выражению над столбцами, .119
сортировка по нескольким столбцам, 123
сортировка по столбцу, 118
сортировка по столбцу, отсутствующему в результате, 119
сортировка результирующих строк, 118
указание порядкового номера столбца, 120
указание синонима столбца сортировки, 121
ORDER SIBLINGS BY, фраза, 194
OVERLAPS, оператор, 27
Р
PRIMARY KEY, ограничение, 224
R
READ ONLY, фраза, 285
REFERENCES, фраза, 227
RIGHT JOIN, оператор, 83
RIGHT OUTER JOIN, оператор, 83
ROLLBACK, предложение, 310
S
SAVEPOINT, предложение, 311
SELECT, предложение, 31
SELECT, фраза, 33
включение текста в результат запроса, 37
вывод всех столбцов, 34
вывод определенных столбцов, 33
вычисляемые выражения, 36
—исключение повторяющихся строк, 34
использование подзапроса, 139
переопределение имени столбца, 36
уточнение имени, 34
SET CONSTRAINTS, предложение, 232, 314
SET TRANSACTION, предложение, 313
SET, оператор, 335
SET, фраза, 246
SIMILAR ТО, оператор, 27, 57
SOME, оператор, 27, 153
—замена на IN и EXISTS, 153
замена на агрегатную функцию, 154
при отсутствии данных, 160
SOME, функция, 93
START TRANSACTION, предложение, 307
START WITH, фраза, 190
использование подзапроса, 194
STDDEV_POP, функция, 92
STDDEV_SAMP, функция, 92
SUBMULTISET, оператор, 27, 337
SUM, функция, 89
т
TO_DATE, функция, 24
TOP N, анализ, 202
TRANSLATE, функция, 22
TRUE, значение, 27
и
UNION, оператор, 38,169
внешнее объединение, 171
вывод дубликатов строк, 173
замена на OR, 174
идентификация строк, 170
полное внешнее объединение, 173
простое объединение, 170
UNIQUE, ограничение, 222
и неопределенные значения, 224
столбца, 223
таблицы, 223
UNIQUE ALL, оператор, 28
UNIQUE DISTINCT, оператор, 28
UNIQUE, оператор, 27
UNKNOWN, значение, 27, 184
UNNEST, оператор, 332, 335
UPDATE, предложение, 242, 302
использование DEFAULT, 248
использование NULL, 248
обновление нескольких таблиц, 247
обновление по условию, 243
обновление таблицы, 242
подзапрос в SET, 246
подзапрос в WHERE, 244
позиционное обновление, 286
UPDATE, фраза, 285
UPPER, функция, 42
V
VAR POP, функция, 92
VAR_SAMP, функция, 92
W
WHERE, фраза
выражения над столбцами, 47
использование простейших условий, 41
логические операторы, 44
операторы сравнения, 42
WITH, фраза
определение повторяющихся подзапросов, 195
рекурсивное выполнение запросов, 196
X
XML
базы данных, 349, 353
высокая степень детализации, 352
на основе двумерных файлов, 352
на основе других баз данных, 354
низкая степень детализации, 352
ориентированные на модель, 354
ориентированные на текст, 354
—документ, 350
ввод, 371
выбор, 372
обновление, 374
отображение между SQL и XML, 355
—значений SQL, 358
идентификаторов SQL, 356
набора символов, 355
—определений таблиц SQL, 360
таблиц SQL, 358
типов данных, 356
функции и предикаты, 361
XMLAgg, функция, 366
XMLAttributes, функция, 364
XMLComment, функция, 368
XMLConcat, функция, 366
XMLElement, функция, 362
XMLForest, функция, 365
XMLParse, функция, 369
XMLPi, функция, 369
XMLRoot, функция, 368
XMLSerialize, функция, 370
А
алиас, 37
аргумент, 25
В
выражение, 28
порядок вычисления, 29
регулярное, 57
скалярное, 28
Г
граф, 185
группировка
по всем измерениям, 199
по наборам измерений, 201
—упорядоченная, 198
д
дерево, 185, 186
домен, 206
3
зависимость по существованию, 226
запрос, 31
вложенный, 126
рекурсивный, 185
в Oracle, 188
в стандарте SQL, 195
самосоединяющийся, 72, 187
составной, 168
строковый, 331
табличный, 331
защита данных, 270
И
именование объектов, 29
индекс, 213
определение, 214
—порядок сортировки, 215
правила использования, 215
—составной, 214
удаление, 215
—уникальный, 214
инкапсуляция, 341
К
ключ
внешний, 62, 226
первичный, 62, 224
— ссылочный, 226
—уникальный, 223
ключевое слово, 19
команда, 19
комментарий, 29
константа, 23курсор, 283атрибут, 289закрытие, 288открытие, 285перемещение, 285прокручиваемость, 284сохраняемость, 284чувствительность, 284Ллитералвремени, 24временного промежутка, 25временной отметки, 25—даты, 24—двоичной строки, 24логический, 25приблизительный числовой, 24точный числовой, 24локатор, 329Мметод, 340изменения, 341наблюдения, 341оригинальный, 340подменяемый, 340предметный параметр, 340многомерный анализ данных, 196множественные операции, 168использование группировки, 178использование сортировки, 178порядок выполнения, 179Оограничение целостности, 220виды, 220процедурное, 304столбца, 221таблицы, 221операнд, 25оператор, 25арифметический, 26константа, 23курсор, 283атрибут, 289закрытие, 288открытие, 285перемещение, 285прокручиваемость, 284сохраняемость, 284чувствительность, 284Ллитералвремени, 24временного промежутка, 25временной отметки, 25—даты, 24—двоичной строки, 24логический, 25приблизительный числовой, 24точный числовой, 24локатор, 329Мметод, 340изменения, 341наблюдения, 341оригинальный, 340подменяемый, 340предметный параметр, 340многомерный анализ данных, 196множественные операции, 168использование группировки, 178использование сортировки, 178порядок выполнения, 179Оограничение целостности, 220виды, 220процедурное, 304столбца, 221таблицы, 221операнд, 25оператор, 25арифметический, 26
константа, 23
курсор, 283
атрибут, 289
закрытие, 288
открытие, 285
перемещение, 285
прокручиваемость, 284
сохраняемость, 284
чувствительность, 284
Л
литерал
времени, 24
временного промежутка, 25
временной отметки, 25
—даты, 24
—двоичной строки, 24
логический, 25
приблизительный числовой, 24
точный числовой, 24
локатор, 329
М
метод, 340
изменения, 341
наблюдения, 341
оригинальный, 340
подменяемый, 340
предметный параметр, 340
многомерный анализ данных, 196
множественные операции, 168
использование группировки, 178
использование сортировки, 178
порядок выполнения, 179
О
ограничение целостности, 220
виды, 220
процедурное, 304
столбца, 221
таблицы, 221
операнд, 25
оператор, 25
арифметический, 26
константа, 23
курсор, 283
атрибут, 289
закрытие, 288
открытие, 285
перемещение, 285
прокручиваемость, 284
сохраняемость, 284
чувствительность, 284
Л
литерал
времени, 24
временного промежутка, 25
временной отметки, 25
—даты, 24
—двоичной строки, 24
логический, 25
приблизительный числовой, 24
точный числовой, 24
локатор, 329
М
метод, 340
изменения, 341
наблюдения, 341
оригинальный, 340
подменяемый, 340
предметный параметр, 340
многомерный анализ данных, 196
множественные операции, 168
использование группировки, 178
использование сортировки, 178
порядок выполнения, 179
О
ограничение целостности, 220
виды, 220
процедурное, 304
столбца, 221
таблицы, 221
операнд, 25
оператор, 25
арифметический, 26
оператор (продолжение)
— логический, 27
— множественный, 28
— специальный, 27
сравнения, 27
старшинство, 29
— строковый, 26
п
подзапрос, 126
-в FROM, 142
-в HAVING, 141
-в SELECT, 139
вложение с использованием IN, 130
вложение с использованием операторов сравнения, 127
возврат пустого множества, 132
замена подзапроса соединением, 137
использование одной таблицы, 128
коррелированный в WHERE, 133
многоуровневая вложенность, 136
обратимость предикатов
с подзапросами, 129
простой, 127
-простой в WHERE, 127
связанный, 133
табличный, 132
последовательность, 216
генератор, 216
изменение, 218
удаление, 218
предикат, 41
над множествами, 164
предложение, 19
условное, 296
цикла, 297
представление, 256, 267
агрегированное, 259
вертикальное, 258
горизонтальное, 257
защита данных, 280
многотабличное, 261
модификация данных, 263
переименование столбцов, 259
ссылкаперекрестная, 229рекурсивная, 228ссылочная целостность, 225поддержка, 229Ттаблицабазовая, 256виртуальная, 256временная, 208дочерняя, 62, 226изменение определения, 209—исходная, 33, 256на основе другой, 208промежуточная, 39результирующая, 32родительская, 62, 226создание, 205типизированная, 340удаление, 212тип данных, 22базовый, 291большой объект, 327встроенный, 330иерархия типов, 341индивидуальный, 338исходный, 338коллекция, 330— размер, 331— элемент, 331конструктор, 330массив, 331— идентичность, 331— конкатенация, 332— определение, 332— подмассив, 331мультимножество, 334— идентичность, 334операции, 335подмультимножество, 334предикаты, 336— подтип, 291ссылкаперекрестная, 229рекурсивная, 228ссылочная целостность, 225поддержка, 229Ттаблицабазовая, 256виртуальная, 256временная, 208дочерняя, 62, 226изменение определения, 209—исходная, 33, 256на основе другой, 208промежуточная, 39результирующая, 32родительская, 62, 226создание, 205типизированная, 340удаление, 212тип данных, 22базовый, 291большой объект, 327встроенный, 330иерархия типов, 341индивидуальный, 338исходный, 338коллекция, 330— размер, 331— элемент, 331конструктор, 330массив, 331— идентичность, 331— конкатенация, 332— определение, 332— подмассив, 331мультимножество, 334— идентичность, 334операции, 335подмультимножество, 334предикаты, 336— подтип, 291
ссылка
перекрестная, 229
рекурсивная, 228
ссылочная целостность, 225
поддержка, 229
Т
таблица
базовая, 256
виртуальная, 256
временная, 208
дочерняя, 62, 226
изменение определения, 209
—исходная, 33, 256
на основе другой, 208
промежуточная, 39
результирующая, 32
родительская, 62, 226
создание, 205
типизированная, 340
удаление, 212
тип данных, 22
базовый, 291
большой объект, 327
встроенный, 330
иерархия типов, 341
индивидуальный, 338
исходный, 338
коллекция, 330
— размер, 331
— элемент, 331
конструктор, 330
массив, 331
— идентичность, 331
— конкатенация, 332
— определение, 332
— подмассив, 331
мультимножество, 334
— идентичность, 334
операции, 335
подмультимножество, 334
предикаты, 336
— подтип, 291
ссылка
перекрестная, 229
рекурсивная, 228
ссылочная целостность, 225
поддержка, 229
Т
таблица
базовая, 256
виртуальная, 256
временная, 208
дочерняя, 62, 226
изменение определения, 209
—исходная, 33, 256
на основе другой, 208
промежуточная, 39
результирующая, 32
родительская, 62, 226
создание, 205
типизированная, 340
удаление, 212
тип данных, 22
базовый, 291
большой объект, 327
встроенный, 330
иерархия типов, 341
индивидуальный, 338
исходный, 338
коллекция, 330
— размер, 331
— элемент, 331
конструктор, 330
массив, 331
— идентичность, 331
— конкатенация, 332
— определение, 332
— подмассив, 331
мультимножество, 334
— идентичность, 334
операции, 335
подмультимножество, 334
предикаты, 336
— подтип, 291
представление (продолжение)
поддержка целостности, 267
простое, 256
смешанное, 258
создание, 256
удаление, 262
псевдоним, 37
Р
роль, 273
С
синоним
обязательный, 72
столбца, 37
таблицы, 39, 66
синтаксис, 19
системный каталог, 376
в Oracle, 378
в стандарте SQL, 377
информационная схема, 378
информация о доступе к данным, 381
информация о привилегиях, 380
информация о себе, 379
информация о таблицах, представлениях и столбцах, 382
информация об ограничениях целостности, 384
схема определения, 377
скрипт, 398
словарь данных, 376
соединение таблиц, 62
больше двух, 67
внешнее, 76, 83
внутреннее, 82
декартово произведение, 62
естественное, 81
перекрестное, 81
по неравенству, 71
по равенству, 64
самосоединение, 72
симметричное, 73
условие, 64
уточненное, 81
таблица (продолжение)
поле, 330
пользовательский, 330, 337
сравнение значений, 345
приведение типов, 347
ссылочный, 343
выводимый из атрибута, 344
область видимости, 344
переход по ссылке, 345
пользовательский, 343
системный, 343
строка, 330
структурный, 339
атрибут, 339
манипулирование экземплярами, 343
создание экземпляра, 342
транзакция, 306
блокировка, 314
завершение, 308
и ограничения целостности, 313
контрольная точка, 311
откат, 310
способ доступа, 307
—уровень изоляции, 307
—установка характеристик, 313
явное инициирование, 307
триггер, 315
в Oracle, 321
—действие, 320
—заголовок, 316
—замещающий, 321
и транзакции, 323
использование, 324
момент инициирования, 316
объект, 317
переменная перехода, 318
постобработки, 316
предобработки, 316
рекурсивный, 324
событие, 317
триггер (продолжение)
ссылочные имена, 317
таблица переходов, 317
удаление, 320
уровень, 318
условие, 320
У
утверждение, 233
ф
фраза, 19
функция
агрегатная, 86
использование выражения, 94
статистическая, 92
класс, 86
одной строки, 86, 95
временная, 101
преобразования, 104
строковая, 95
числовая, 100
числовая над строками, 99
— тип, 86
Я
язык
-PL/SQL, 283, 289
-QUEL, 16
-SEQUEL, 15
-SQL, 15
—встроенный, 18, 283
интерактивный, 18, 283
процедурный, 283
стандарты, 16
-SQL/PSM, 283
XML, 349
запросов (ЯЗ), 17, 31
— манипулирования данными (ЯМД), 17, 235
определения данных (ЯОД), 17, 205
Филипп Андон, Валерий Резниченко
Язык запросов SQL. Учебный курс
О. Кравницкая О. Кравницкая О. ЗаплаткинаЛ. Аду вескаяО. Кравницкая О. Кравницкая О. ЗаплаткинаЛ. Аду вескаяРедактор
О. Кравницкая О. Кравницкая О. Заплаткина
Л. Аду веская
О. Кравницкая О. Кравницкая О. Заплаткина
Л. Аду веская
Руководитель проекта Технический редактор Художник
Подписано в печать 13.04.06. Формат70X100/16. Уст. п. л. 33,54. Тираж 3000 экз. Заказ№ 1123.
ООО «Питер Пресс», 198206, Санкт-Петербург, Петергофское шоссе, д. 73, лит. А29.
ООО «Издательская группа ВН V»
Свидетельство о занесении в Государственный реестрсерия ДК № 175 от 13.09.2000
Налоговая льгота — общероссийский классификатор продукции ОК 005-93, том 2; 953005 — литература учебнаяОтпечатано с готовых диапозитивов в ФГУП «Печатный двор» им. А. М. Горького Федерального агентствапо печати и массовым коммуникациям.
197110, Санкт-Петербург, Чкаловский пр., 15.
АНТИВИРУС
ИГОРЯ ДАНИЛОВА
www.drweb.ruни Innin пип
Филипп Андон, Валерий Резниченко
язык запросов SQLязык запросов SQLУЧЕБНЫЙ КУРС .УЧЕБНЫЙ КУРС .
язык запросов SQL
язык запросов SQL
УЧЕБНЫЙ КУРС .
УЧЕБНЫЙ КУРС .
Книга посвящена SQL — языку, являющемуся основным средством взаимодействия пользователей с базами данных. В современных СУБД этот язык является главенствующим, и умение составлять SQL-запросы является абсолютно необходимым для всех, кто имеет дело с разработкой и использованием баз данных, а также с анализом данных.
Описываются как широко известные средства SQL, так и новые возможности, в частности:
инструменты объектно-ориентированного программирования;
интеграция с XML;
аналитическая обработка данных;
рекурсивные запросы.
Тема: SQL/базы данных
Уровень пользователя: начинающий/опытный
СОЛИТЕР у®!.
Заказ книг:
197198, Санкт-Петербург, а/я 619; тел.: (812)103-73-74, postbook@piter.com
61093, Харьков-93, а/я 9130; тел.: (057)712-27-05, piter@tender.kharkov.ua
Посетите веб-сайты издательств: www.bhv.kiev.ua и www.piter.com
УЧЕБНЫЙ КУРСУЧЕБНЫЙ КУРС:ode5:ode5Создание и модификацияv баз данных, таблиц‘ \ и представленийСоздание и модификацияv баз данных, таблиц‘ \ и представленийЕй ^ ^£ '^ /£ sis 1 % V 1 ^Ей ^ ^£ '^ /£ sis 1 % V 1 ^Процедурный SQLПроцедурный SQL«»«ч/ ^В f о£«»«ч/ ^В f о£^гман^* ^‘1^гман^* ^‘1Администрирование • баз данных средствами SQLАдминистрирование • баз данных средствами SQL(У»(У»СОЛИТЕРСОЛИТЕР
УЧЕБНЫЙ КУРС
УЧЕБНЫЙ КУРС
:ode5
:ode5
Создание и модификацияv баз данных, таблиц‘ \ и представлений
Создание и модификацияv баз данных, таблиц‘ \ и представлений
Ей ^ ^
£ '^ /
£ sis 1 % V 1 ^
Ей ^ ^
£ '^ /
£ sis 1 % V 1 ^
Процедурный SQL
Процедурный SQL
«»«
ч/ ^В f о£
«»«
ч/ ^В f о£
^гман^* ^‘
1
^гман^* ^‘
1
Администрирование • баз данных средствами SQL
Администрирование • баз данных средствами SQL
(У»
(У»
СОЛИТЕР
СОЛИТЕР
Филипп Андон, Валерий Резниченко
ЯЗЫК ЗАПРОСОВ
SQL
Филипп АндонВалерий Резниченко
ЯЗЫК ЗАПРОСОВ
УЧЕБНЫЙ КУРС
(§Ьу
^ПИТЕР*
Москва • Санкт-Петербург • Нижний Новгород • ВоронежНовосибирск ■ Ростов-на-Дону ■ Екатеринбург ■ СамараКиев • Харьков • Минск
2006
ББК 32.973-018.1я7
УДК 004.43(075)
К90
Андон Ф., Резниченко В.
К90 Язык запросов SQL Учебный курс. — СПб.: Питер; Киев: Издательская группа BHV, 2006. — 416 с.: ил.
ISBN 5-469-00394-9
ISBN 996-552-192-6
Книга ориентирована прежде всего на начинающего пользователя, желающего всерьез заняться базами данных. Основу материала составляет изучение примеров готовых баз данных. Подробно рассматриваются приемы конструирования запросов: от самых простых до вложенных со множественными сравнениями. Описываются дополнительные возможности SQL (поддержка целостности данных, транзакции, безопасность данных, привилегии), что дает возможность читателю познакомиться с администрированием баз данных. Тем, кто изучает SQL на профессиональном уровне, будет полезна информация о спецификации и стандартах этого языка. Глава, посвященная применению SQL в различных средах программирования, поможет понять принцип взаимодействия разрабатываемого приложения и СУБД, а также определиться в выборе протокола взаимодействия прикладной программы с базой данных.
Книга может служить как учебным пособием по курсу «Базы данных», так и руководством для тех, кто желает освоить SQL самостоятельно.
ББК 32.973-018.1я7
УДК 004.43(075)
Все права защищены. Никакая часть данной книги не может быть воспроизведена в какой бы то ни было форме без письменного разрешения владельцев авторских прав.
Информация, содержащаяся в данной книге, получена из источников, рассматриваемых издательством как надежные. Тем не менее, имея в виду возможные человеческие или технические ошибки, издательство не может гарантировать абсолютную точность и полноту приводимых сведений и не несет ответственности за возможные ошибки, связанные с использованием книги.
ISBN 5-469-00394-9ISBN 996-552-192-6ISBN 5-469-00394-9ISBN 996-552-192-6© ЗАО Издательский дом «Питер», 2006
ISBN 5-469-00394-9
ISBN 996-552-192-6
ISBN 5-469-00394-9
ISBN 996-552-192-6
© Издательская группа BHV, Киев, 2006
Краткое содержание
Введение13
Урок 1. Введение в SQL15
Урок 2. Простейшие запросы31
Урок 3. Отбор строк по условию41
Урок 4. Многотабличные запросы62
Урок 5. Использование функций86
Урок 6. Группировка и сортировка109
Урок 7. Вложенные запросы126
Урок 8. Дополнительные операторы и выражения145
Урок 9. Множественные операции над таблицами168
Урок 10. Развитые возможности SQL182
Урок 11. Определение таблиц205
Урок 12. Определение ограничений целостности220
Урок 13. Манипулирование данными235
Урок 14. Представления256
Урок 15. Защита данных270
Урок 16. Процедурный SQL283
Урок 17. Транзакции и триггеры304
Урок 18. Объектно-ориентированный SQL326
Урок19. SQL/XML349
Урок 20. Системный каталог376
Приложение А. Демонстрационные материалы386
Приложение Б. Инструментальное средство SQL*PLus395
Алфавитный указатель408
Введение13
Урок 1. Введение в SQL15
Краткая история развития SQL15
Деятельность по стандартизации SQL16
Возможности SQL17
Основы SQL18
Основные синтаксические правила18
Ключевые слова, фразы и предложения19
Правила описания синтаксиса19
Поддержка наборов символов20
Типы данных SQL22
Литералы23
Операторы и выражения25
Именование объектовё29
Комментарии 29
Подведение итогов30
Урок 2. Простейшие запросы31
О предложении SELECT31
Основные фразы — SELECT и FROM33
Фраза SELECT — указание выводимых данных33
Указание выводимых столбцов33
Исключение повторяющихся строк34
Использование вычисляемых выражений36
Переопределение имен результирующих столбцов36
Включение текста в результат запроса37
Фраза FROM — указание используемых таблиц39
Синонимы таблиц39
Запрос в качестве имени таблицы39
Самостоятельная работа40
Подведение итогов40
Урок 3. Отбор строк по условию41
Использование простейших условий41
Операторы сравнения42
Логические операторы44
Использование выражений над столбцами47
Использование специальных операторов48
Проверка на принадлежность множеству48
Проверка на принадлежность диапазону значений51
Проверка на соответствие шаблону54
Проверка на соответствие регулярному выражению57
Проверка на неопределенное значение59
Самостоятельная работа60
Подведение итогов61
Урок 4. Многотабличные запросы62
Декартово произведение таблиц62
Условие соединения64
Соединение таблиц по равенству64
Вывод столбцов разных таблиц64
Вывод столбцов с условием отбора65
Запросы по трем и более таблицам67
Другие виды соединений по равенству70
Соединение таблиц по неравенству71
Самосоединение таблицы72
Внешнее соединение таблиц76
Внешнее соединение и условие отбора78
Внешнее соединение трех и более таблиц80
Соединения с использованием фразы FROM 81
Внутреннее соединение(82
Внешнее соединение83
Соединение трех и более таблиц84
Самостоятельная работа85
Подведение итогов85
Урок 5. Использование функций86
Агрегатные функции86
Функция COUNT87
Функция SUM89
Функция AVG90
Функции MIN и МАХ91
Функции VAR_POP, STDDEV_POP, VAR_SAMP, STDDEV_SAMP92
Функции EVERY, ANY, SOME 93
Выражения с использованием агрегатных функций94
Отсутствующие и неопределенные значения в агрегатных функциях94
Однострочные функции95
Строковые функции95
Числовые функции над строками99
Числовые функции над числами100
Временные функции101
Функции преобразованияЮ4
Самостоятельная работа Ю8
Подведение итогов108
Урок 6. Группировка и сортировка109
Запросы с группировкой строк109
Группировка по одному столбцу110
Группировка по нескольким столбцам111
Использование выражений112
Вложение агрегатных функций113
Значение NULL в столбцах группировки114
Условие отбора групп114
Уникальность условия отбора115
Использование столбцов группировки во фразеHAVING116
Фраза HAVING без фразы GROUP BY117
Сортировка результирующих строк 118
Сортировка по столбцу или выражению118
Направление сортировки121
Сортировка значения NULL121
Сортировка по нескольким столбцам....123
Сортировка и группировка123
Определение упорядоченности символов124
Самостоятельная работа124
Подведение итогов125
Урок 7. Вложенные запросы126
Подзапросы во фразе WHERE127
Простые подзапросы127
Коррелированные подзапросы-.133
Многоуровневая вложенность запросов136
Замена вложенного запроса соединением137
Простые и коррелированные подзапросы во фразе SELECT139
Простые и коррелированные подзапросы во фразе HAVING141
Простые подзапросы во фразе FROM142
Самостоятельная работа144
Подведение итогов 144
Урок 8. Дополнительные операторы и выражения145
Использование оператора EXISTS145
Оператор EXISTS с простыми подзапросами145
Оператор EXISTS с коррелированными подзапросами146
Комбинирование оператора EXISTS с соединением147
Использование оператора NOT EXISTS148
Оператор EXISTS и агрегатные функции149
Замена оператора EXISTS функцией COUNT или соединением таблиц150
Использование оператора EXISTS во фразе HAVING152
Использование операторов ANY, SOME и ALL152
Операторы ANY и SOME153
Оператор ALL155
Операторы SOME и ALL при отсутствии данных160
Выражения и функции выбора вариантов161
Выражение CASE161
Функция COALESCE163
Функция NULLIF164
Выражение предикатов надмножествами164
Самостоятельная работа166
Подведение итогов167
Урок 9. Множественные операции над таблицами168
Множественные операции в стандарте SQL168
Объединение таблиц169
Простое объединение170
Идентификация строк170
Внешнее объединение171
Объединение с сохранением дублирования173
Замена оператора UNION оператором OR174
Пересечение таблиц175
Замена оператора INTERSECT оператором IN175
Разность таблиц176
Замена оператора MINUS оператором NOT IN177
Дополнительные аспекты использования множественных операций177
Множественные операции и группировка178
Множественные операции и сортировка178
Порядок выполнения множественных операций179
Критерии использования множественных операций179
Самостоятельная работа180
Подведение итогов181
Урок 10. Развитые возможности SQL182
Использование неопределенных значений182
Рекурсивное вычисление запросов185
Древовидные структуры185
Представление деревьев и манипулирование ими186
Рекурсивные запросы в Oracle188
Рекурсивные запросы в стандарте SQL195
Многомерный анализ данных196
Упорядоченная группировка198
Группировка по всем комбинациям измерений199
Группировка по наборам измерений201
Анализ «ТОР N»202
Самостоятельная работа204
Подведение итогов204
Урок 11. Определение таблиц205
Создание таблицы205
Определение столбцов205
Определение и использование доменов206
Значения по умолчанию207
Определение временной таблицы208
Определение таблицы на основе существующей208
Изменение определения таблицы209
Добавление столбца210
Изменение определения столбца210
Удаление столбца211
Переименование таблицы212
Удаление таблицы212
Определение и использование индексов^213
Определение и удаление индекса•214
Правила использования индексов215
Последовательности216
Генератор последовательности216
Использование последовательности217
Изменение и удаление генератора последовательности218
Самостоятельная работа218
Подведение итогов219
Урок 12. Определение ограничений целостности220
Виды ограничений целостности220
Ограничение на отсутствие значения221
Ограничение уникальности222
Уникальность как ограничение столбца223
Уникальность как ограничение таблицы223
Уникальность и неопределенные значения224
Ограничение первичного ключа224
Простой первичный ключ225
Составной первичный ключ225
Ограничение ссылочной целостности225
Внешний ключ и ссылочная целостность226
Простой внешний ключ227
Составной внешний ключ227
Рекурсивные и перекрестные ссылки228
Поддержка ссылочной целостности229
Ограничение на значение■ 230
Определение множества допустимых значений231
Задание условия на нескольких столбцах231
Отложенная проверка ограничений231
Изменение ограничений целостности232
Добавление новых ограничений232
Удаление существующих ограничений233
Утверждения233
Самостоятельная работа234
Подведение итогов234
Урок 13. Манипулирование данными235
Добавление новых строк235
Вставка отдельных строк236
Использование запроса при вставке строк240
Вставка значений по умолчанию241
Обновление существующих данных242
Обновление всех строк242
Обновление по условию243
Подзапросы во фразе WHERE244
Подзапросы во фразе SET246
Обновление нескольких таблиц247
Использование значений NULL и DEFAULT248
Обновление представлений248
Слияние данных248
Удаление существующих строк251
Удаление всех строк таблицы251
Удаление по условию252
Удаление одной строки252
Использование запросов253
Поддержка целостности при манипулировании данными253
Импорт и экспорт данных254
Самостоятельная работа254
Подведение итогов255
Урок 14. Представления256
Создание представления 256
Простое представление256
Выбор столбцов и строк исходной таблицы257
Переименование столбцов259
Агрегированные представления259
Многотабличные представления261
Удаление представления262
Модификация данных через представления263
Условия модифицируемости263
Проверка модифицируемых значений265
Использование представлений267
Поддержка целостности267
Самостоятельная работа268
Подведение итогов269
Урок 15. Защита данных270
Составляющие системы защиты270
Субъекты защиты данных270
Условия предоставления доступа271
Защищаемые объекты271
Защищаемые операции272
Передача прав доступа272
Пользователи и роли272
Определение пользователей272
Определение ролей273
Предоставление и отмена привилегий274
Предоставление привилегий на объекты базы данных274
Предоставление ролей пользователям или ролям276
Привилегии владельца277
Отмена привилегий на объекты277
Отмена многократно предоставленных привилегий277
Каскадный эффект при отмене привилегий278
Отмена права предоставления привилегий278
Отмена ролей у пользователей или других ролей279
Представления и защита данных280
Привилегии на базовые таблицы и представления280
Распространение привилегий на столбцы280
Распространение привилегий на строки281
Предоставление доступа к агрегированным данным281
Самостоятельная работа282
Подведение итогов282
Урок 16. Процедурный SQL283
Курсоры283
Курсоры в стандарте SQL284
Курсоры в Oracle286
Введение в PL/SQL289
Типы данных PL/SQL290
Структура блока PL/SQL292
Раздел объявлений DECLARE 293
Выполняемый раздел295
Раздел исключений EXCEPTION299
Расширения SQL301
Самостоятельная работа303
Подведение итогов303
Урок 17. Транзакции и триггеры304
Использование транзакций304
Модель транзакции в стандарте SQL306
Явное инициирование транзакции307
Успешное завершение транзакции308
Откат транзакции310
Установка характеристик транзакции313
Установка проверки ограничений целостности313
Блокировка транзакций314
Использование триггеров314
Что такое триггер базы данных?315
Составляющие триггера316
Удаление триггера320
Триггеры в Oracle321
Дополнительные аспекты использования триггеров323
Самостоятельная работа324
Подведение итогов325
Урок 18. Объектно-ориентированный SQL326
Основные объектные возможности SQL326
Большие объекты данных327
Конструируемые типы данных330
Тип строк330
• Типы коллекций331
Пользовательские типы данных337
Индивидуальные типы338
Структурные типы339
Ссылочные типы и типизированные таблицы343
Сравнение значений345
. Определяемое пользователем приведение типов347
Самостоятельная работа347
Подведение итогов348
Урок 19. SQL/XML349
XML и базы данных349
Сходство и отличие349
Два вида документов XML350
Разновидности баз данных XML352
Отображения между SQL и XML 355
Отображение наборов символов SQL в Unicode355
Отображение идентификаторов SQL в имена XML и наоборот356
Отображение в XML типов данных SQL356
Отображение значений SQL в значения XML 358
Отображение таблиц SQL в XML358
Отображение в XML определений таблиц SQL360
Функции и предикаты XML361
Функция XMLElement362
Функция ХМ [Attributes364
Функция XMLForest:365
Функция XMLConcat366
Функция XMLAgg366
Функция XMLRoot368
Функция XMLComment368
Функция XMLPi369
Функция XMLParse369
Функция XMLSerialize370
Предикат IS DOCUMENT371
Ввод, выбор и обновление документов XML371
Ввод документов XML371
Выбор документов XML и их фрагментов372
Обновление документов XML374
Самостоятельная работа375
Подведение итогов375
Урок 20. Системный каталог.••••376
Что такое системный каталог376
Системный каталог в стандарте SQL377
Системный каталог Oracle378
Информация о себе379
Свои привилегии380
Доступ к данным381
Таблицы, представления и столбцы382
Ограничения целостности384
Подведение итогов385
Приложение А. Демонстрационные материалы386
Учебная база данных386
ДокументХМС393
Приложение Б. Инструментальное средство SQL*Plus395
Запуск SQL* Plus395
Ввод и выполнение команд396
Буфер SQL396
Ввод и выполнение команд SQL396
Ввод и выполнение команд SQL*Plus398
Создание и выполнение скриптов398
Работа с буфером SQL398
Вывод содержимого буфера399
Редактирование текущей строки399
Добавление текста к текущей строке401
Вставка новых строк401
Удаление строк402
Форматирование результатов выполнения запросов403
Изменение заголовков столбцов403
Форматирование числовых столбцов404
Форматирование текстовых столбцов405
Просмотр, приостановка и отмена форматирования406
Переменные SQL*Plus407
Алфавитный указатель408