Классика баз данных - статьи

       

Операции манипулирования данными


Выборка: Вот пример выборки на языке 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 также допускают:

  • Ссылки на отношения в рабочих пространствах, как если бы они были в базе данных. В таких ссылках используются имена рабочих пространств как если бы они были именами отношений.
  • Спецификация упорядочения результата (аналогично ORDER BY в языке SQL) с использованием ключевых слов UP и DOWN.
  • Спецификация квоты для ограничения числа выбираемых кортежей. Однако в статье не рассматривается вопрос о том, что должно произойти, если результирующее отношение определяется неоднозначно [10].
  • Использование некоторых истинностных функций (TOP и BOTTON). TOP и BOTTON - это аналоги Alpha описанных в [10] функций IS_NTH_LARGEST и IS_NTH_SMALLEST.
  • Использование некоторых агрегатных функций (COUNT, TOTAL, MAX, MIN, AVERAGE в целевом списке (однако термин "агрегатные функции" не используется).


    Замечание: В исходной версии статьи упущен из вида тот факт, что, по крайней мере, для 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.


    Содержание раздела