Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Скидка до 20% на услуги дата-центра. Аренда серверной стойки. Colocation от 1U!

Миграция в облако #SotelCloud. Виртуальный сервер в облаке. Выбрать конфигурацию на сайте!

Виртуальная АТС для вашего бизнеса. Приветственные бонусы для новых клиентов!

Виртуальные VPS серверы в РФ и ЕС

Dedicated серверы в РФ и ЕС

По промокоду CITFORUM скидка 30% на заказ VPS\VDS

VPS/VDS серверы. 30 локаций на выбор

Серверы VPS/VDS с большим диском

Хорошие условия для реселлеров

4VPS.SU - VPS в 17-ти странах

2Gbit/s безлимит

Современное железо!

2009 г.

SEQUEL 2: унифицированный подход к определению, манипулированию и контролю данных

Д.Д. Чамберлин, М.М.Астрахан, К.П.Эсваран, П.П.Грифитс, Р.А.Лори, Д.В.Мел, П.Райшер, Б.В.Вейд

Источник: журнал Системы Управления Базами Данных # 1/1996, издательский дом «Открытые системы»
Новая редакция: Сергей Кузнецов, 2009 г.

Оригинал: D.D. Chamberlin, M.M. Astrahan, K.P. Eswaran, P.P. Griffiths, R.A. Lorie, J.W. Mehl, P. Reisner, B.W. Wade. SEQUEL 2: A Unified Approach to Data Definition, Manipulation, and Control. IBM Journal of Research and Developoment, V. 20, No. 6, 1976.

Содержание

Введение
Средства запросов
Средства манипулирования данными
Средства определения данных
Средства контроля данных
Связывание с основным языком
Заключение
Приложение. Синтаксис SEQUEL 2
Литература

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

Введение

Со времени введения Коддом реляционной модели данных как общего средства управления базами данных [1] было предложено несколько реляционных языков данных, предназначенных для неопытных пользователей. Одним из таких языков является SEQUEL, Structured English Query Language [2], который основан на английских ключевых словах и предназначен для использования как неспециалистами в обработке данных, так и профессиональными программстами. К другим хорошо известным языкам аналогичной ориентации относятся QUEL [3], Query By Example [4] и SQUARE [5].

В результате серии тестов, во время которых студенты университета с опытом программирования и без него обучались средствам запросов SEQUEL [6,7]. Эти тесты выявили некоторые языковые средства, вызывавшие затруднения в обучении. Поэтому в средства запросов языка было внесено несколько изменений.

Помимо того, SEQUEL был расширен в нескольких направлениях. Добавлено средство манипулирования данными, позволяющее вставлять, удалять и модифицировать отдельные кортежи или множества кортежей в реляционной базе данных. Средство определения данных позволяет определять отношения и различные альтернативные представления отношений. Средство контроля данных позволяет каждому пользователю предоставлять другим пользователям права доступа к его данным. Предусматривается также средство контроля данных для определения утверждений о целостности данных и хранимых транзакций, инициируемые различными событиями. Кроме того, к SEQUEL были добавлены средства, которые позволяющие привязывать его к основному языку программирования высокого уровня, такому как PL/1.

Результатом этих расширений и усовершенствований стал, SEQUEL 2 описываемый в этой статье. Можно считать, что SEQUEL 2 состоит из нескольких "уровней" возрастающей сложности. Большинство случайных пользователей могут знакомиться только с простейшими средствами запросов – более обученным пользователям предоставляются более мощные средства, включая некоторые возможности, обычно резервируемые для администратора базы данных. Все возможности базируются на согласованном синтаксисе, ориентированном на ключевые слова.

SEQUEL 2 – это основной внешний интерфейс, который будет поддерживаться System R, экспериментальной реляционной системой управления базами данных, которая сейчас находится в процессе разработки [8]. System R сделает SEQUEL 2 доступным как в качестве автономного интерфейса, ориентированного на работу с дисплеем, так и в качестве подязыка данных, встраиваемого в PL/1.

SEQUEL 2 оперирует отношениями в первой (или более высокой) нормальной форме, как это описано Коддом [1,9]. Язык описывается здесь с помощью серии примеров, основанных на базе данных, показанной на рис. 1. Отношение EMP описывает множество служащих, задавая для каждого служаего его служащего, имя, номер отдела, название задания, номер руководителя, зарплату и комиссионное вознаграждение. Отношение DEPT для каждого отдела задает номер отдела, имя и расположение. Отношение USAGE описывает детали, используемые различными отделами. Отношение SUPPLY описывает компании, которые могут поставлять различные детали. В SEQUEL 2 отношения обозначаются более привычным термином таблица (table). В этой статье термины "отношение" и "таблица" используются взаимозаменяемым образом.

EMP

EMPNO

NAME

DNO

JOB

MGR

SAL

COMM

DFPT

DNO

DNAME

LOC

USAGE

DNO

PART

SUPPLY

SUPPLIER

PART

Рис. 1. Пример базы данных

В следующих разделах вводятся средства языка SEQUEL 2 для запросов, манипулирования данными, определения данных, контроля данных и привязки к основному языку. Там, где это необходимо, делаются ссылки на определенные возможности System R – однако SEQUEL 2 адаптируется с незначительными модификациями для использования и в других реляционных системах. В приложении приводится полный BNF-синтаксис для SEQUEL 2. SEQUEL 2 допускает запись условий в свободном формате; расположение строк и сдвигов в нижеследующих примерах используется только для ясности.

Средства запросов

Базовая операция языка SEQUEL, называемая отображением (mapping), иллюстрируется в приводимом ниже примере Q1. Отображение предполагает, что известная количественная характеристика (DNO = 50) должно быть преобразовано в искомую количественную характеристику (NAME) посредством отношения (EMP). В разделе SELECT перечисляются атрибуты, которые должны быть возвращены запросом, – если нужен весь кортеж, можно написать SELECT *. Раздел WHERE может содержать любой набор предикатов, которые сравнивают атрибуты кортежа со значениями (например, DNO = 50) или два атрибута кортежа между собой (например, SAL < COMM). Предикаты могут соединяться с помощью AND и OR; и могут использоваться скобки, чтобы установить последовательность вычисления.

Q1. Найти имена служащих в отделе 50.

    SELECT NAME 
    FROM EMP 
    WHERE DNO = 50 

В общем случае, отображение возвращает набор значений – выбранные атрибуты кортежей, которые удовлетворяют разделу WHERE. Из возвращенного множества не исключаются значения-дубликаты, если пользователь не потребует этого, написав SELECT UNIQUE. Мы выбрали это соглашение, поскольку исключение значений-дубликатов – это дорогостоящая операция, которая, по нашему мнению, не должна выполняться по умолчанию. В запросе Q2 иллюстрируется "проекция" отношения EMP на атрибут DNO.

Q2. Выдать все различные номера отделов в таблице EMP.

    SELECT UNIQUE DNO 
    FROM EMP 

Предикат во разделе WHERE может проверять атрибут на принадлежность множеству, как показано в запросе Q3, где также иллюстрируется представление множества констант.

Q3. Выдать имена служащих в отделах 25, 47 и 53.
    SELECT NAME 
    FROM EMP 
    WHERE DNO IN (25,47,53) 

Можно использовать результат отображения в разделе WHERE другого отображения. Эта операция, называемая вложенным отображением (nested mapping), иллюстрируется в Q4. Внутреннее отображение возвращает набор значений DNO отделов, расположенных в Эванстоне (Evanston). Затем внешнее отображение выполняется так, как если бы вместо внутреннего отображения ему было задано множество констант. Может иметься любое число уровней вложения отображений. Вместо IN может использоваться операция сравнения = без изменения смысла запроса (пользователю это может показаться более естественным, если внутреннее отображение возвращает одно значение).

