Шрифт:
Следующий скрипт создает две таблицы, создает просмотр, который является соединением этих двух таблиц, а затем создает три триггера (для операций DELETE, UPDATE, INSERT), которые будут передавать все изменения в просмотре базовым таблицам:
CREATE TABLE Table1 (
ColA INTEGER NOT NULL,
ColB VARCHAR(20),
CONSTRAINT pk_table PRIMARY KEY(ColA) );
COMMIT;
CREATE TABLE Table2 (
ColA INTEGER NOT NULL,
ColC VARCHAR(20),
CONSTRAINT fk_table2 FOREIGN KEY REFERENCES Table1(ColA) ) ;
COMMIT;
CREATE VIEW TableView AS
SELECT Table1.ColA, Table1.ColB, Table2.ColC
FROM Table1, Table2
WHERE Table1.ColA = Table2.ColA;
COMMIT;
SET TERM ^;
CREATE TRIGGER TableView_Delete FOR TableView
ACTIVE BEFORE DELETE AS
BEGIN
DELETE FROM Table1
WHERE ColA = OLD. ColA;
DELETE FROM Table2
WHERE ColA = OLD. ColA;
END ^
CREATE TRIGGER TableView_Update FOR TableView
ACTIVE BEFORE UPDATE AS
BEGIN
UPDATE Table1
SET ColB = NEW.ColB
WHERE ColA = OLD.ColA;
UPDATE Table2
SET ColC = NEW.ColC
WHERE ColA = OLD.ColA;
END ^
CREATE TRIGGER TableView_Insert FOR TableView
ACTIVE BEFORE INSERT AS
BEGIN
INSERT INTO Table1 values (NEW.ColA,NEW.ColB);
INSERT INTO Table2 values (NEW.ColA,NEW.ColC);
END ^
COMMIT ^
SET TERM ;^
При определении триггеров для просмотров проследите, чтобы они не создавали конфликтов или неожиданных условий в отношении триггеров, определенных для базовых таблиц. Выполнение триггера для просмотра предшествует выполнению триггера для таблицы соответствующей фазы (BEFORE/AFTER).
Предположим, у вас есть триггер BEFORE INSERT (перед вставкой) для базовой таблицы, который получает значение генератора для первичного ключа, если его NEW. VALUE имеет значение NULL. ЕСЛИ триггер для просмотра включает оператор INSERT для базовой таблицы, не указывайте столбец первичного ключа в этом операторе в просмотре. Это приведет к тому, что для NEW.VALUE первичного ключа будет передано значение NULL, давая возможность триггеру таблицы выполнить свою работу.
О триггерах и контекстных переменных NEW.* см. главу 31.
Не все просмотры могут быть сделаны изменяемыми путем создания для них триггеров. Например, следующий удобный маленький просмотр только для чтения читает контекстную переменную с сервера, но несмотря ни на какие триггеры, которые вы определите для него, все операции за исключением SELECT не будут выполняться:
CREATE VIEW SYSTRANS
(CURR_TRANSACTION) AS
SELECT CURRENT_TRANSACTION FROM RDB$DATABASE;
Естественно изменяемые просмотры
Просмотр является естественно изменяемым, если выполняются следующие два условия:
* спецификация просмотра является подмножеством одной таблицы или другого изменяемого просмотра;
* все столбцы базовой таблицы, не включенные в определение просмотра, допускают значение NULL.
Следующий оператор создает естественно изменяемый просмотр:
CREATE VIEW EMP_MNGRS (FIRST, LAST, SALARY) AS
SELECT FIRST_NAME, LAST_NAME, SALARY
FROM EMPLOYEE
WHERE JOB_CODE = 'Mngr'
WITH CHECK OPTION;
Поскольку предложение WITH CHECK OPTION включено в эту спецификацию, приложения не смогут изменять значение столбца JOB_CODE, даже если не было нарушения ограничения внешнего ключа для этого столбца в базовой таблице.
Изменение поведения изменяемых просмотров
Альтернативное поведение естественно изменяемых просмотров может быть задано с использованием триггеров. Для конкретной фазы операции (BEFORE/AFTER) триггеры просмотра вызываются до триггеров базовой таблицы. Следовательно, можно бережно и умело использовать просмотры для замены поведения обычного триггера базовой таблицы на планируемое.
Однако также можно создать разрушение при наличии плохо спланированных триггеров просмотров. Проверяйте, проверяйте, проверяйте!
Изменить определение просмотра?
Термины изменяемый и только для чтения относятся к тому, как может осуществляться доступ к данным из базовых таблиц, а не к тому, может ли изменяться определение просмотра. Firebird не предоставляет синтаксис ALTER VIEW.
Для изменения определения просмотра вы должны удалить просмотр, а затем заново его создать.