Скачиваний:
147
Добавлен:
02.05.2014
Размер:
2.66 Mб
Скачать

Глава 5

Домены, отношения и базовые переменные- отношения

5.1. Введение

Как упоминалось в главе 3, реляционная модель состоит из трех основных частей, ка- сающихся структуры, целостности данных и манипулирования ими соответственно. Каж- дая часть имеет свою терминологию. Наиболее важные термины описания структуры данных представлены на рис. 5.1 (на нем показано отношение поставщиков для базы дан- ных поставщиков и деталей (см. рис. 3.8), расширенное таким образом, чтобы были видны используемые типы данных и домены). Терминами здесь являются отношение, кортеж, кардинальность (количество записей), атрибут, степень, домен и первичный ключ.

Домены

Первичный ключ

g 3

Рис. 5.1. Термины, используемые для описания структуры данных

Термины отношение и первичный ключ уже должны быть вам знакомы из главы 3. Сейчас мы объясним значения остальных терминов на понятийном уровне, а затем в со- ответствующих разделах дадим их более формальные определения. Итак, если рассмат-

ривать отношение как таблицу, то кортежам будут соответствовать строки этой табли- цы, а атрибутам — ее столбцы. Количество кортежей в таблице называется ее карди- нальностью, а количество атрибутов — степенью. Домен — это совокупность значе- ний, из которой берутся значения для определенных атрибутов определенного отноше- ния. Например, домен, обозначенный на рис. 5.1 как Si, — это множество всех допусти- мых номеров поставщиков, и каждое значение, принимаемое атрибутом Si, принадлежит этому множеству (аналогично каждое значение атрибута Si в отношении поставок (см. рис. 3.8) также принадлежит этому множеству).

Все сказанное ранее подытожено на рис. 5.2. Однако следует отметить, что эти поня- тия "эквивалентны" показанным на рисунке только приблизительно (и каждый из терми- нов имеет точное определение). Так, "отношение" и "таблица" — это не одно и то же, хотя, как вы знаете из части I, на практике данные понятия часто отождествляются.

Формальный^еляционный термин

Неформальный эквивалент

отношение кортеж

кардинальность

атрибут

степень

первичный ключ домен

таблица

строка или запись количество строк столбец или поле количество столбцов уникальный идентификатор совокупность допустимых значений

Рис. 5.2. Термины, использующиеся для описания структуры таблиц баз данных

5.2. Домены

Домен -— это не что иное, как тип данных (или, для краткости, — просто тип); в частности, возможно, простой, определяемый системой, подобно типам INTEGER и CHAR. В общем случае этот тип определяется пользователем, как, например, типы Si, Pi, WEIGHT и QTY в базе поставщиков и деталей. В действительности термины домен и тип данных взаимозаменяемы, и в этой книге будут использоваться оба термина (хотя нам больше нравится термин тип; термин домен будет употребляться, в основном, как дань истории).

Итак, что же такое тип? Прежде всего, это множество значений — всех возможных значений рассматриваемого типа. Например, тип INTEGER — это множество всех целых чисел, тип Si — множество всех номеров поставщиков и т.д. Говоря о каком-либо типе данных, мы не должны также забывать о допустимых операторах, которые могут кор- ректно применяться к значениям этого типа. Другими словами, значениями заданного типа можно манипулировать только с помощью операторов, определенных для этого типа. Рассмотрим, например, тип INTEGER (который для простоты будем считать опреде- ляемым системой).

  • Для сравнения целых чисел системой предоставляются операторы "=", "<" и т.д.

  • Арифметические действия над целыми числами выполняются с помощью опера- торов "+", "*" и т.д.

■ Этот тип данных не поддерживает такие операторы, как "| |" (конкатенация), SUBSTR (выделение подстроки) и т.д. Другими словами, операторы манипулирова- ния строками к целым числам неприменимы.

Многие системы позволяют определять собственные типы, как, например, тип St. Возможно, нам понадобится определить операторы "=" и "<" для сравнения номеров по- ставщиков. С другой стороны, для данного типа наверняка не потребуется определять операторы "+" и "*". Это означает, что выполнение арифметических действий над номе- рами поставщиков поддерживаться не будет (действительно, зачем может потребоваться складывать или перемножать номера поставщиков?).