Q4. Найти имена служащих, которые работают в отделах, расположенных в EVANSTON.
    SELECT NAME 
    FROM EMP 
    WHERE DNO IN 
          SELECT DNO 
          FROM DEPT 
          WHERE LOC = 'EVANSTON' 

В SEQUEL 2 требуется заключать символьно-строковые константы в одинарные кавычки, чтобы отличать их от имен атрибутов (например, и NAME = JOB, и NAME = 'JOB' являются допустимыми предикатами, но с различным смыслом). Для числовых констант являются необязательными (например, SAL = 10000 и SAL = '10000' эквивалентны).

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

Q5. Выдать номер служащего, его имя и зарплату для служащих отдела 50 в порядке номеров служащих.
    SELECT EMPNO,NAME,SAL 
    FROM EMP 
    WHERE DNO = 50 
    ORDER BY EMPNO 

В SEQUEL 2 обеспечивается несколько встроенных функций, которые могут использоваться в разделе SELECT, как показано в запросе Q6. Эти функции включают AVG, SUM, COUNT, MAX и MIN. System R позволяет добавлять к системе дополнительные функции, размещая соответствующие программы в специальной библиотеке функций.

Q6. Найти среднюю зарплату клерков.

    SELECT AVG(SAL) 
    FROM EMP 
    WHERE JOB = 'CLERK' 

Нотация COUNT(*) обозначает количество кортежей, которые удовлетворяют разделу WHERE.

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

Q7. Сколько различных заданий у служащих в отделе 50?

    SELECT COUNT(UNIQUE JOB) 
    FROM EMP 
    WHERE DNO = 50 

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

    AVG(SAL)/52 
    AVG(SAL)+AVG(COMM) 
    AVG(SAL+COMM) 

Отношение может быть разделено на группы в соответствии с значением некоторого атрибута, и затем встроенная функция применяется к каждой группе. Этот тип запроса показан в примере Q8. Раздел GROUP BY всегда используется вместе с какой-либо встроенной функцией. Если используется этот раздел, то каждый элемент в разделе SELECT должен быть уникальным группы, а не индивидуального кортежа. Например, в Q8 у каждой группы служащих имеются уникальный DNO и уникальная средняя зарплата. Если в разделе SELECT запроса Q8 добавить EMPNO, возникнет ошибка, так как EMPNO не является уникальным свойством каждой группы.

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

    SELECT DNO,AVG(SAL) 
    FROM EMP 
    GROUP BY DNO 

Отношение может быть разделяться на группы с последующим применением некоторого предиката или набора предикатов для выбора только требуемых групп и отбраковки других. Эти предикаты, задающие требования к группам, всегда основываются на встроенных функциях и размещаются в специальном разделе HAVING, как показано в запросе Q9. Предикат в разделе HAVING может сравнивать некоторое агрегатное свойство группы с константой (например, AVG(SAL) < 10000) или с другим агрегатным свойством той же самой группы (например, AVG(SAL) ≤ AVG(COMM)).

Q9. Выдать номера отделов, в которых средняя зарплата служащих не превышает 10000.

    SELECT DNO 
    FROM EMP 
    GROUP BY DNO 
    HAVING AVG(SAL)<10000 

Если в запросе содержатся и раздел WHERE, и раздел HAVING, то они обрабатываются в следующем порядке: сначале применяется раздел WHERE для отбора кортежей; затем формируются группы; далее применяется раздел HAVING для отбора групп, как показано в запросе Q10.

Q10. Перечислить отделы, в которых работает более десяти клерков.

     SELECT DNO 
     FROM EMP 
     WHERE JOB = 'CLERK' 
     GROUP BY DNO 
     HAVING COUNT(*) > 10 

В языке обеспечивается специальная встроенная функция SET, которая вычисляет множество значений заданного атрибута, присутствующих в данной группе. Это множество атрибутов затем можно сравнивать с другим множеством в разделе HAVING. В запросе Q11 внутреннее отображение возвращает множество всех названий заданий в таблице EMP (с дубликатами). Внешнее отображение группирует служащих по номерам отделов и затем выбирает те группы, в которых множество названий заданий совпадает со множеством всех названий заданий. В этом случае операция "=" используется для сравнения двух множеств. К другим операциям сравнения множеств относятся ¬=, [IS][NOT]IN, CONTAINS и DOES NOT CONTAIN. Все эти операции сравнения множеств до выполнения сравнения исключают дубликаты из обоих своих операндов.

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

     SELECT DNO 
     FROM EMP 
     GROUP BY DNO 
     HAVING SET(JOB) = 
            SELECT JOB 
            FROM EMP 

В SEQUEL 2 также доступны теоретико-множественные операции INTERSECT, UNION и MINUS. Их можно использовать для комбинирования результатов двух отображений, как показано в запросе Q12. Запрос может содержать несколько теоретико-множественных операторов; для разрешения неоднозначностей при необходимости используются скобки. Как и при применении перечисленных выше операций сравнения множеств, до выполнения операций INTERSECT, UNION и MINUS из операндов автоматически исключаются дубликаты.

Q12. Выдать номера отделов, в которых нет служащих.

    SELECT DNO 
    FROM DEPT 
    MINUS 
    SELECT DNO 
    FROM EMP 

Запрос может возвращать значения, выбранные из более чем одного отношения. Примером является операция соединения (join), которую иллюстрируетзапрос Q13. В разделе FROM пользователь может указать несколько отношений. При выполнении такого запроса концептуально формируется декартово произведение этих отношений, и затем оно фильтруется предикатами раздела WHERE. (Конечно, правильно разработанная система будет избегать реального формирования декартова произведения, но достигнет того же результата с помощью более эффективных средств.) Если в разделе FROM указывается более одного отношения, пользователь должен надлежащим образом уточнять каждое имя атрибута в разделах SELECT и WHERE (например, чтобы можно было различить EMP.DNO и DEPT.DNO). Если имя атрибута фигурирует только в одном из участвующих отношений, его не нужно уточнять (например, в Q13 можно было бы указать просто SELECT NAME, LOC).

Q13. Выдать имена всех служащих и расположение их отделов.

    SELECT EMP.NAME,DEPT.LOC 
    FROM EMP,DEPT 
    WHERE EMP.DNO = DEPT.DNO 

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

Q14. Для каждого служащего, зарплата которого выше зарплаты его руководителя, выдать имя этого служащего и имя его руководителя.

    SELECT X.NAME, Y.NAME 
    FROM EMP X, EMP Y 
    WHERE X.MGR = Y.EMPNO 
    AND X.SAL > Y.SAL 

Язык SEQUEL 2 также позволяет использовать метку для уточнения имен атрибутов вне блока отображения, в котором определена эта метка. Например, в запросе Q15 ищутся кортежи X отношения SUPLLY, такие что множество деталей, поставляемых компанией-поставщиком в кортеже X (вычисляемое в первом вложенном отображении), содержит множество деталей, используемых отделом 50 (вычисляемое во втором вложенном отображении).

Q15. Выдать названия компаний, которые поставляют все детали, используемые отделом 50.

    SELECT SUPPLIER 
    FROM SUPPLY X 
    WHERE 
         (SELECT PART 
          FROM SUPPLY 
          WHERE SUPPLIER = X.SUPPLIER) 
    CONTAINS 
         (SELECT PART 
          FROM USAGE 
          WHERE DNO = 50) 

Мы разрабатывали SEQUEL 2 таким образом, чтобы всякий раз, когда переменная появляется вне блока, в котором она определена, ее можно было внести в этот блок (и часто совсем исключить) с помощью GROUP BY и специальной функции SET. Например, запрос Q16 эквивалентен запросу Q15.

Q16. (Эквивалентно Q15.)

    SELECT SUPPLIER 
    FROM SUPPLY 
    GROUP BY SUPPLIER 
    HAVING SET(PART) CONTAINS 
           SELECT PART 
           FROM USAGE 
           WHERE DNO = 50 

