Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
66
Добавлен:
10.02.2015
Размер:
206.85 Кб
Скачать

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

Языки запросов первого типа – алгебраические языки, основаные на классической теории множеств (с некоторыми уточнениями), которые позволяют выражать запросы средствами специализированных операторов, применяемых к отношениям. Языки запросов второго и третьего типов – языки исчисления, которые основаны на классическом логическом аппарате исчисления предикатов первого порядка и позволяют выражать свойства желаемого результата, фактически не указывая, как его получить. Оба механизма (алгебра и исчисление) обладают важным свойством: они замкнуты относительно понятия отношения. Это означает, что выражения реляционной алгебры и формулы реляционного исчисления определяются над отношениями реляционных БД и результатом таких вычислений также являются отношения. В результате любое выражение или формула могут пониматься как отношения. Языки этих трех типов были предложены Е.Ф. Коддом и служат теоретической основой для описания действий, выполняемых над отношениями. Определенные в них элементарные операции реализуются в любом реальном языке запросов независимо от его внешнего оформления.

Конкретный язык манипулирования реляционными БД (SQL, QBE и др.) называется реляционно полным, если любой запрос, выраженный с помощью одного выражения реляционной алгебры или одной формулы реляционного исчисления, может быть выражен с помощью одного оператора языка. При этом для любого допустимого выражения реляционной алгебры можно построить эквивалентную формулу реляционного исчисления, и наоборот, то есть эти механизмы эквивалентны.

Рассмотрим реализацию запросов с использованием языков реляционного исчисления кортежей и реляционной алгебры на конкретном примере:

БАЗА ДАННЫХ.

Предприятие занимается сборкой изделий из покупных деталей и заключает договора с поставщиками на поставку этих деталей. В период действия договора поставщик поставляет детали не обязательно «все за раз», а обычно партиями.

Таблица ПОСТАВКИ (PST) содержит сведения о партиях поставленных деталей: «кто» (KPst: код поставщика)

«что» (KDet: код детали)

«в каком количестве» (Kol: количество)

«когда» поставил (DtP: дата поставки).

Таблица ПОСТАВЩИКИ (PSTS):

код поставщика (KPst - уникальный ключ),

наименование поставщика (ImPst),

адрес поставщика (AdrPst).

Таблица ДЕТАЛИ (DET):

код детали (KDet - уникальный ключ),

наименование детали (ImDet),

цвет детали (Cvet).

Таблица ДОГОВОРА (DOG) содержит сведения о том «кто» - «что» - «в каком количестве» обязался поставить, и имеет поля

код поставщика (KPst),

код детали (KDet),

количество (Kol),

дата начала договора (DtN),

дата завершения договора (DtK).

(KPst, KDet) – уникальный (составной) ключ этой таблицы.

Реляционное исчисление кортежей строит правильные отношения путем описания условий, которым должны удовлетворять составляющие их кортежи. Условия описываются с помощью формул, которые имеют вид: . Здесь - переменная, обозначающая некоторый кортеж, а - предикат от той переменной. Формула исчисления кортежей описывает множество всех таких кортежей , для которых предикат принимает значение истина.

  1. Дан запрос в реляционном исчислении кортежей:

НАЙТИ{(de.ImDet)/deDet}:

(doDog)((do.DtN<=’10.10.2006’  do.KDetde.KDet)

(psPsts)((ps.KPst=do.KPst)(ps.AdrPst’Казань’))

(pvPst)((pv.KPst=do.KPst)(pv.KDet=do.KDet)))

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

  • Составить две программы решения этой задачи:

  • SELECT-оператором на языке SQL.

  • PASCAL(С++)-программу с использованием средств обработки баз данных.

В первой задаче необходимо найти формулировку исходной задачи на естественном языке. Попытка построчной расшифровки приведенного предиката приводит к очень громоздкой и малопонятной формулировке задачи:

Найти все наименования деталей, что для каждого договора выполняются условия: или договор датирован до 10.10.2006, или предметом договора является другая деталь, или в договоре прописан не Казанский поставщик, или существуют поставки деталей по договору.

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

Введем следующие обозначения:

(do.DtN<=’10.10.2006’)

=(do.KDetde.KDet)

(psPsts)(( ps.KPst=do.KPst)(ps.AdrPst’Казань’))

=(pvPst)((pv.KPst=do.KPst)(pv.KDet=do.KDet))

Несложно видеть, что предикат применяется к формуле . Используя тождество введем импликацию. Вопрос заключается в том, что выбрать в качестве , а что в качестве . Анализ формул и подсказывает, что предпочтительным является выбор: и . После преобразования получим .

С учетом вышесказанного эквивалентной формой исходного запроса является запрос:

НАЙТИ{(de.ImDet)/deDet}:

(doDog)((do.DtN>’10.10.2006’ do.KDet=de.KDet)-> (psPsts)((ps.KPst=do.KPst)(ps.AdrPst’Казань’))(pvPst)((pv.KPst=do.KPst)(pv.KDet=do.KDet)))

Формулировка запроса на естественном языке выглядит следующим образом:

Найти детали, что каждый договор по этой детали, заключенный после ’10.10.2006’ или заключен не с Казанскими поставщиками или имеются поставки этих деталей по данному договору.

Рассмотрим задачу построения запроса на языке SQL

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

НАЙТИ{(de.ImDet)/deDet}:(doDog)((do.DtN<=’10.10.2006’  do.KDetde.KDet)

(psPsts)(( ps.KPst=do.KPst)(ps.AdrPst’Казань’))

(pvPst)((pv.KPst=do.KPst)(pv.KDet=do.KDet)))

Используя правила де Моргана, будем иметь

После преобразования получим

НАЙТИ{(de.ImDet)/deDet}:(doDog)((do.DtN>’10.10.2006’ do.Kdet=de.KDet)

(psPsts)(( ps.KPst=do.KPst)(ps.AdrPst’Казань’))

(pvPst)((pv.KPst=do.KPst)(pv.KDet=do.KDet)))

Реализуя запрос на языке SQL, получим

SELECT Det.ImDet FROM DET

WHERE NOT EXISTS (SELECT * FROM DOG

WHERE (dog.KDet=det.KDet) AND (dog.DtN>’10.10.2006’)

AND NOT EXISTS (SELECT * FROM PSTS WHERE (psts.KPst=dog.KPst)

AND (psts.AdrPst<>’Казань’))

AND NOT EXISTS (SELECT * FROM PST WHERE (pst.KPst=dog.KPst) AND (pst.Kdet=dog.KDet)))

Ниже приводится пример реализации запроса средствами языка DELPHI с использованием команд навигации по таблицам.

При реализации запроса учитываются следующие эквивалентные представления:

Учитывая, что семантически

  • реализация оператора «b:=xFile(B(x))» может быть представлена в виде:

b:=false; RESET(File);

WHILE NOT b AND NOT EOF(File) DO

BEGIN READ(File,x); b:=B(x) END

  • реализация оператора «b:=xFile(B(x))»:

b:=true; RESET(File);

WHILE b AND NOT EOF(File) DO

BEGIN READ(File,x); b:=B(x) END

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

Вернемся к исходной форме запроса:

НАЙТИ{(de.ImDet)/deDet}:

(doDog)((do.DataN<=’10.10.2006’ do.KDetde.KDet)

(psPsts)(( ps.KPst=do.KPst)(ps.AdrPst’Казань’))

(pvPst)((pv.KPst=do.KPst)(pv.KDet=do.KDet)))

{ NewTable - таблица, куда помещаются результаты запроса. Эта таблица должна быть создана заранее}

NewTable.Close; NewTable.EmptyTable; NewTable.Open;

{ Открываются все таблицы }

PstsTable.Open; DogTable.Open; DetTable.Open; PstTable.Open; ;

