Лекции №19,20 (9 и 16.11.2004)

advertisement
Модификация представления с помощью триггеров.
Oracle позволяет «перехватить» попытку модификации
представления, используя instead-of триггер.
Пример.
Likes(drinker, beer)
Sells(bar, beer, price)
Frequents(drinker, bar)
CREATE VIEW Synergy AS
SELECT Likes.drinker, Likes.beer,Sells.bar
FROM Likes, Sells, Frequents
WHERE Likes.drinker = Frequents.drinker
AND
Likes.beer = Sells.beer
AND
Sells.bar = Frequents.bar;
1
CREATE TRIGGER ViewTrig
INSTEAD OF INSERT ON Synergy
FOR EACH ROW
BEGIN
INSERT INTO Likes VALUES(:new.drinker, :new.beer);
INSERT INTO Sells(bar, beer)
VALUES(:new.bar, :new.beer);
INSERT INTO Frequents
VALUES(:new.drinker, :new.bar);
END;
.
RUN
SQL Triggers
 Рекомендуется прочитать раздел 7.4.3 книги.
 Некоторые отличия, включая
1. Ограничения Oracle относительно модификации
отношения вызвавшего триггер или отношения
связанного с ним внешним ключом отсутствует в SQL
(однако Oracle –реальная СУБД, SQL – стандарт на
бумаге).
2. Действие в SQL - список (ограниченный) SQL
операторов, а не PL/SQL оператор, как в Oracle.
3. Имеются некоторые синтаксические отличия
Пример 1.
MovieExec (name, address, cert#, netWorth)
CREATE TRIGGER NetWorthTrigger
AFTER UPDATE of netWorth ON MovieExec
REFERENCING
OLD ROW AS OldTuple,
NEW ROW AS NewTuple
FOR EACH ROW
WHEN (OldTuple.netWorth > NewTuple.netWorth )
UPDATE MovieExec
SET netWorth = OldTuple.netWorth
WHERE cert# = NewTuple.cert#
 FOR EACH ROW – триггер уровня кортежа, FOR EACH
STATEMENT – триггер уровня оператора,
 UPDATE, INSERT, DELETE – возможные события,
 BEGIN … END – если действие состоит из нескольких SQL
операторов.
Пример 2.
CREATE TRIGGER AvgNetWorthTrigger
AFTER UPDATE OF netWorth ON movieExec
REFERENCING
OLD TABLE AS OldStuff,
NEW TABLE AS NewStuff
FOR EACH STATEMENT
WHEN ( 500000 > (SELECT AVG(netWorth) FROM Movie) )
BEGIN
DELETE FROM MovieExec
WHERE (name, address, cert#, netWorth) IN NewStuff;
INSERT INTO MovieExec
(SELECT * FROM OldStuff);
END;
PL/SQL
 Oracle версия хранимых процедур SQL( PSM - Persistent,
Stored Modules). Используется через sqlplus.
 Компромисс между полным процедурным языком
программирования и SQL операторами – операторами
высокого уровня, но ограниченными с точки зрения
управления программой.
 Имеет локальные переменные, циклы, процедуры,
возможность работы и проверки отдельного кортежа
отношения.
 Общий вид:
DECLARE
Объявления (описания) переменных
BEGIN
Выполнимые операторы
END;
.
RUN;
 секция DECLARE не обязательна.
 . и RUN (или слеш вместо RUN) необходимо, чтобы
закончить программу и выполнить ее.
Простейшая форма: последовательность изменений
Likes(drinker, beer)
BEGIN
INSERT INTO Likes VALUES('Sally', 'Bud');
DELETE FROM Likes
WHERE drinker = 'Fred' AND beer = 'Miller';
END;
.
RUN;
Procedures.
Хранимые объекты базы данных, использующие PL/SQL
утверждения в своем теле.
Объявление процедур.
CREATE OR REPLACE PROCEDURE
< имя > ( < список_аргументов > ) AS
< объявления >
BEGIN
< PL/SQL операторы >
END;
.
RUN;
 Список_аргументов состоит из троек имя-режим-тип.
 Режим: IN, OUT, или IN OUT для только-чтения, толькозаписи или чтения-записи соответственно
 Тип: стандартный SQL тип + общие типы, такие как
NUMBER = любое целое или вещественное значение.
Поскольку типы в процедуре должны соответствовать типам в
схеме базы данных, рекомендуется использовать выражения
вида <отношение>.<атрибут>%TYPE чтобы это обеспечить.
Пример.
Процедура принимает в качестве параметров beer и price и
добавляет в меню бара Joe's.
Sells(bar, beer, price)
CREATE PROCEDURE joeMenu(
b IN Sells.beer%TYPE,
p IN Sells.price%TYPE
) AS
BEGIN
INSERT INTO Sells
VALUES('Joe''s Bar', b, p);
END;
.
RUN;
Замечание: RUN только компилирует и запоминает процедуру
в базу данных, но не выполняет ее.
Вызов процедуры.
Вызов процедуры может использоваться в теле PL/SQL
оператора.
Пример.
BEGIN
joeMenu('Bud', 2.50);
joeMenu('MooseDrool', 5.00);
END;
.
RUN;
Присваивание.
Значение объявленной переменной присваивается при
помощи оператора :=.
Ветвление.
IF < condition > THEN
< statement(s) >
ELSE
< statement(s) >
END IF;
 Но во вложенных условных операторах используются
ELSIF вместо ELSE IF.
Циклы.
LOOP
...
EXIT WHEN < условие >
…
END LOOP;
Запросы в PL/SQL.
1. Однострочный SELECT (результатом которого является
ровно один кортеж) позволяет записать результат
запроса в переменную (переменные).
2. Курсор позволяет извлекать результаты многострочного
запроса по одному кортежу.
Однострочный SELECT.
 SELECT-FROM-WHERE в PL/SQL должен иметь опцию
INTO со списком переменных, в которые будут записаны
компоненты кортежа.
 Если результат запроса содержит более одного кортежа,
возникает ошибка. Для обработки результата в этом случае
необходим курсор.
Пример.
Найти цену Joe берет за Bud (на самом деле она никак в этом
примере не используется).
Sells(bar, beer, price)
DECLARE
p Sells.price%TYPE;
BEGIN
SELECT price
INTO p
FROM Sells
WHERE bar = 'Joe''s Bar' AND beer = 'Bud';
END;
.
RUN
Курсоры.
Объявляются при помощи
CURSOR < имя_курсора > IS
SELECT-FROM-WHERE запрос
 Курсор получает каждый кортеж из результата запроса по
очереди, используя оператор FETCH в цикле.
FETCH < имя_курсора > INTO
<список_переменных>;
 Окончание цикла происходит при обнаружении конца
результата:
EXIT WHEN < имя_курсора > %NOTFOUND;
Условие становится истинным, когда просмотрены
(извлечены) все кортежи результата.
 Курсор перед использованием должен быть открыт при
помощи оператора OPEN, а после использования – закрыт
при помощи CLOSE.
Пример.
Процедура проверяет меню бара Joe's и поднимает цену на
$1.00, если она меньше, чем $3.00.
Sells(bar, beer, price)
Этот простой алгоритм может быть реализован при помощи
единственного утверждения UPDATE, но в более сложных
случаях без курсора не обойтись.
CREATE PROCEDURE joeChange() AS
theBeer Sells.beer%TYPE;
thePrice Sells.price%TYPE;
CURSOR c IS
SELECT beer, price
FROM Sells
WHERE bar = 'Joe''s bar';
BEGIN
OPEN c;
LOOP
FETCH c INTO theBeer, thePrice;
EXIT WHEN c%NOTFOUND;
IF thePrice < 3.00 THEN
UDPATE Sells
SET price = thePrice + 1.00
WHERE bar = 'Joe''s Bar'
AND beer = theBeer;
END IF;
END LOOP;
CLOSE c;
END;
.
RUN
Строчный тип.
Объекты, состоящие из кортежей, имеют тип %ROWTYPE.
 Можно объявить переменную-кортеж, имеющую строчный
тип и обращаться к компонентам кортежа при помощи .
(оператора «точки») и имени атрибута.
 Удобно, когда кортеж имеет много атрибутов.
Пример. Та же процедура с использованием переменнойкортежа.
CREATE PROCEDURE joeGouge() AS
CURSOR c IS
SELECT beer, price
FROM Sells
WHERE bar = 'Joe''s bar';
bp c%ROWTYPE;
BEGIN
OPEN c;
LOOP
FETCH c INTO bp;
EXIT WHEN c%NOTFOUND;
IF bp.price < 3.00 THEN
UDPATE Sells
SET price = bp.price + 1.00
WHERE bar = 'Joe''s Bar'
AND beer = bp.beer;
END IF;
END LOOP;
CLOSE c;
END;
.
RUN
Download