Операции манипулирования данными
Выборка: Вот пример выборки на языке Alpha ("Получить имена поставщиков и названия городов для поставщиков, которые поставляют все детали"):
RANGE S SX
RANGE SP SPX
RANGE P PX
GET W1 (SX.SNAME, SX.CITY):
ALL PX SOME SPX (SPX.S# = SX.S# AND SPX.P# = PX.P#)
В этом примере W1 - имя применяемого рабочего пространства; двоеточие можно воспринимать как "где" или "такое, что", а ALL и SOME обозначают кванторы всеобщности и существования соответственно. В действительности, в [2] для ALL и SOME используются стандартные логические символы (как и для связок AND, OR и т.д.); в отличие от этого, в [1] применяются ключевые слова, что я предпочитаю. Согласно [2] кванторы можно переместить в объявления RANGE, например:
RANGE S SX
RANGE SP SPX SOME
RANGE P PX ALL
GET W1 (SX.SNAME, SX.CITY):
SPX.S# = SX.S# AND SPX.P# = PX.P#
Замечание: В [2] никогда не упоминается возможность определения переменной на области значений, являющейся, например, объединением двух базовых отношений, и вообще на чем-то более сложном, чем одно базовое отношение. (Я обсуждал эту возможность в своей заметке в прошлом месяце.) Кроме того, в ранней статье [1] использовалось ключевое слово DUMMY вместо RANGE в тех случаях, когда требуется разновидность "фиктивной" переменной (я также обсуждал это предыдущей заметке).
Операции GET также допускают:
Замечание: В исходной версии статьи упущен из вида тот факт, что, по крайней мере, для TOTAL и AVERAGE аргументом является мультимножество, а не множество (дубликаты не должны удаляться до выполнения агрегации). Позже Кодд признал эту ошибку [3].
Немного отходя от основной темы, замечу, что в Alpha прямо не допускается использование агрегатных функций в условии выборки; используется сокращенная версия, называемая функциями образов (которые могут также применяться и в списке выборки). Я опускаю здесь детали, хотя, если говорить честно, не думаю, что функции образов относятся к числу лучших идей Alpha. На самом деле, они могли быть источником странного синтаксиса вызова агрегатных функций и в QUEL, и в SQL и сложности обоих языков, связанной с этим неортодоксальным синтаксисом. (Эти сложности порождаются тем фактом, что аргументы функции частично определяются контекстом вместо того, чтобы -- что было бы более ортодоксально -- полностью определяться тем, что содержится в скобках, непосредственно следующих за именем функции [7,8].)
В Alpha также допускается покортежное выполнение выборки в конвейерном режиме (аналогично FETCH через курсор в языке SQL). Например (в предположении тех же, что и раньше определений RANGE):
OPEN GET W1 (SX.SNAME, SX.CITY):
SPX.S# = SX.S# AND SPX.P# = PX.P# UP SX.CITY
GET W1
/* теперь текущая строка обрабатывается программой на основном языке */
.…
CLOSE W1
Здесь при каждом выполнении GET W1 из результата запроса в OPEN выбирается следующий кортеж. (Обратите внимание на спецификация упорядочения UP в этом OPEN.) Конечно, конвейерный режим открывает возможность дискредитации системы, поскольку его можно использовать для выполнения того, что по существу является "ручной навигацией" (вместо автоматической навигации, обычно являющейся предпочтительной в реляционной системе) [4]. Но конвейерный режим или что-то в этом роде является существенным, если язык, как в случае Alpha, - это подъязык данных.
Вставка: Операция PUT пересылает набор кортежей из указанного рабочего пространства в указанное отношение.
Например:
PUT W2 SP
(" Вставить кортежи из рабочего пространства W2 в отношение SP".) Можно также указать и порядок, чтобы дать знать системе, что вставляемые кортежи упорядочены некоторым образом в рабочем пространстве. На самом деле, в связи с этим понятием я ощущаю небольшой дискомфорт; мне кажется, что здесь слишком сильно перемешаны идеи логического и физического уровней.
Возможна также "конвейерная вставка":
OPEN PUT W2 S
….
/* конструирование текущей строки программой на основном языке */
PUT W2
….
CLOSE W2
Обновление: Вот пример обновления данных ("Переместить всех парижских поставщиков в Рим"):
HOLD W3 (SX.S#, SX.CITY): SX.CITY = 'Paris'
/* установить значение 'Rome' столбца CITY в каждом кортеже */
/* рабочего пространства с использованием основного языка */
UPDATE W3
В языке Alpha требуется, чтобы обновляемые строки были сначала выбраны с помощью HOLD. (Отсутствует аналог беззаботного "поискового UPDATE" языка SQL.) Целевой список HOLD должен содержать в точности одну переменную с областью значений, что означает, что UPDATE будет применяться только к одному (базовому) отношению. (Как говорит Кодд, "[ограничение одной переменной с областью определения] позволяет избежать неоправданной сложности". И всего-то!) Если пользователь решит после всего не выполнять UPDATE, то может быть выполнена операция RELEASE W3, чтобы освободить сохраняемые кортежи.
Замечание: Хотя в [2] это не говорится, целевой список HOLD должен включать все атрибуты первичного ключа обновляемого отношения, чтобы система могла узнать, какие кортежи вы обновляете [3]. Сами атрибуты первичного ключа не могут напрямую обновляться с помощью последовательности HOLD…UPDATE, но для достижения аналогичного эффекта можно использовать удаления и вставки.
Для HOLD…UPDATE/RELEASE также возможен конвейерный режим (аналогично UPDATE CURRENT в языке SQL). Странно, что нет аналога DELETE CURRENT. Однако это упущение не является важным, поскольку -- как я утверждаю в [9] -- идея обновления или удаления (а также и вставки) одного кортежа в любом случае является плохой.Операции обновления следует всегда выполнять над множествами.
Вероятно, можно сказать, что части Alpha, связанные с модификацией, не относятся к сильным сторонам языка; действительно приведенное обсуждение порождает много вопросов, которые просто не затрагиваются в статье.
Удаление: Операция DELETE в основном проста, если оставить в стороне приведенную ранее критику, применимую к операциям модификации в целом. Вот пример:
DELETE SX: SX.S# = 'S1'
В своей следующей заметке я завершу обсуждение подъязыка данных Alpha.