{Внешний цикл строится по таблице Det}

DetTable.First;

WHILE NOT DetTable.EOF DO begin

{ aDog – переменная селектор для реализации квантора }

aDog:=true;

{Вложенный цикл строится по таблице Dog c учетом условия aDog }

DogTable.First;

WHILE aDog AND NOT DogTable.EOF DO begin

{в переменной DogUsl по частям формируется условие aDog, первоначальное значение переменной соответствует значению . Проверка условия С имеет смысл только при условии, что }

DogUsl:=dog.DataN<=’10.10.2006’ OR dog.Kdet<>det.KDet);

IF NOT DogUsl then begin

{в переменной PstsUsl формируется условие С, цикл по таблице Psts}

PstsUsl:=false; PstsTable.First;

WHILE Not PstsUsl AND NOT PstsTable.EOF DO begin

PstsUsl:=(psts.KPst=dog.KPst)(psts.AdrPst’Казань’);

{Навигация по таблицев Psts}

PstsTable.Next;

End;

{корректировка переменной DogUsl после формирования значения переменной PstsUsl, в данном контексте формула эквивалентна DogUsl:= DogUsl PstsUsl; }

DogUsl:=PstsUsl;

End;

{значение переменной DogUsl соответсвует значению дизъюнкции . Проверка условия D имеет смысл только при условии, что }

IF NOT DogUsl then begin

PstUsl:=false; PstTable.First;

WHILE Not PstUsl AND NOT PstTable.EOF DO begin

PstUsl:=(pst.KPst=dog.KPst)(pst.KDet=dog.KDet);

{Навигация по таблицев Pst}

PstTable.Next;

End;

DogUsl:= PstsUsl;

End;

{корректировка переменной ADogl после формирования значения переменной DogUsl}

ADog:=Adog AND DogUsl;

{Навигация по таблицев Dog}

DogTable.Next;

End;

{Отбор информации в таблицу NewTable при выполнении условий запроса }

IF aDog then begin

NewTable.Append;

NewTable.FieldByName('ImDet').Value:=

DetTable.FieldByName('ImDet').Value;

NewTable.Post;

End;

{Навигация по таблицев Det}

DetTable.Next;

end;

{Завершение запроса, закрытие таблиц}

NewTable.Close;

PstsTable.Close;DogTable.Close;DetTable.Close;PstTable.Close;

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

Расширенный начальный вариант алгебры, определенный Коддом, состоит из восьми алгебраических операций, которые делятся на два класса – теоретико–множественные операции и специальные реляционные операции.

В состав теоретико–множественных операций входят:

  • объединение отношений;

  • пересечение отношений;

  • взятие разности отношений;

  • декартово произведение отношений.

Специальные реляционные операции включают:

  • проекцию отношения;

  • соединение отношений;

  • деление отношений;

  • выборка или ограничение отношения.

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

  • Операция переименования производит отношение, тело которого совпадает с телом операнда, но имена атрибутов изменены.

  • Операция присваивания позволяет сохранить результат вычисления реляционного выражения в существующем отношении БД.

Ниже используются обозначения:

A,B,C... (возможно с индексами) - имена полей (атрибуты), причем считается, что для каждого имени однозначно определен тип данных (домен) и этот тип неструктурный;

r,s,t... (возможно с индексами) - переменные типа кортеж (запись), причем считается, что порядок полей в кортеже не существенен, т.е. кортежи с одинаковым множеством полей (и их значениями) одинаковы;

R,S,T... (возможно с индексами) - переменные типа отношение (файл, таблица), причем считается, что порядок кортежей в отношении не существенен и в отношении не может быть одинаковых кортежей, т.е. отношения с одинаковым множеством кортежей одинаковы.

Базовый набор отношений: отношения, содержащие один кортеж; базовые файлы определяются с помощью операции - (имя_поля: значение_поля, ...)