Нотация для множества констант была показана в примере Q3. Кортеж констант обозначается, как показано в следующем примере:

    <'CLERK',50> 

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

    (<'CLERK',50>, <'CLERK',52>, <'PROGRAMMER',52>) 

Угловые скобки (<, >) могут также использоваться для обозначения подкортежа атрибутов, выбранных из кортежа в базе данных, как в запросе Q17.

Q17. Перечислить имена служащих, которые имеют те же задание и зарплату, что и Смит.

    SELECT NAME 
    FROM EMP 
    WHERE <JOB,SAL> = 
          SELECT JOB,SAL 
          FROM EMP 
          WHERE NAME = 'SMITH' 

В SEQUEL 2 допускается существование в базе данных неизвестных, или null-значений. На null-значение можно сослаться с помощью ключевого слова NULL. Null-значения игнорируются при вычислении всех встроенных функций, за исключением COUNT (например, в вычислении AVG(SAL) не участвуют неизвестные зарплаты).

AND T  F  ? 
T
T
F
?
F
F
F
F
?
?
F
?

 OR  T  F  ? 
T
T
T
T
F
T
F
?
?
T
?
?

NOT    
T
F
F
T
?
?

IF X THEN YY=TY=FY=?
X=T
T
F
?
X=F
T
T
T
X=?
T
?
?

Рис. 2. Таблицы истинности для трехзначной логики

При определении, удовлетворяет ли данный кортеж разделу WHERE запроса, предикатам, тестирующим атрибуты, для которых кортеж содержит null-значение, присваивается неизвестное значение истинности (обозначаемое как "?"). Затем вычисляется значение истинности всего раздела WHERE с использованием трехзначной логики для вычисления результатов операций AND и OR (см. Рис. 2). Кортеж считается удовлетворяющим разделу WHERE, если итоговым истинностным значением раздела является TRUE, а не FALSE или ?. Например, кортеж со значением DNO, равным 50, и неопределенной зарплату будет удовлетворять разделу WHERE запроса Q18, но не запроса Q19.

Q18.

    SELECT * 
    FROM EMP 
    WHERE DNO = 50 
    OR SAL > 15000 

Q19.

    SELECT * 
    FROM EMP 
    WHERE DNO = 50 
    AND SAL > 15000 

Исключение из перечисленных выше правил делается в случае предикатов, которые явно ищут null-значения, например, WHERE SAL = NULL. В этих предикатах null-значение обрабатывается так же, как и любое другое значение.

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

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

Средство вставки позволяет пользователю вставлять в отношение новый кортеж или множество кортежей. Вставка одного кортежа иллюстрируется примером М1. Атрибутам, которые не определены оператором вставки, присваиваются null-значения. Если у кортежа, который должен быть вставлен, все атрибуты приведены в правильном порядке, список имен атрибутов может быть опущен.

М1. Вставить нового служащего по имени 'Jones' с номером 535 и отделом 51 с неопределенными остальными атрибутами.

INSERT INTO EMP(EMPNO,NAME,DNO): 
       <535,'JONES',51> 

Оператор вставки языка SEQUEL может также вычислять запрос и вставлять результирующее множество кортежей в некоторое существующее отношение. Предположим, что база данных содержит отношение CANDIDATES, которое содержит столбцы номера служащего, его имени, номера отдела и зарплаты. Тогда можно использовать оператор М2 для выбора множества значений из отношения EMP и их вставки в CANDIDATES.

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

INSERT INTO CANDIDATES: 
       SELECT EMPNO,NAME,DNO,SAL 
       FROM EMP 
       WHERE COMM > 0.5 * SAL 

Удаление – это процесс спецификации кортежей, которые должны быть удалены из базы данных. Эти кортежи указываются с помощью раздела WHERE, который синтаксически идентичен разделу WHERE запроса, как показано в примере М3.

М3. Удалить из EMP служащего с номером 561.

    DELETE EMP 
    WHERE EMPNO = 561 

Иногда может быть полезно придумать метку для кортежей, которые должны быть удалены, и затем использовать эту метку для определения свойств кортежей. Это аналогично использованию меток в средствах запросов языка. Удаление с использованием метки иллюстрируется примером М4.

М4. Удалить из таблицы DEPT все отделы, в которых нет служащих.

    DELETE DEPT X 
    WHERE
	   (SELECT COUNT (*) 
	    FROM EMP
            WHERE DNO = X.DNO) = 0 

Средства модификации SEQUEL 2 аналогичны средствам удаления, за исключением того, что для указания модификаций, которые должны быть сделаны в выбранных кортежах, используется дополнительный раздел SET. Новые значения для модифицированных атрибутов могут быть заданы как константы, как вложенные запросы или как выражения, основанные на исходных значениях атрибутов, как показано в примере М5. Как и в случае удаления, в разделе UPDATE можно поместить метку и использовать ее во вложенных запросах разделов SET или WHERE.

М5. Модифицировать таблицу EMP, повысив на 10 процентов зарплату всем тем служащим, номер которых содержится в таблице CANDIDATES.

UPDATE EMP 
SET SAL = SAL*1.1 
WHERE EMPNO IN 
      SELECT EMPNO 
      FROM CANDIDATES 

Не проверяются, являются ли вновь вставленные или модифицированные кортежи дубликатами уже существующих кортежей, так как в SEQUEL допускается существование кортежей-дубликатов, если пользователь не указал иначе. В версии System R языка SEQUEL кортежи-дубликаты могут быть запрещены с помощью "уникального образа" ("unique image") (объясняется в следующем разделе).

Оператор присваивания создает новое отношение в базе данных и копирует в него результат запроса. Это новое отношение может затем запрашиваться, модифицироваться и обрабатываться точно также, как любое другое отношение. В операторе присваивания специфицируются имя нового отношения и имена столбцов. Если имена столбцов нового отношения одназначно определяются разделом SELECT запроса, они могут быть опущены. Присваивание иллюстрируется примером М6.

М6. Создать новое отношение MANAGERS (с соответствующими именами столбцов) и разместить в нем номер служащего, имя, номер отдела и зарплату всех служащих, которые являются руководителями.

ASSIGN TO MANAGERS (EMPNO,NAME,DEPT,SALARY): 
    SELECT EMPNO,NAME,DNO,SAL 
    FROM EMP 
    WHERE EMPNO IN 
          SELECT MGR 
          FROM EMP 

Новое отношение, созданное оператором присваивания, не зависит от отношения(-ий), из которого(ых) оно выведено. После выполнения М6 добавление нового руководителя в таблицу EMP не влияет на отношение MANAGERS, а модификация MANAGERS не влияет на EMP.

Средства определения данных

Средства определения данных позволяют создавать и удалять отношения, определять альтернативные представления отношений и специфицировать способы доступа (индексы и т.д.), которые будут поддерживаться в базе данных. Средства определения данных языка описывают структуры данных, поддерживаемые системой, в которой функционирует язык. В этом разделе описываются операторы определения данных SEQUEL 2 в контексте System R. Можно было бы сделать соответсвующие модификации для адаптации этого языка к другим реляционным системам.

Пример D1 – это оператор, создающий новое отношение (таблицу), которое будет физически храниться в системе. System R разрешает создавать и удалять таблицы динамически. Пользователь специфицирует имя таблицы, имена столбцов и типы данных. Если в некотором столбце не должны допускаться null-значения (например, столбец DNO в данном примере), пользователь может это указать. Типы данных, поддерживаемые System R, показаны в сводке синтаксических правил в Приложении.

D1. (Это оператор, который можно было бы использовать для создания таблицы DEPT.)

CREATE TABLE DEPT 
  (DNO(CHAR(2),NONULL), 
   DNAME(CHAR(12) VAR), 
   LOC(CHAR(20) VAR) ) 