Тем не менее следует различать типы данных сами по себе и физическое пред- ставление значений этих типов внутри системы2. (Фактически типы являются моде- лями, в то время как физическое представление значений — это их реализация.) На- пример, номера поставщиков физически могут быть представлены как символьные строки, однако это не значит, что над ними можно выполнять те же операции, что и над строками. Выполнение любых операций возможно лишь в том случае, если для за- данного типа были определены соответствующие операторы. И безусловно, опреде- ляемые для заданного типа операторы должны зависеть от реального смысла или се- мантики рассматриваемого типа и ни в коем случае не от его физической реализации. Более того, физическое представление типа должно быть скрыто настолько, насколь- ко в этом заинтересован пользователь.

К настоящему моменту вы, должно быть, уже догадались, что предметом нашего об- суждения является то, что в программировании называется строгим контролем типов или строгой типизацией. Разные авторы определяют этот термин несколько по- разному. Мы же дадим ему следующее определение: строгий контроль типов имеет ме- сто, если каждое значение принадлежит какому-либо типу и при выполнении любой операции система проверяет, принадлежит ли каждый из операндов этой операции до- пустимому для нее типу. Рассмотрим, например, следующие выражения.

P.WEIGHT + SP.QTY /* Вес детали плюс количество деталей */

P.WEIGHT * SP.QTY /* Вес детали, умноженный на количество деталей */

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

Ниже приводится еще один пример, на этот раз для операторов сравнения (в частно- сти, для оператора равенства).

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


P.WEIGHT = SP.QTY P.CITY = S.CITY

И в этом случае первое выражение, в отличие от второго, смысла не имеет. Таким об- разом, оператор "=" для веса и количества деталей (в сочетании) определять наверняка не следует, тогда как для сравнения городов он, скорее всего, понадобится3. (Здесь мы придерживаемся мнения, высказанного в [3.3] и состоящего в том, что для каждого типа должен быть определен оператор "=", поскольку всегда должна существовать возмож- ность проверки, совпадают ли два заданных значения одного и того же типа.)

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

Вышесказанное имеет очень большое значение и очень часто понимается неправиль- но, поэтому мы выскажем эту мысль еще раз другими словами.

Вопрос о том, какие типы данных поддерживаются, ортогонален вопросу о поддержке реляционной модели.

Каждое значение имеет тип

Каждое значение данных обязательно имеет некоторый тип. Другими словами, если v— значение, то оно как бы обладает неким признаком, который гласит: "Я— целое число" или "Я — номер поставщика", или "Я — геометрическая точка". Заметьте, что по определению заданное значение обязательно принадлежит лишь одному типу4 и никогда не может изменить свой тип (отсюда следует, что разные типы данных никогда не пере- секаются, т.е. не имеют общих значений).

Каждый тип данных может быть либо скалярным, либо нескалярным. Нескалярны- ми являются все типы, явно определенные таким образом, что в них есть компоненты, видимые для пользователя. В частности, в этом смысле нескалярными являются типы отношений. Например, отношение, представленное на рис. 5.1, принадлежит определен- ному типу и этот тип, несомненно, имеет видимые компоненты (а именно — атрибуты St, SNAME, STATUS и CITY). Скалярные же типы, напротив, видимых пользователю ком- понентов не имеют. Подведем итоги.

* В отношении вопроса о том, какие операторы и для каких типов являются допустимыми, нами замечено, что исторически в большинстве изданий по базам данных, в том числе в несколь- ких первых изданиях этой книги, рассматриваются операторы сравнения (">", "=" и т.д.) и не рассматриваются другие операторы, подобные "*" и "+".

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

1. В оставшейся части этого раздела все рассматриваемые типы будут скалярными, и поэтому, употребляя термин тип, мы будем подразумевать именно скалярный тип.

  1. Физическое представление заданного скалярного значения, т.е. заданное значение за- данного скалярного типа, может быть произвольно сложным. В частности, оно может быть составным (однако его компоненты не могут быть видимы пользователю). На- пример, при определенных обстоятельствах заданное скалярное значение может иметь физическое представление в виде массива стеков списков символьных строк.

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

  3. Как вы вскоре убедитесь, скалярные типы имеют так называемые допустимые представления, а допустимые представления, в свою очередь, обязательно имеют видимые компоненты. Обратите внимание на то, что в данном случае видимые компоненты являются компонентами не типа, а его допустимого представления. Тип данных всегда остается скалярным в смысле приведенного выше определения.

Определение типа