Базовый набор операций над отношениями.

  • Теоретико-множественные:   - (объединение, пересечение и разность, соответственно). Операции применимы только к парам отношений, имеющих одинаковую структуру (схему отношения базы данных). Операция объединения по двум отношениям R и S строит новое отношение , которое включает все кортежи, входящие в отношения R и S ровно один раз. Операция пересечения по двум отношениям R и S строит новое отношение , которое включает все кортежи, одновременно входящие в отношения R и S. Операция разности по двум отношениям R и S строит новое отношение , которое включает все кортежи, входящие в отношение R и отсутствующие в отношении S.

  • Естественное соединение R*S={r*s / rR, sS}, где операция соединения кортежей r и s применима только к парам кортежей, у которых одноименные поля имеют одинаковое значение. Результатом соединения таких кортежей r и s является кортеж, который содержит все поля (со своими значениями) из r и s (одноименные поля не дублируются). В частном случае, при отсуствии одноименных полей имеем операцию декартова произведения двух отношений.

ПРИМЕР.(A:1,B:2)*(B:2,C:3)=(A:1,B:2,C:3);

(A:1,B:2)*(C:3,D:4)=(A:1,B:2,C:3,D:4) - в случае отношений без одноименных полей, операция применима к каждой паре записей;

(A:1,B:2)*(B:3,D:4) - к такой паре записей операция не применима.

  • Выборка [B] (R) = отношение состоящее из кортежей из R, удовлетворяющих условию B. Операция выборки применяется к отношению R и определяет результирующее отношение, который содержит только те записи из R, которые удовлетворяют условию B. Условие B строится как обычное логическое выражение - из имен полей и констант с помощью операций сравнения и логических операций.

  • Переименование полей [A1B1,A2B2,...](R). A1,A2,... должны быть именами полей файла R, а поля B1,B2,... должны иметь соответствующий тип. Результат операции будет содержать те же записи, что и файл R, но поля A1,A2,... будут соответственно переименованы на B1,B2,...ё Операция переименования часто используется перед выполнением теоретико!множественных операцийё

  • Проекция [имя_поля,...](R) = отношение, полученное из R, и состоящее из кортежей в которых удалены все поля, кроме перечисленных в операции. Операция проекции создает новое отношение S из отношения R, кортежи которого являются соответствующими подмножествами кортежей отношения -операнда, с последующим удалением из результата дубликатов записей.

  • Деление RS. Операция применима, если все поля отношения-«делителя» S являются полями отношения-«делимого» R; пусть A1,A2,... - поля отношения S, а A1,A2,...B1,B2,... - поля отношения R. Результат деления будет отношением с полями B1,B2,...

RS={t: такие, что (t*s)R для любой записи s из S}.

Отметим, что в этом выражении записи t и s не имеют общих полей, поэтому операция * это просто декартово произведение записей.

ПРИМЕР. Пусть R - файл с полями (A,B), S - файл с полем (A), T=(RS) - будет файлом с полем (B):

B

T

A

S

2. Дан запрос на языке реляционной алгебры

  • Сформулировать на естественном языке постановку задачи, специфицированной этим запросом

  • Составить две программы решения этой задачи1:

    • Select оператором на языке SQL

    • PASCAL(С++) – программу с использованием средств обработки баз данных

1.([KPst][AdrPst=’КАЗАНЬ’]Psts)-

([KPst][DtN>’01.01.2002’]Dog)

======================================================

Выражение, задающее данный запрос, можно представить в виде формулы, где

([KPst][AdrPst=’КАЗАНЬ’]Psts)

([KPst][DtN>’01.01.2002’]Dog)

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

Результатом выполнения запроса А является множество кортежей, описывающих коды поставщиков с Казанскими адресами. Заметим, что проекция строится по ключевому полю, поэтому в результате выполнения операции проекции не получается кортежей с одинаковыми значениями поля KPst.