В SEQUEL 2 имя таблицы при необходимости может уточняться именем пользователя, который ее создал. Например, если пользователи Смит и Джонс каждый создали таблицу с именем EMP, то Смит может ссылаться на свою собственную таблицу по имени EMP, а на таблицу Джонса (если у него есть такие права) – по имени JONES.EMP. Пользователь может также определить для таблицы синоним, или альтернативное имя, в примере D2. Этот прием позволяет ссылаться на таблицу, созданную другим пользователем, без повторения имени ее создателя при каждой ссылке.

D2. Определить JEMP как синоним для таблицы EMP, созданной Джонсом.

   DEFINE SYNONYM JEMP AS JONES.EMP 

Способы доступа, поддерживаемые System R, называются образами (image) и линками (link) [8]. Образ – это индекс на одном или несколькими атрибутами, поддерживаемый в форме В-дерева [10]. Не более чем один образ на каждом отношении может иметь свойство кластеризации, (clustering), которое означает, что кортежи, находятся поблизости друг от друга в порядке представления данного образа, физически сохраняются поблизости друг от друга в базе данных. Образ также может быть определен уникальным (unique), что означает, что индексный атрибут должен быть ключом соответствующего отношения, т.е. никакие два кортежа не могут содержать одно и то же значение этого атрибута. Линк (link) – это набор указателей, соединяющих кортежей одного отношения с кортежами другого отношения, которые подбираются в соответствии с некоторым атрибутом. Линк может иметь свойство кластеризации; в этом случае система пытается поддерживать физическую смежность связанных кортежей. Примеры операторов, которые создают образы и линки, показаны в D3 и D4. Каждому образу или линку задается имя (I3 и L5 в примерах), которые дают возможность пользователю ссылаться на них (например, в операторе DROP).

D3. Создать образ I3 для атрибута SAL в таблице EMP.

    CREATE IMAGE I3 ON EMP(SAL)

D4. Создать линк L5, который соединяет строки DEPT со строками EMP с такими же значениями атрибута DNO. Упорядочить служащих на линке сначала по JOB, а затем по SAL.

    CREATE LINK L5 
    FROM DEPT(DNO) 
    TO EMP(DNO) 
    ORDER BY JOB,SAL 

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

Очень важный аспект определения данных – возможность определять альтернативные представления (view) хранимых данных. В SEQUEL 2 способ определения представления очень похож на способ задания запроса. Это связано с тем, что SEQUEL 2 обладает свойством замкнутости (closure): результат любого запроса к одной или нескольким таблицам сам является таблицей. Поэтому формулировка любого запроса может использоваться как определение представления. В операторе DEFINE VIEW задается имя представления и имена его столбцов. (Если имена столбцов могут быть одназначно выведены из запроса, определяющего представление, они могут быть опущены.) После определения представления оно может использоваться точно также, как используется хранимая таблица: к нему можно обращаться с запросами, на его основе могут определяться другие представления, и при некоторых ограничениях [11] оно может обновляться. В отличие от описанного выше оператора присваивания, представление – это динамическое окно в базу данных. Через представление видны изменения, производимые в отношениях, лежащих в его основе. Вообще говоря, через данное представление могут производиться обновления, только если каждый кортеж представления связан в точности с одним кортежем хранимого отношения. Это позволяет реализовывать обновления кортежей представления путем обновления соответствующих хранимых кортежей.

Одно важное применение представлений – предоставление пользователю возможности доступа только к некоторой части отношения. Например, если пользователь имеет право читать только номер, имя и задание служащих в отделе 50, ему может быть предоставлено представление, показанное в D5.

D5. Определить представление D50, содержащее номер, имя и задание служащих в отделе 50.

    DEFINE VIEW D50 AS 
        SELECT EMPNO,NAME,JOB 
        FROM EMP 
        WHERE DNO = 50 

Представления также полезны для предоставления статистических характеристик данных. Например, представление на основе запроса Q8 обеспечивало бы данные о средней зарплате в каждом отделе, не позволяя получить сведения о какой-либо индивидуальной зарплате. Представление может определяться с использованием ключевого слова USER, которое всегда интерпретируется как идентификатор текущего пользователя. За счет этого, например, мы можем определить представление, которое позволяет каждому пользователю иметь информацию только о служащих своего отдела.

Представление не обязательно выводится из одного отношения. Например, в примере D6 представление определяется как соединение двух таблиц с помощью запроса, аналогичного Q13. Пример D6 также показывает, что к представлению можно сделать запрос, как если бы оно было хранимым отношением. При определении представление на основе соединения, такое как в D6, пользователи должны остерегаться "ловушки соединения", описанной Коддом [1]. В терминах D6, из тех фактов, что служащий X работает в отделе Y, и отдел Y находится в месте Z, не обязательно следует, что служащий X находится в месте Z.

D6. Определить представление PROGS, состоящее из имен и зарплат всех программистов, а также мест расположения их отделов.

    DEFINE VIEW PROGS 
                   (NAME,SALARY,HOMEBASE) AS 
        SELECT EMP.NAME,EMP.SAL,DEPT.LOC 
        FROM EMP,DEPT 
        WHERE EMP.DNO = DEPT.DNO 
        AND EMP.JOB = "PROGRAMMER" 

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

    SELECT AVG(SAL) 
    FROM PROGS 
    WHERE HOMEBASE = "DENVER" 

Иногда может потребоваться расширить существующую таблицу, добавив в нее новый столбец, например, чтобы можно было создать новое приложение. SEQUEL 2 позволяет добавлять столбцы в правую часть существующих таблиц посредством оператора EXPAND, в котором указываются имя и тип данных нового столбца. Считается, что существующие кортежи имеют в новом столбце null-значения до тех пор, пока они не будут модифицированы. На запросы и представления, которые были написаны в терминах существующей таблицы, расширение не влияет (за исключением тех запросов, которые включают раздел SELECT *).

D7. Добавить в таблицу DEPT новый столбец NEMPS целого типа.

    EXPAND TABLE DEPT 
           ADD COLUMN NEMPS(INTEGER) 

Если в таблицах, представлениях, образах и линках больше нет необходимости, они могут быть удалены из системы командой DROP, как показано в примере D8.

D8. Удалить представление D50.

    DROP VIEW D50 

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

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

D9. (Иллюстрирует использование комментариев.)

    COMMENT ON VIEW D50: 
       'LIMITED VIEW OF EMPLOYEES IN DEPT.50' 

Средства контроля данных

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

Так как SEQUEL позволяет любому пользователю создавать новые отношения и представления, на каждого пользователя ложится ответственность за контроль доступа к объектам данных, которые он создает. Когда пользователь создает отношение или представление, он и только он получает все права по выполнению действий над ним. (Если объект – это представление, права пользователя ограничиваются теми правами, которые он имеет для базового отношения.) Пользователь может предоставить доступ к своему отношению или представлению другим пользователям с помощью команды GRANT языка SEQUEL. Могут быть предоставлены следующие привилегии:

  • Read
  • Insert
  • Delete
  • Update (по столбцам)
  • Expand
  • Image (для определения образов на отношении)
  • Link (для создания линков на отношении)
  • Control (для задания утверждений целостности или определения триггеров, относящихся к данному отношению – объяснение приведено ниже).
Дополнительная привилегия RUN, которая применяется не к отношениям, а к программам, объясняется в следующем разделе.

Кроме того, пользователь, передающий свои привилегии, может позволить пользователю, принимающему эти привилегии, передавать их другим пользователям, включив в оператор GRANT раздел WITH GRANT OPTION. Если некоторый обладает некоторой привиленией, но не имеет связанной с ней привилегии GRANT OPTION, то он может пользоваться основной привилегией, но не может передавать ее другим пользователям.