В этой книге мы часто будем использовать язык Tutorial D (вернее, некоторую его версию), впервые применявшийся в главе 3 для иллюстрации излагаемых в ней идей. В общих чертах язык Tutorial D напоминает язык Pascal. Мы будем знакомить вас с этим языком по мере его использования. Первое, для чего он нам потребуется, — для получе- ния средства определения собственных типов.

TYPE <имя типа> <возможное представление>

(CHAR) ; (CHAR) ; (CHAR) ; (CHAR) ; (RATIONAL) ; (INTEGER) ;

В качестве примера рассмотрим определения типов для базы данных поставщиков и деталей (см. рис. 3.9).

TYPE St POSSREP

TYPE NAME POSSREP

TYPE Pt POSSREP

TYPE COLOR POSSREP

TYPE WEIGHT POSSREP

TYPE QTY POSSREP

Пояснения

  1. Поскольку из главы 3 следует, что атрибут поставщиков STATUS и атрибут поставщи- ков и деталей CITY определяется с помощью встроенных типов, а не типов, опреде- ленных пользователем, определение типов для указанных атрибутов отсутствует.

  2. Как мы уже видели, физическое представление типа скрыто от пользователя. Соот- ветственно приведенные выше определения типов не содержат никакой информации об их физическом представлении. Фактически эти представления должны задаваться как часть отображения "концептуальный-внутренний" (см. главу 2, раздел 2.6).

Обязательным является наличие у каждого типа данных хотя бы одного допусти- мого представления по причине, рассматриваемой в следующем разделе. Напри- мер, значения типов St, NAME, Pt и COLOR можно представить в виде строк симво- лов, а значение типа WEIGHT — в виде рационального числа.

Замечание. В этой книге (следуя рекомендациям из [3.3]) вместо привычного на- звания встроенного типа REAL будет использоваться более точное название — RATIONAL.

  1. Здесь принимаются очевидные синтаксические соглашения, суть которых состоит в следующем: неименованные допустимые представления наследуют имя соответст- вующих типов, а компоненты неименованных допустимых представлений насле- дуют имена соответствующих представлений. Например, единственное допустимое представление, определенное для типа QTY, также называется QTY; то же самое от- носится к единственному компоненту данного возможного представления.

  2. При определении нового типа система делает в каталоге запись, содержащую опи- сание этого типа (чтобы вспомнить некоторые детали, касающиеся каталогов, воз- вратитесь к разделу 3.6 главы 3). То же самое происходит при определении опера- тора (об этом рассказывается в двух следующих разделах).

  3. Возможно, вы заметили, что в приведенных выше определениях типов не задаются фактические значения, составляющие конкретный тип. Эту функцию выполняют наложенные на тип ограничения (то, что находится в круглых скобках в приведен- ном выше примере описания типов), которые будут рассмотрены в главе 8.

Если какой-либо тип данных больше не нужен, от него, конечно же, можно избавиться.

DROP TYPE <иыя maa> ;

В приведенном выше операторе параметр <имя игоа> должен задавать имя типа дан- ных, определенного пользователем, но не имя какого-либо встроенного типа. В резуль- тате выполнения этого оператора из каталога удаляется запись, описывающая рассмат- риваемый тип данных, после чего он перестает быть известным системе.

Замечание. Для простоты будем считать, что оператор DROP TYPE не выполняется, ес- ли удаляемый тип данных в текущий момент где-либо используется, например если на основе этого типа определен атрибут некоторого отношения.

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

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

TYPE POINT /* геометрические точки */

POSSREP CARTESIAN ( X RATIONAL, Y RATIONAL ) POSSREP POLAR ( R RATIONAL, THETA RATIONAL ) ;

В первую очередь, следует отметить, что тип POINT имеет два разных допустимых представления, CARTESIAN и POLAR, отображающих тот факт, что точку на плоскости можно задать либо в декартовых, либо в полярных координатах. (Безусловно, физиче- ское представление этого типа в конкретной системе на самом деле может быть выпол- нено в декартовых координатах, в полярных координатах или посредством некоторого

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

При каждом объявлении допустимого представления автоматически5 определяются два более или менее очевидных оператора.

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

  • Набор операторов THE (по одному оператору для каждого компонента допусти- мого представления), обеспечивающих доступ к соответствующему компоненту данного допустимого представления.

Рассмотрим на примере использование оператора выбора и оператора ТНЕ_ для ти- па POINT.

CARTESIAN j 5.0, 2.5 ) /* Задает точку с координатами х = 5.0, у = 2.5 */ CARTESIAN ( XXX, YYY ) /* Задает точку с координатами х = XXX, у = YYY */