Во втором запросе поле KPst является только частью ключа в таблице договоров (ключ (KPst,KDet)), и следовательно операция проекции по KPst может дать кортежи с повторяющимися значениями по этому полю. Разделим множество всех поставщиков на три класса по дате начала договора:

  1. Поставщики, все договора которых были заключены до ’02.01.2002’

  2. Поставщики, все договора которых были заключены после ’01.01.2002’

  3. Поставщики, которые имеют договора, которые были заключены как до ’02.01.2002’, так и после ’01.01.2002’

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

Поэтому правильная интерпретация запроса связана с квантором всеобщности:

Выбрать поставщиков из Казани, которые не заключали договоров позже 01.01.2002

На языке реляционного исчисления кортежей этот запрос может быть сформулирован следующим образом:

НАЙТИ{(ps.KPst)/psPsts}:

(ps.AdrPst=’КАЗАНЬ’  (doDog)((( ps.KPst=do.KPst) (DtN>’01.01.2002’))))

Или

НАЙТИ{(ps.KPst)/psPsts}:

(ps.AdrPst=’КАЗАНЬ’  (doDog)(( ps.KPst=do.KPst) (DtN>’01.01.2002’)))

На языке SQL этот запрос выглядит следующим образом:

SELECT Psts.KPst FROM Psts

WHERE (Psts.AdrPst=’КАЗАНЬ’) AND

NOT EXISTS(SELECT * FROM Dog WHERE (Psts.KPst=Dog.KPst) AND (Dog.Dtn>’01.01.2002’));

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

Реализация запроса, задаваемого формулой (операция выборки и проекции):

CREATE VIEW W1 (KPst) AS

SELECT KPst FROM Psts

WHERE AdrPst=’КАЗАНЬ’

Реализация запроса, задаваемого формулой (операция выборки и проекции):

CREATE VIEW W2 (KPst) AS

SELECT Distinct KPst FROM Dog

WHERE DtN>’01.01.2002’

Реализация разности (sA tB a.KPst=b.sPst):

CREATE VIEW W3 (KPst) AS

SELECT KPst FROM W1

WHERE NOT EXISTS (SELECT * FROM W2

WHERE W2.KPst=W1.KPst)

2.([KDet,KPst][DtN>’01.01.2002’]Dog)

([KPst][AdrPst=’КАЗАНЬ’]Psts)

Содержательная формулировка запроса:

Найти все детали(коды деталей), что для любого поставщика из Казани найдется договор по закупке этих деталей с датой начала после ’01.01.2002’.

Представим данный запрос в виде суперпозиции следующих формул:

=[KDet,KPst][DtN>’01.01.2002’]Dog

=[KPst][AdrPst=’КАЗАНЬ’]Psts

.

При реализации запроса используем представления. Формируем делимое ():

CREATE VIEW W1 (Kdet,KPst) AS

SELECT Kdet,KPst FROM DOG

WHERE DtN>’01.01.2002’

Формируем делитель ():

CREATE VIEW W2 (KPst) AS

SELECT KPst FROM PSTS

WHERE AdrPst=’КАЗАНЬ’

Операция деления реализуется по следующей формуле:

W3=(W1W2) = НАЙТИ{(r.KDet)/rW1}

sW2 tW1 ((t.KPst=s.KPst)(t.KDet=r.KDet))

CREATE VIEW W3 (KDet) AS

SELECT Distinct KDet FROM W1 psW1

WHERE NOT EXISTS (SELECT * FROM W2

WHERE NOT EXISTS (SELECT * FROM W1

WHERE ((W1.KDet=psW1.Kdet) AND (W1.KPst=W2.KPst))))

Внимание! Поскольку данный запрос дважды использует таблицу W1 необходимо при формировании оператора Select использовать псевдонимы, причем для правильной реализации запроса в InterBase псевдоним необходимо определить при первом обращении к таблице.

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

10

Соседние файлы в папке Базы данных(1 курс, 2 семестр,2011-2012)