С1. Дать следующие привилегии на таблице EMP Смиту и Андерсону: возможность читать, вставлять кортежи, модифицировать столбцы JOB и DNO и передавать эти возможности другим пользователям.

    GRANT READ, INSERT, UPDATE(JOB,DNO) ON EMP 
       TO SMITH, ANDERSON WITH GRANT OPTION 

Вместо списка пользователей, которым должна быть передана привилегия, может использоваться ключевое слово PUBLIC, если эта привиления должна быть передана всем пользователям. Вместо списка привилегий в операторе GRANT может использоваться фраза ALL RIGHTS. Если список привилегий не указывается, по умолчанию передается привилегия READ.

После того как некоторая привилегия передана, ее можно изъять с помощью команды REVOKE. Указываемые привилегии отбираются у того, кому они были переданы, и у всех пользователей, которым он их, в свою очередь, передал, если у обладателя привилегий не имеется другого, независимого источника отбираемых привилегий. Изъятие привилегии может также иметь и другие последствия. Например, если у пользователя отбирается привилегия READ на отношение EMP, то должны быть уничтожены все представления, определенные на EMP этим пользователем. Эти вопросы более подробно рассматриваются в [12].

С2. Лишить Андерсона возможности модифицировать таблицу EMP.

    REVOKE UPDATE ON EMP FROM ANDERSON 

В языке SEQUEL пользователю, облдающему привилегией CONTROL на некоторой таблице, определять утверждения (assertion) целостности относительно данных этой таблицы. Утверждение целостности – это предикат, который может иметь значения TRUE или FALSE. Когда выполняется оператор ASSERT, система проверяет текущее значение истинности предиката. Если в данный момент оно равно FALSE, условие отвергается. Если – TRUE, то система с этого момента производит проверку истинности этого утверждения при всех дальнейших модификациях базы данных. Пользователь, определяющий утверждение целостности, задает его имя. Если оператор вставки, удаления или модификации нарушает некоторое утверждение целостности, этот оператор отвергается, и возвращается код нарушения вместе с именем нарушенного условия.

Простейший тип утверждений целостности относится к конкретному отношению (идентифицируемому фразой вида ON EMP), и такие утверждения должны применяться к каждому кортежу отношения.

С3. Задать утверждение, что зарплата всех служащих меньше 50000.

    ASSERT A1 ON EMP: SAL < 50000

С4. Задать утверждение, что все клерки получают зарплату между 8000 и 15000.

    ASSERT A2 ON EMP: 
        IF JOB = "CLERK" THEN 
        SAL BETWEEN 8000 AND 15000 

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

С5. Задать утверждение, что значение атрибут NEMPS каждой строки таблицы DEPT равно числу служащих в данном отделе.

ASSERT A3 ON DEPT X: NEMPS=
       (SELECT COUNT(*) 
        FROM EMP
        WHERE DNO = X.DNO) 

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

С6. Задать утверждение, что ни одна строка в таблице ЕМР не может включать значение DNO, не присутствующее в таблице DEPT.

ASSERT A4:
   (SELECT DNO FROM EMP) 
     IS IN
   (SELECT DNO FROM DEPT) 

Представленные до сих пор утверждения иллюстрируют условия, которые должны соблюдаться статически. Другой класс утверждений имеет дело с переходами (transition) в базе данных. В утверждении этого типа должно задаваться обстоятельства, при которых оно должно проверяться: при вставке, удалении или модификации кортежей в некотором отношении. Когда над кортежем данного отношения выполняется указанное действие, проверяется тело утверждени для определения допустимости такого перехода. Переход можно описать c в терминах значений OLD или NEW, которые представляют атрибуты кортежа до и после перехода. Если один оператор SEQUEL модифицирует много кортежей, условие проверяется для каждого кортежа, и, если для какого-либо кортежа утверждение нарушается, то отбрасывается весь оператор.

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

ASSERT A5 ON UPDATE OF EMP(SAL): 
   NEW SAL >= OLD SAL 

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

Общее правило для обработки null-значений при проверке утверждения состоит в том, что наличие null-значений никогда не должно вызывать выполнение условия утверждени, если в противном случае (при отсутствии null-значений) оно не выполняется, или его невыполнение, если в противном случае оно выполняется. Это правило реализуется на основе использования трехзначной логики. Предикат утверждения, который в общем случае может быть булевским выражением, вычисляется с помощью таблиц истинности с рис. 2. Утверждение целостности удовлетворяется, если результат равен TRUE или ?, и нарушается, если результат равен FALSE. Например, условие, что ни одна зарплата не превышает 20000, не нарушается в случае неизвестного размера зарплаты. Исключение из этого правила делается в том случае, когда null-значения в утверждении целостности используются явным образом, например, EMPNO ¬= NULL. В таких утверждениях null-значение обрабатывается подобно любому другому значению.

SEQUEL позволяет группировать несколько операторов в транзакцию, размещая их между операторами BEGIN TRANSACTION и END TRANSACTION. Обычно проверка утверждений целостности внутри транзакции откладывается. В конце транзакции проверяются все относящиеся к ней утверждения, и, если какое-либо из них нарушается, отвергается вся транзакция. Это позволяет производить обновления, которые вызывают переход базы данных через временно несогласованные состояния. Например, если нанимается новый служащий, могут быть сделаны изменения в EMP и DEPT, которые приведут к тому, что в базе данных на мгновение будет нарушено утверждение А3 из примера С5. Однако в конце транзакции утверждение А3 будет удовлетворяться.

Пользователь, который задает утверждение целостности, может дополнительно определить, что проверка его условия никогда не должна отладываться. Если он включит слово IMMEDIATE в префикс утверждения, проверка всегда будет осуществляться при выполнении каждого оператора SEQUEL. Так как утверждения переходов (в которых сравниваются значения OLD и NEW) основываются на покортежном принципе, они всегда должны проверяться немедленно, а не в конце транзакции.

В System R размещение нескольких операторов в транзакции имеет дополнительное значение, определяя, что система должна выполнять эти операторы как атомарное действие, не допуская вмешательства (например, модификации соответствующих данных) со стороны других пользователей во время выполнения транзакции. Настолько, насколько возможно, System R пытается защитить каждого пользователя от восприятия наличия других пользователей, работающих одновременно с ним. Поэтому SEQUEL не требует от пользователя выполнения операторов блокировки или специальных операторов, выражающих намерение модификации. Установкой и сбросом блокировок, обнаружением и разрешением тупиковых ситуаций занимается основная система. Эти аспекты и их реализация в System R более подробно обсуждаются в [8].

В любой момент в пределах транзакции пользователь может объявить "точку сохранения" с помощью оператора SAVE <имя-точки сохранения>. В одной транзакции можно объявить много точек сохранения. В любой момент пользователь может аннулировать все изменения, сделанные им в базе данных с момента объявления определенной точки сохранения, с помощью оператора RESTORE <имя-точки сохранения>. Если в операторе RESTORE имя точки сохранения опущено, аннулирование изменений производится с начала текущей транзакции. Ни один оператор RESTORE не может производить аннулирование изменений до точки сохранения, установленной до начала текущей транзакции. Оператор RESTORE не влияет на изменения, которые сделаны другими пользователями.

Чтобы помочь поддерживать целостность базы данных, пользователь может определить триггер (trigger), который будет выполняться при появлении определенного действия: READ, INSERTION, DELETE или UPDATE над кортежем в некоторой заданной таблице. Тело триггера, которое состоит из одного или более операторов SEQUEL, выполняется сразу же после выполнения указанного действия любым пользователем. Если оператор SEQUEL выполняет действие (например, модификацию) над многими кортежами, и это действие вызывает триггер, то триггер выполняется повторно, сразу после модификации каждого кортежа. Триггеры всегда выполняются немедленно и не могут быть отложены до конца транзакции. В теле триггера можно использовать слова OLD и NEW для ссылки на предыдущее и измененное значения кортежа, как показано в примере С8.