/* Здесь XXX и YYY - переменные типа RATIONAL */ POLAR ( 2.7, 1.0 ) /* Задает точку с г = 2.7 и theta = 1.0 */

ТНЕ_Х ( Р ) /* Возвращает координату х точки Р */

/* Здесь Р - переменная типа POINT */ THE_R ( Р ) /* Возвращает координату г точки Р */

Замечание. Очевидным является тот факт, что оператор выбора— это обобщение уже знакомого нам понятия литерал (literal).

Для того чтобы увидеть, как все вышесказанное работает на практике, будем считать, что физическим представлением значения типа POINT являются фактические декартовы координаты точки (хотя в общем случае физическое представление может быть произ- вольным). Кроме того, допустим, что для описания этого физического представления системой предоставляются специальные защищенные операторы (выделенные курсивом), которые затем будут использованы определителем типа для реализации операторов вы- бора6 CARTESIAN и POLAR, как, например, показано ниже.

OPERATOR CARTESIAN ( X RATIONAL, Y RATIONAL ) RETURNS ( POINT ) ; BEGIN;

VAR P POINT;

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

^ Очевидно, что определитель типа является исключением из общего правила, гласящего, что пользователи не осведомлены о физическом представлении типа.


Х-компонент физического представления P := X ; Y-компонент физического представления Р := Y ;

RETURN ( P ) ; END ; END OPERATOR ;

OPERATOR POLAR ( R RATIONAL, THETA RATIONAL ) RETURNS ( POINT ) ; RETURN ( CARTESIAN ( R * COS ( THETA ),

R * SIN ( THETA ) ) ) ;

END OPERATOR ;

Обратите внимание на то, что при определении оператора POLAR используется опера- тор выбора CARTESIAN, а также встроенные операторы SIN и COS. Оператор POLAR можно определить и по-другому, непосредственно с помощью защищенных операторов.

OPERATOR POLAR ( R RATIONAL, THETA RATIONAL ) RETURNS( POINT ) ; BEGIN;

VAR P POINT ;

Х-компонент физического представления P := R * COS ( THETA ) ; Y-компонент физического представления P := R * SIN ( THETA ) ; RETURN ( P ) ; END ; END OPERATOR ;

Защищенные операторы используются также определителем типа для реализации не- обходимых операторов ТНЕ_.

OPERATOR ТНЕ_Х ( Р POINT ) RETURNS ( RATIONAL ) ;

RETURN ( -компонент физического представления Р ) ; END OPERATOR ;

OPERATOR ТНЕ_У ( Р POINT ) RETURNS ( RATIONAL ) ;

RETURN ( "Y-компонент физического представления Р ) ; END OPERATOR ;

OPERATOR THE R ( P POINT ) RETURNS ( RATIONAL ) ; RETURN ( SQRT ( THE_X ( P ) ** 2+ THE_Y ( P ) ** 2 ) ) ; END OPERATOR ;

OPERATOR THE THETA ( P POINT ) RETURNS ( RATIONAL ) ;

RETURN ( ARCTAN ( THE Y ( P ) / THE X ( P ) ) ) ; END OPERATOR ;

Здесь при определении операторов THE R и THE_THETA используются операторы THE X и THE Y, а также (встроенные по предположению) операторы SQRT и ARCTAN. Операторы THE_R и ТНЕ_ТНЕТА также можно определить непосредственно в терминах защищенных операторов. Предлагаем читателю сделать это самостоятельно в качестве упражнения.

На этом наше пространное обсуждение типа POINT можно считать завершенным. Од- нако следует понимать, что все вышесказанное применимо и к более простым типам, на- пример к таким, как тип QTY. Вот несколько примеров использования оператора выбора для этого типа.

QTY (100)

QTY (Q)

QTY ( ( Ql - Q2 ) * 2 )

Операторы THE_ этого типа могут использоваться следующим образом, THE_QTY ( Q )

THE_QTY ( ( Ql - Ql ) * 2 )

Отметим, в частности, что, поскольку каждое значение всегда принадлежит ка- кому-либо типу, совершенно некорректно говорить, например, что количество дета- лей определенной поставки равно 100. Количество деталей — это значение типа QTY, а не INTEGER! В этом случае более правильно было бы сказать, что количество дета- лей равно QTY(IOO), а не просто 100. В неформальном контексте мы часто не забо- тимся о такой точности и употребляем число 100 как удобное сокращение для опе- ратора выборки QTY(IOO)7. В частности, подобные сокращения использовались на рис. 3.8 (база данных поставщиков и деталей) и на рис. 4.5 (база данных поставщи- ков, деталей и проектов).

В завершение приведем пример определения типа LINESEG (отрезок).

TYPE LINESEG POSSREP ( BEGIN POINT, END POINT ) ;

Допустимые представления можно, конечно же, определять не только в терминах встроенных типов (как во всех предыдущих примерах), но и с помощью типов, опреде- ленных пользователем, так как это сделано в данном случае.

Определение операторов

В этом разделе особое внимание будет уделено определению операторов. Для этого рассмотрим еще несколько примеров. В первом примере определяется пользовательский оператор для встроенного типа RATIONAL.

OPERATOR ABS ( Z RATIONAL ) RETURNS ( RATIONAL ) ; RETURN(CASE

WHEN Z > 0.0 THEN +Z WHEN Z < 0.0 THEN -Z END CASE ) ; END OPERATOR ;

7 В контексте языка SQL мы делаем то же самое, но по другой причине, а именно — потому, что в языке SQL не поддерживаются (пока) типы, определенные пользователем (см. приложе- ние Б).

Оператор ABS (модуль числа) определен для одного параметра Z типа RATIONAL и воз- вращает значение того же типа (другими словами, такое выражение, как ABS (АМТ1 - АМТ2), принадлежит типу RATIONAL).

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

OPERATOR DIST ( PI POINT, P2 POINT ) RETURNS ( LENGTH ) ; RETURN ( WITH THE X( Pi ) AS XI , THE~X( P2 ) AS X2 , THE~Y( PI ) AS Yl , THE_Y( P2 ) AS Y2 : LENGTH ( SQRT ( ( XI - X2 ) ** 2 + ( Yl - Y2 ) ** 2 ) ) ) ; END OPERATOR ;

Здесь предполагается, что LENGTH — это определенный пользователем тип с допусти- мым представлением RATIONAL. Обратите внимание на то, что для использования в соот- ветствующих выражениях сокращенных имен употребляется предложение WITH.

В следующем примере рассмотрен оператор равенства "=" для типа POINT.

OPERATOR EQ ( PI POINT, P2 POINT ) RETURNS ( BOOLEAN ) ; RETURN { THE X ( PI ) = THE_X ( P2 ) AND THE~Y ( PI ) = THE Y ( P2 ) ) ; END OPERATOR ;

Обратите внимание, что в выражении оператора RETURN используется встроенный оператор "=" для типа RATIONAL. Далее с целью упрощения будем считать, что обычное инфиксное обозначение "=" используется для оператора равенства (для всех типов, в ча- стности и для типа POINT). Практическое определение данного инфиксного обозначения рассматриваться не будет, поскольку это всего лишь вопрос синтаксиса.

Оператор "<" для типа QTY определяется следующим образом.

OPERATOR LT (Ql QTY, Q2 QTY ) RETURNS ( BOOLEAN ) ;

RETURN ( THE_QTY ( Ql ) < THE QTY ( Q2 ) ) ; END OPERATOR ;

Здесь в выражении оператора RETURN используется встроенный оператор "<" для типа INTEGER. И опять же, с этого момента и далее будем считать, что обычное инфиксное обозначение "<" используется для этого оператора по отношению ко всем "упорядоченным" типам, каковым, в частности, является и тип QTY. (По определению упорядоченным типом называется тип, для которого применим оператор "<". Про- стейшим примером неупорядоченного типа может служить тип POINT.)

Рассмотрим пример определения оператора обновления (во всех предыдущих приме- рах операторы были операторами считывания)*. Мы увидим далее, что в теле определе- ния таких операторов вместо слова RETURNS используется слово UPDATES. Операторы об- новления значений не возвращают и должны активизироваться с помощью явных вызо- вов CALL [3.3].

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

OPERATOR REFLECT ( P POINT ) UPDATES ( P ) ; BEGIN ;

THE X ( P ) := - THE X ( P ) ; THE~Y ( P ) := - THE~Y ( P ) ; RETURN ; END ; END OPERATOR ;

Оператор REFLECT отображает точку с декартовыми координатами (х,у) симметрично относительно начала координат в точку (-х,-у), модифицируя соответствующим обра- зом координаты исходной точки. Обратите внимание на использование в этом примере выражений вида ТНЕ_псевдопеременная. ТНЕ_псевдопеременная — это обращение опе- ратора ТНЕ_ к точке назначения (в частности, слева от оператора присвоения). Такое об- ращение оператора фактически не возвращает, а назначает значение указанному компо- ненту своего аргумента. Например, в определении оператора REFLECT выражение ТНЕ_Х ( Р ) :=...; фактически присваивает компоненту X некоторое значение (допустимого декартова представления) аргумента-переменной, представленной параметром Р. Разу- меется, для изменения любого аргумента с помощью оператора обновления, в частности путем присвоения значения выражению THE псевдопеременная, этот аргумент следует определить как переменную, а не как более общее выражение.

Ниже показано, что псевдопеременные могут быть вложенными.

VAR LS LINESEG ;

ТНЕ_Х ( THE_BEGIN ( LS ) ) :- 6.5 ;

Наконец, от ненужного оператора можно избавиться, как, например, показано ниже. DROP OPERATOR REFLECT ;

Однако удаляемый таким образом оператор не может быть встроенным.

Преобразование типов

Еще раз рассмотрим следующее определение типа данных. TYPE Si POSSREP ( CHAR ) ;

По умолчанию допустимое представление этого типа унаследует имя Si, а значит, данное имя получит и соответствующий оператор выбора. Таким образом, следующее выражение будет корректным.

si ( 'si' )

Оно возвращает номер определенного поставщика. Обратите внимание на то, что оператор выбора Si можно рассматривать как оператор преобразования типа, который преобразует строки в номера поставщиков. Аналогично оператор выбора Pi можно рас- сматривать как оператор преобразования строк в номера деталей, а оператор выбора QTY — как оператор преобразования целых чисел в количество деталей и т.д.

В главе 3 приводилось несколько примеров, в которых строки сравнивались с номе- рами деталей. Например, в упр. 3.4 присутствует следующее выражение.

...WHERE Pi = 'Р2'

Левая часть этого сравнения принадлежит типу Р#, а правая имеет тип CHAR. Поэтому при сравнении (фактически во время компилирования) должна возникнуть ошибка не- совпадения типов. Однако с концептуальной точки зрения система может "догадаться", что для преобразования значения в правой части сравнения (тип CHAR) в тип Pt можно использовать "оператор преобразования" Pt. В этом случае система перепишет преды- дущее выражение следующим образом.

...WHERE Pt = Pt ('Р2' )

Теперь операция сравнения является корректной.

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

  • Величины, расположенные слева и справа от операторов "<", ">" и "=", должны быть одного и того же типа.

  • Величины, расположенные слева и справа от оператора присвоения ":=", должны быть одного и того же типа.

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

CAST_AS_RATI0NAL ( 5 )

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

Заключительные замечания

Из всего вышесказанного о поддержке типов данных можно сделать несколько выво- дов. Наиболее важные из них приводятся ниже.

  • Во-первых, наиболее важно то, что теперь система может определить, какие вы- ражения являются допустимыми, а какие нет, и установить тип результата выполнения любого допустимого выражения.

  • Во-вторых, общая совокупность всех типов данных определенной базы данных является замкнутым множеством. Это означает, что тип результата выполнения любого допустимого выражения принадлежит этой совокупности. В частности, если операторы сравнения являются допустимыми, то этому замкнутому множе- ству обязательно должен принадлежать тип boolean или значение true!

  • В-третьих, тот факт, что системе известны типы результатов выполнения всех до- пустимых выражений, означает, в частности, что системе известно и то, какие операции присвоения и сравнения допустимы.

В завершение этого раздела приведем важный факт, который пригодится нам в буду- щем. Мы сказали, что домен — это тип данных, системный или определенный пользовате- лем, с произвольной внутренней структурой и что к значениям этого типа применимы только определенные для него операторы (внутреннее представление типа скрыто от поль- зователя). Теперь, если переключиться на объектно-ориентированные системы, можно обнаружить, что фундаментальное понятие таких систем, класс объектов, — это тип дан- ных, системный или определенный пользователем, с произвольной внутренней структурой и что к значениям этого типа применимы только определенные для него операторы (внутреннее представление типа скрыто от пользователя)... Другими словами, домены и классы объектов — это одно и то же\ Данный факт является звеном, связующим две тех- нологии — объектную и реляционную. Подробно этот важный вопрос изучается в главе 25.

Соседние файлы в папке Дейт К. Дж. Введение в системы баз данных [7 издание]