С8. (Этот триггер автоматически модифицирует соответствующие атрибуты NEMP в таблице DEPT при каждой модификации атрибута DNO служащего.)

DEFINE TRIGGER T1 
ON UPDATE OF EMP(DNO): 
   (UPDATE DEPT 
    SET NEMPS = NEMPS + 1 
    WHERE DNO = NEW EMP.DNO
	
    UPDATE DEPT 
    SET NEMPS = NEMPS – 1 
    WHERE DNO = OLD EMP.DNO 

К кортежу, вызывающему триггер, может быть присоединена метка, и эта метка может использоваться в теле триггера. Кроме того, оператор в теле триггера может содержать раздел IF, который делает его выполнение зависимым от некоторых условий, как показано в примере С9.

С9. При удалении служащего из EMP, если в его отделе больше не остается служащих, удалить соответствующую запись в DEPT.

    DEFINE TRIGGER T2 
    ON DELETION OF EMP X: 
      (IF (SELECT COUNT(*) 
           FROM EMP 
           WHERE DNO = X.DNO) = 0 
       THEN DELETE DEPT 
           WHERE DNO = X.DNO) 

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

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

Пользователь с привилегией CONTROL может удалить утверждение целостности или триггер с помощью команды DROP, например:

    DROP TRIGGER T2 

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

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

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

Связывание с основным языком

SEQUEL 2 разрабатывается таким образом, что может использоваться как в качестве автономного языка для интерактивных пользователей, так и в качестве подъязыка данных, встраиваемого в основной язык программирования. Возможности, рассмотренные в предыдущих разделах, описывались с точки зрения интерактивного пользователя. В этом разделе описываются дополнительные возможности языка, которые обеспечиваются для связи с основным языком. Там, где это необходимо, мы ссылаемся на конкретные детали реализации System R.

System R обеспечивает использование операторов SEQUEL в качестве операторов программы PL/1. Операторы SEQUEL обнаруживаются прекомпилятором, который заменяет их допустимыми вызовами PL/1 программ модуля времени выполнения, которые и выполняют нужныю функции.

Для запроса обеспечиваются средства, доставляющие результат в основную программу. Запросы, встраиваемые в программу, могут содержать раздел INTO, в котором задается список переменных основной программы, служащих адресатами для выбранных атрибутов, как показано в примере Р1.

Р1. Возвратить задание служащего с номером 507 в программную переменную X и его зарплату в программную переменную Y.

   SELECT JOB,SAL 
   INTO X,Y 
   FROM EMP 
   WHERE EMPNO = 507; 

Кроме раздела INTO, программные переменные могут появляться везде, где может использоваться константа в запросе или операторе SEQUEL любого другого типа. Всюду, где появляется программная переменная, программист может вместо этого определить пару имен переменных, разделенных двоеточием. Первая переменная этой пары называется хранителем значения (value holder), а вторая, которая должна иметь тип данных BIN FIXED, – null-индикатором (null indicator). Ноль в null-индикаторе означает наличие реального значения в хранителе значения; отрицательное значение в null-индикаторе означает null-значение. Эти возможности иллюстрируются в примере Р2.

Р2. Возвратить в программную переменную Х1 зарплату служащего, номер которого находится в программной переменной Z1. (Переменные Х2 и Z2 служат null-индикаторами.)

   SELECT SAL 
   INTO X1:X2 
   FROM EMP 
   WHERE EMPNO = Z1:Z2; 

Если имя объявленной программной переменной совпадает с именем столбца в базе данных (например, WHERE SAL = COMM, если COMM – объявленная программная переменная), система предполагает, что это ссылка на программную переменную, а не на столбец.

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

Р3. Прочитать номер отдела с терминала, затем найти и вывести имена служащих данного отдела. (Операторы, помеченные с левого края звездочкой, обрабатываются прекомпилятором SEQUEL. Все остальные – стандартные операторы PL/1. Звездочки не являются частью программы.)

   P3: PROC OPTIONS(MAIN); 
       DCL X CHAR(50), Y CHAR(2); 
*      LET C1 BE 
*          SELECT NAME INTO X 
*          FROM EMP WHERE DNO = Y; 
       DISPLAY('DNO?') REPLY(Y); 
*      OPEN C1; 
       DO WHILE (CODE = OK); 
*         FETCH C1; 
          DISPLAY(X); 
       END; 
*      CLOSE C1; 
   END P3; 

В этом примере объявления X и Y – стандартны для PL/1. Оператор LET C1 BE <запрос> является объявлением для системы базы данных и связывает имя курсора С1 с данным запросом. Оператор OPEN С1 связывает входную переменную Y с ее текущим значением и подготавливает доставку кортежей, соответствующих запросу. При каждом выполнении FETCH C1 в программные переменные, указанные в запросе, помещаются значения соответствующих атрибутов нового кортежа результата. CODE – это специальная переменная, в которую система управления базой данных помещает код результата после каждого обращения к базе данных. (Здесь мы не приводим полную информацию относительно кодов результата.) Оператор CLOSE C1 сообщает системе, что больше не будут делаться выборки кортежей из результата запроса, в данный момент связанного с С1. Если С1 открывается повторно, входная переменная Y повторно связывается с потенциально другим значением, и может быть выбрано новое множество кортежей.

При каждом открытии курсора для его поддерживается позиция во множестве кортежей, на котором он определен (так называемое активное множество (active set)). Если каждый кортеж активного множества однозначно связан с кортежем некоторого отношения (например, запрос включает ключ этого отношения), говорят, что курсор является обновляемым (updateable). Это означает, что на текущую позицию курсора можно ссылаться в операторах UPDATE или DELETE для обозначения кортежа, который будет модифицироваться или удаляться. Предположим, например, что нам нужно модифицировать программу примера Р3, чтобы она повышала зарплату каждому служащему в указанном отделе. Это можно сделать, заменив цикл DO в Р3 следующим:

   DO WHILE (CODE = OK); 
*     FETCH C1; 
      /* Вычислить новую зарплату для этого 
         служащего в программной переменной Z */ 
*     UPDATE EMP 
*        SET SAL = Z 
*        WHERE CURRENT OF C1; 
   END; 

Если в операторе модификации или удаления используется фраза WHERE CURRENT OF <имя-курсора>, в ней не должны присутствовать другие предикаты выбора. Ссылка на курсор не может использоваться в операторе INSERT, так как отношения являются неупорядоченными объектами, и, следовательно, вставка с помощью курсора не определена.

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

Р4. Предположим, что курсор С2 спозиционирован на некоторый кортеж в DEPT. Определить С5 как множество кортежей EMP, значение DNO которых соответствует кортежу в DEPT, на который указывает С2.

   LET C5 BE 
       SELECT * FROM EMP 
       WHERE DNO = DNO OF CURSOR C2 ON DEPT; 

Заметим, что CURRENT OF C2 обозначает реальный кортеж, на который указывает С2, но DNO = DNO OF CURSOR C2 – это условие поиска другого множества кортежей по соответствию значений. Фраза ON DEPT сообщает System R, что курсор С2 указывает на некоторый кортеж в DEPT. Этот факт может быть полезен при выборе пути доступа (например, может быть линк из DEPT к EMP по совпадению значений DNO). При использовании каждого из двух описанных типов ссылок на курсор позиция курсора не изменяется.

В SEQUEL 2 обеспечивается специальное средство EXECUTE, которое позволяет основной программе поддерживать интерактивных пользователей. Предположим, что программа во время выполнения читает с терминала текст оператора SEQUEL, который должен быть выполнен. Она может вызвать выполнение этого оператора, как показано в примере Р5.

Р5. Вызвать System R для выполнения оператора SEQUEL, текст которого находится в программной переменной QSTRING.

   EXECUTE QSTRING; 

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

P6. Прочитать текст запроса в переменную QSTRING и выбрать и отобразить результат запроса. (Звездочки обозначают SEQUEL; остальное – PL/1.)

   DISPLAY("ENTER QUERY") REPLY(QSTRING); 
*  LET C1 BE EXECUTE QSTRING; 
*  DESCRIBE C1 INTO <pointer-1>: 
   /* Отформатировать буфер для одного кортежа и 
      установить на него pointer-2 –
      объяснения приведены ниже. */
*  OPEN C1; 
   DO WHILE (CODE = OK); 
*     FETCH C1 INTO <pointer-2>; 
      /* Отобразить кортеж */ 
   END; 
*  CLOSE C1; 

В этой программе оператор LET C1 BE EXECUTE QSTRING связывает имя С1 с запросом, текст которого во время выполнения будет находиться в переменной QSTRING. Оператор DESCRIBE C1 возвращает описание числа полей и типов данных результата в массив, на который указывает <pointer-1>. Это позволяет программе выделить буферное пространство для хранения каждого поля результирующего кортежа. Затем программа образует массив указателей на эти буферы полей и устанавливает <pointer-2>, чтобы он указывал на этот массив. Оператор OPEN C1 подготавливает систему к доставке первого кортежа. Затем каждый оператор FETCH C1 размещает один кортеж в указанных буферах. После выполнения оператора CLOSE C1 в QSTRING может быть прочитан текст нового запроса. При последующем выполнение операторов DESCRIBE C1, OPEN C1 и FETCH C1 в них будет использоваться новый запрос.

При написании программы поддержки интерактивного пользователя программист должен проводить различие между операторами запросов (например, SELECT * FROM EMP) и другими операторами, которые не возвращают никакого результата (например, DELETE EMP WHERE EMPNO = 505). Для этого проверяется первое слово входной строки. Все запросы начинаются со слова SELECT и обрабатываются с помощью

   LET C1 BE EXECUTE QSTRING; 

Все операторы, не начинающиеся с SELECT, обрабатываются с помощью

   EXECUTE QSTRING; 

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

Р7. Присвоить активное множество курсора С5 новому отношению EXEMPT, которое имеет столбцы EMPNO, NAME и JOB.

   ASSIGN TO EXEMPT(EMPNO,NAME,JOB): CURSOR C5; 

Программа на PL/1 со встроенными операторами SEQUEL передается прекомпилятору System R. Все операторы SEQUEL распознаются и заменяются вызовами модуля времени выполнения, который выполняет эти операторы. Там, где это возможно, производится синтаксический разбор оператора SEQUEL, и оптимальный путь доступа выбирается для него во время прекомпиляции. Когда это невозможно, как в случае EXECUTE, синтаксический разбор и выбор пути доступа производятся во время выполнения.

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

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

Заключение

Мы описали подъязык данных SEQUEL 2, обеспечивающий согласованный, ориентированный на английские ключевые слова синтаксис для запросов, а также средств определения данных, манипулирования данными и контроля данных. Возможности SEQUEL 2 охватывают диапазон от средств запросов, в которых легко разобраться неспециалистам в обработке данных, до сложных средств, предназначенных для профессиональных программистов и администраторов баз данных. Мы продемонстрировали, как SEQUEL 2 может встраиваться в программу на PL/1 и как можно написать такую программу для поддержки SEQUEL 2 как автономного интерфейса для интерактивных пользователей. SEQUEL 2 является основным внешним интерфейсом экспериментальной системы баз данных System R. Хочется подчеркнуть, что System R и SEQUEL 2 – это части исследовательского проекта по управлению базами данных и не планируются как продукты IBM.

Приложение. Синтаксис SEQUEL 2

Здесь мы предлагаем упрощенную версию BNF-синтаксиса для SEQUEL 2. Акцент сделан на читаемости, а не на строгости, поэтому были допущены некоторые незначительные неоднозначности. Опущены некоторые возможности, которые присущи конкретно System R. Они относятся к массовой загрузке данных и управлению физическими сегментами. Кроме того, синтаксис допускает образование некоторых операторов, которые семантически бессмысленны. Более полный, но менее читаемый синтаксис используется в настоящее время в проекте System R.

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

statement ::= query
            | dml-statement
            | ddl-statement
            | control-statement
            | cursor-statement
dml-statement ::= assignment
                | insertion
                | deletion
                | update
query ::= query-expr [ ORDER BY ord-spec-list ]
assignment ::= ASSIGN TO receiver : query-expr
             | ASSIGN TO receiver : CURSOR cursor-name
receiver ::= table-name [ (field-name-list) ]
field-name-list ::= field-name
                  | field-name-list, field-name
insertion ::= INSERT INTO receiver : insert-spec
insert-spec ::= query-expr
              | lit-tuple
deletion ::= DELETE table-name [ var-name ] [ where-clause ]
update ::= UPDATE table-name [ var-name ]
             SET set-clause-list [ where-clause ]
where-clause ::= WHERE boolean
               | WHERE CURRENT OF cursor-name
set-clause-list ::= set-clause
                  | set-clause-list, set-clause
set-clause ::= field-name = expr
             | field-name = ( query-block )
query-expr ::= query-block
             | query-expr set-op query-block
             | ( query-expr )
set-op ::= INTERSECT | UNION | MINUS
query-block ::= select-clause [ INTO target-list ]
                       FROM from-list
                       [ WHERE boolean ]
                       [ GROUP BY field-spec-list
                       [ HAVING boolean ] ]
select-clause ::= SELECT [ UNIQUE ] sel-expr-list
                | SELECT [ UNIQUE ] *
sel-expr-list ::= sel-expr
                | sel-expr-list, sel-expr
sel-expr ::= expr
           | var-name.*
           | table-name.*
target-list ::= host-location
              | target-list, host-location
from-list ::= table-name [ var-name ]
            | from-list, table-name [ var-name ]
field-spec-list ::= field-spec
                  | field-spec-list, field-spec
ord-spec-list ::= field-spec [ direction ]
                | ord-spec-list, field-spec [ direction ]
direction ::= ASC | DESC
boolean ::= boolean-term
          | boolean OR boolean-term
boolean-term ::= boolean-factor
               | boolean-term AND boolean-factor
boolean-factor ::= [ NOT ] boolean-primary
boolean-primary ::= predicate
                  | ( boolean )
predicate ::= expr comparison expr
            | expr BETWEEN expr AND expr
            | expr comparison table-spec
            | < field-spec-list > = table-spec
            | < field-spec-list> [ IS ] [ NOT ] IN table-spec
            | IF predicate THEN predicate
            | SET ( field-spec-list ) comparison table-spec
            | SET ( field-spec-list ) comparison SET ( field-spec-list )
            | table-spec comparison table-spec
table-spec ::= query-block
             | ( query-expr )
             | literal
expr ::= arith-term
       | expr add-op arith-term
arith-term ::= arith-factor
                  | arith-term mult-op arith-factor
arith-factor ::= [ add-op ] primary
primary ::= [ OLD | NEW ] field-spec
          | set-fn ( [ UNIQUE ] expr )
          | COUNT ( * )
          | constant
          | ( expr )
field-spec ::= field-name
             | table-name.field-name
             | var-name.field-name
comparison ::= comp-op
             | CONTAINS
             | DOES NOT CONTAIN
             | [ IS ] IN
             | [ IS ] NOT IN
comp-op ::= = | ¬= | > | >= | < | <=
add-op ::= + |-
mult-op ::= * | /
set-fn ::= AVG | MAX | MIN | SUM | COUNT| identifier
literal ::= ( lit-tuple-list )
          | lit-tuple
          | ( entry-list )
          | constant
lit-tuple-list ::= lit-tuple
                 | lit-tuple-list, lit-tuple
lit-tuple ::= < entry-list >
entry-list ::= entry
                  | entry-list, entry
entry ::= [ constant ]
constant ::= quoted-string
           | number
           | host-location
           | NULL
           | USER
           | DATE
           | field-name OF CURSOR cursor-name ON table-name
table-name ::= name
image-name ::= name
link-name ::= name
asrt-name ::= name
trig-name ::= name
name ::= [ creator. ] idetifier
creator ::= identifier
user-name ::= identifier
field-name ::= identifier
var-name ::= identifier
cursor-name ::= identifier
pointer ::= identifier
save-point-name ::= identifier
host-location ::= identifier [ : identifier ]
integer ::= number
ddl-statement ::= create-table
                | expand-table
                | create-image
                | create-link
                | define-view
                | define-synonym
                | drop
                | comment
create-table ::= CREATE TABLE table-name ( field-defn-list )
field-defn-list ::= field-defn
                       | field-defn-list, field-defn
field-defn ::= field-name ( type [ , NONULL ] )
type ::= CHAR ( integer ) [ VAR ]
       | INTEGER
       | SMALLINT
       | DECIMAL ( integer, [ integer ] )
       | FLOAT
expand-table ::= EXPAND TABLE table-name ADD COLUMN field-defn
create-image ::= CREATE [ image-mod-list ] IMAGE image-name
                  ON table-name ( ord-spec-list )
image-mod-list := image-mod
                | image-mod-list image-mod
image-mod ::= UNIQUE
            | CLUSTERING
create-link ::= CREATE [ CLUSTERING ] LINK link-name        
                 FROM table-name ( field-name-list )
                 TO table-name ( field-name-list )
                 [ ORDER BY ord-spec-list ]
define-view ::= DEFINE VIEW table-name
                [ ( filed-name-list ) ] AS query
define-synonym ::= DEFINE SYNONYM identifier AS table-name
drop ::= DROP system-entity name
comment ::= COMMENT ON system-entity name : quoted-string
          | COMMENT ON COLUMN table-name.field-name : quoted-string
system-entity ::= TABLE | VIEW | ASSERTION | TRIGGER | IMAGE | LINK
control-statement ::= asrt-statement
                    | define-trigger
                    | grant
                    | revoke
                    | begin-trans
                    | end-trans
                    | save
                    | restore
asrt-statement ::= ASSERT asrt-name [ IMMEDIATE ]
                    [ ON asrt-condition ] : boolean
asrt-condition ::= action-list
                 | table-name [ var-name ]
action-list ::= action
              | action-list, action
action ::= INSERTION OF table-name [ var-name ]
         | DELETION OF table-name [ var-name ]
         | UPDATE OF table-name [ var-name ]
           [ ( filed-name-list ) ]
define-trigger ::= DEFINE TRIGGER trig-name
                    ON trig-condition : ( statement-list )
trig-condition ::= action
                 | READ OF table-name [ var-name ]
statement-list := cond-statement
                | statement-list; cond-statement
cond-statement ::= statement
                 | IF boolean THEN statement
grant ::= GRANT [ auth ] table-name TO user-list
           [ WITH GRANT OPTION ]
auth ::= ALL RIGHTS ON
       | operation-list ON
       | ALL BUT operation-list ON
user-list ::= user-name
            | user-list, user-name
            | PUBLIC
operation-list ::= operation
                 | operation-list, operation
operation ::= READ
            | INSERT
            | DELETE
            | UPDATE [ ( field-name-list ) ]
            | EXPAND
            | IMAGE
            | LINK
            | CONTROL
            | RUN
revoke ::= REVOKE [ operation-list ON ] table-name FROM user-list
begin-trans ::= BEGIN TRANSACTION
end-trans ::= END TRANSACTION
save ::= SAVE save-point-name
restore ::= RESTORE [ save-point-name ]
cursor-statement ::= let
                   | open
                   | fetch
                   | close
                   | describe
                   | execute
let ::= LET cursor-name BE query
      | LET cursor-name BE execute
open ::= OPEN cursor-name
fetch ::= FETCH cursor-name [ INTO pointer ]
close ::= CLOSE cursor-name
describe ::= DESCRIBE cursor-name INTO pointer
execute ::= EXECUTE host-location


Литература

  1. E.F.Codd, "A Relational Model of Data for Large Shared Data Banks", Communications ACM 13, 377 (июнь 1970). Есть русский перевод: Е.Ф.Кодд, "Реляционная модель данных для больших совместно используемых банков данных", СУБД N1, 1995.
  2. D.D.Chamberlin, R.F. Boyce, "SEQUEL : A Structured English Query Language", Proceedings of ACM-SIGFIDET Workshop, Ann Arbor, MI, май 1974.
  3. G.D.Held, M.R.Stonebraker, E.Wong, "INGRES : A Relational Data Base System", Proceedings of AFIPS National Computer Conference, Anaheim, CA, май 1975.
  4. M.M.Zloof, "Query By Example", Proceedings of AFIPS National Computer Conference, Anaheim, CA, май 1975.
  5. R.F.Boyce, D.D.Chamberlin, W.F.King, M.M.Hammer, "Specifying Queries as Relational Expressions: The SQUARE Data Sublanguage", Communications ACM 18, 621 ( Ноябрь 1975 ).
  6. P.Reisner, R.F.Boyce, D.D.Chamberlin, "Human Factors Evaluation of Two Data Base Query Languages: SQUARE and SEQUEL", Proceedings of AFIPS National ComputerConference, Anaheim, CA, май 1975.
  7. P.Reisner, "Use of Phychological Experimentation as an Aid to Development of a Query Language", Research Report RJ 1707, IBM Research Laboratory, San Jose, CA, январь 1976.
  8. M.M.Astrahan, et al., "System R: A Relational Approach to Data Base Management", ACM Transactions on Data Base Systems 1, 97 (июнь 1976).
  9. E.F.Codd, "Normalized Data Base Structure: A Brief Tutorial", Proceedings of ACM-SIGFIDET Workshop, San Diego, CA, Ноябрь 1971.
  10. R.Bayer, E.McCreight, "Organization and Maintenance of Large Ordered Indices", Proceedings of ACM-SIGFIDET Workshop, Houston, TX, ноябрь 1970.
  11. D.D.Chamberlin, J.N.Gray, L.L.Traiger, "Views, Authorization and Locking in a Relational Data Base System", Proceedings of AFIPS National Computer Conference, Anaheim, CA, май 1975.
  12. P.P.Griffits, B.W.Wade, "An Authorization Mechanizm for a Relational Data Base System", Proceedings of ACM SIGMOD Conference, Washington, DC, июнь 1976.
  13. K.P.Eswaran, D.D.Chamberlin, "Functional Specifications of a Sybsystem for Data Base Integrity", Proceedings of International Conference on Very Large Data Bases, Framingham, MA, сентябрь 1975.
  14. J.Mylopoulos, S.A.Schuster, D.Tsichrizis, "A Multi-level Relational System", Proceedings of AFIPS National Computer Conference, Anaheim, CA, май 1975.
Бесплатный конструктор сайтов и Landing Page

Хостинг с DDoS защитой от 2.5$ + Бесплатный SSL и Домен

SSD VPS в Нидерландах под различные задачи от 2.6$

✅ Дешевый VPS-хостинг на AMD EPYC: 1vCore, 3GB DDR4, 15GB NVMe всего за €3,50!

🔥 Anti-DDoS защита 12 Тбит/с!

VPS в 21 локации

От 104 рублей в месяц

Безлимитный трафик. Защита от ДДоС.

🔥 VPS до 5.7 ГГц под любые задачи с AntiDDoS в 7 локациях

💸 Гифткод CITFORUM (250р на баланс) и попробуйте уже сейчас!

🛒 Скидка 15% на первый платеж (в течение 24ч)

Новости мира IT:

Архив новостей

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 495 7861149
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2019 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...