Представления

advertisement
Представления
Представление – это виртуальная таблица. В действительности представление –
всего лишь результат выполнения оператора SELECT, который хранится в
структуре памяти, напоминающей SQL таблицу.
Для тех, кто работает с представлением, манипулирование его данными ничем
не отличается от манипулирования данными таблицы. В некоторых случаях
пользователь может вводить данные в представление, как если бы оно было
таблицей. Работая с представлением нужно помнить, что:
Представления добавляют уровень защиты данных (например, можно создать
представление для таблицы, где пользователю, выполняющему SELECT над
представлением, видны только сведения о зарплате)
Представления могут скрывать сложность данных, комбинируя нужную
информацию из нескольких таблиц
Представления могут скрывать настоящие имена столбцов, порой трудные для
понимания, и показывать более простые имена.
Представление создается с помощью команды CREATE VIEW. После создания
представления становятся частью схемы создавшего их пользователя.
Синтаксис:
CREATE {OR REPLACE} {FORCE | NO FORCE} VIEW {(ALIAS)}
AS <Subquery>
{WITH {READ ONLY} {CHECK OPTION CONSTRAINT <constraint>}}
Основные ключевые слова и параметры CREATE VIEW Oracle:
OR REPLACE, FORCE, NOFORCE, Sсhema, View, Alias, AS subquery, WITH
CHECK OPTION, Constraint
OR REPLACE — пересоздает представление, если оно уже существует. Можно
использовать эту опцию для изменения определения представления без того,
чтобы удалять его, создавать заново и вновь назначать все объектные
привилегии, которые были назначены по данному представлению;
FORCE — создает представление независимо от того, существуют ли базовые
таблицы этого представления, и от того, имеет ли владелец схемы, содержащей
представление, привилегии по этим таблицам. Необходимо чтобы оба
названных условия были удовлетворены, прежде чем по данному
представлению можно будет выдавать любые
предложения SELECT, INSERT, UPDATE или DELETE. По умолчанию
применяется параметр NOFORCE;
NOFORCE — создает представление только в том случае, если существуют
базовые таблицы этого представления, а владелец схемы, содержащей
представление, имеет привилегии по этим таблицам;
WITH CHECK OPTION — указывает, что вставки и обновления, которые будут
осуществляться через этот запрос, должны давать в результате только такие
строки, которые могут быть выбраны запросом этого же представления.
Опция CHECK OPTION не может гарантировать этого, если существует
подзапрос в запросе этого представления или любого представления, на
котором базируется данное представление. Другими словами, при указании
параметра WITH CHECK OPTION пользователь не может вводить, удалять и
обновлять информацию таблицы, из которой он не имеет возможности считать
информацию через простое представление (создаваемое из данных одной
таблицы). Обновляемое представление, использующее несколько связанных
таблиц, нельзя создавать с данным параметром;
Примеры.
CREATE VIEW London_view AS SELECT * FROM Salespeople WHERE city =
‘London’;
CREATE VIEW empl_v04 AS SELECT e.eid, e.sname, e.fname, e.otch, p.pname,
d.dname FROM posts p, departments d, employees e WHERE e.did = d.did AND e.pid
= p.pid;
Индексы
Индексы создаются для обеспечения уникальности столбцов, упрощения
сортировки и быстрого поиска данных по значениям столбцов. Столбцы,
которые часто фигурируют в условиях равенства в предложениях WHERE,
являются хорошими кандидатами на создание индекса. Условия равенства
могут относиться к одной таблице или же к соединению. Эти два случая
представлены в следующих примерах:
SELECT *
FROM MyTable
WHERE Columnl =100;
и
SELECT *
FROM MyTable1, MyTable2
WHERE MyTable1.Columnl = MyTable2.Column2;
Если подобные операторы выполняются часто, то столбцы Columnl и Column2
являются перспективными кандидатами на создание индексов.
Синтаксис:
CREATE [UNIQUE] INDEX index_name ON
table_name(column_name[, column_name...])
TABLESPACE table_space;
Следующий оператор создает индекс по столбцу Name таблицы CUSTOMER:
CREATE INDEX CustNameldx ON CUSTOMER(Name);
Индексу дано имя CustNameldx. И здесь имя не играет особой роли для Oracle.
Чтобы создать уникальный индекс, перед ключевым словом INDEX нужно
вставить ключевое слово UNIQUE. Например, чтобы гарантировать, что ни одно
произведение не будет записано дважды в таблицу WORK, можно создать
уникальный индекс по столбцам (Title, Сору, ArtistID), как показано ниже:
CREATE UNIQUE INDEX WorkUniquelndex ON W0RK(Title, Copy, ArtistID);
Последовательности
Пример.
CREATE SEQUENCE SEQ1
INCREMENT BY 1
START WITH 1
MAXVALUE 9999
MINVALUE 1
NOCYCLE;
Триггеры
Синтаксис:
CREATE OR REPLACE TRIGGER TName
BEFORE/AFTER {OR} <условие> {OF FIELD} ON <Table_name>
{FOR EACH ROW}
{WHEN <условие>}
DECLARE
BEGIN
END TName;
Каждый из триггеров, как и любой другой объект БД, после создания хранится в словаре
данных в виде P-кода. Ранее до версии Oracle 7.3 триггеры хранились в словаре данных, в
виде исходного кода. И каждые раз при вызове компилировались, а затем исполнялись. В
более старших версиях Oracle, триггеры хранятся уже в скомпилированном виде. В
результате, так же как и модули и подпрограммы, могут автоматически становиться
недостоверными. Но, становясь недостоверным, триггер компилируется при следующей
его активации. Активация триггеров, как вы уже знаете происходит при выполнении
операторов DML. Порядок активации триггеров в большинстве случаев таков:
1. Выполняется операторный триггер BEFORE (при его наличии)
2. Для каждой строки, на которую воздействует оператор:
a. Выполняется строковый триггер BEFORE (при его наличии).
b. Выполняется собственно оператор.
c. Выполняется строковый триггер AFTER (при его наличии).
3. Выполняется операторный триггер AFTER (при его наличии).
Аудит в системе доступа к таблице MILLER.CUSTOMERSS. Для этого создадим
простой операторный триггер:
CREATE OR REPLACE TRIGGER testTrg
AFTER INSERT OR DELETE OR UPDATE ON customers
DECLARE
BEGIN
INSERT INTO MILLER.ADT(USAL, TISP)
VALUES(USER, SYSDATE);
END testTrg;
Строковые и операторные триггеры.
1. Операторный BEFORE
CREATE OR REPLACE TRIGGER BFOTST
BEFORE UPDATE ON TSTTRIG
DECLARE
BEGIN
INSERT INTO ADT(USAL, TISP, WDO, PRIM)
VALUES(USER, SYSDATE, 'Update', 'Before Statement trigger');
END BFOTST;
2. Операторный AFTER
CREATE OR REPLACE TRIGGER AFTTST
AFTER UPDATE ON TSTTRIG
DECLARE
BEGIN
INSERT INTO ADT(USAL, TISP, WDO, PRIM)
VALUES(USER, SYSDATE, 'Update', 'After Statement trigger');
END AFTTST;
3. Строковый BEFORE
CREATE OR REPLACE TRIGGER BFOTSTR
BEFORE UPDATE ON TSTTRIG
FOR EACH ROW
DECLARE
BEGIN
INSERT INTO ADT(USAL, TISP, WDO, PRIM)
VALUES(USER, SYSDATE, 'Update', 'Before Row trigger');
END BFOTSTR;
4. Строковый AFTER
CREATE OR REPLACE TRIGGER AFTTSTR
AFTER UPDATE ON TSTTRIG
FOR EACH ROW
DECLARE
BEGIN
INSERT INTO ADT(USAL, TISP, WDO, PRIM)
VALUES(USER, SYSDATE, 'Update', 'After Row trigger');
END AFTTSTR;
Выполним:
UPDATE MILLER.TSTTRIG
SET ROD = 'SPOOKY'
WHERE ID IN (7369, 7370)
Получим:
SELECT * FROM ADT
USAL
TISP
WDO
PRIM
-------------------- ----------- ----------------- ------------------------
MILLER
MILLER
MILLER
MILLER
MILLER
MILLER
17.03.2004
17.03.2004
17.03.2004
17.03.2004
17.03.2004
17.03.2004
Update
Update
Update
Update
Update
Update
Before Statement trigger
Before Row trigger
After Row trigger
Before Row trigger
After Row trigger
After Statement trigger
---
Строковые триггеры и псевдозаписи.
Одним из интересных моментов при создании строковых триггеров является наличие двух
псевдозаписей :old и :new. Строковый триггер срабатывает один раз для каждой строки.
При этом внутри триггера можно обращаться к строке обрабатываемой в данный момент
времени. Делать это можно как вы уже поняли, применяя псевдозаписи. По своей сути
:old и :new вообще-то записями в полном понимании не являются. Например, как
рассмотренном нами ранее - таблица%ROWTYPE.
При этом верно утверждение что :old и :new это активизирующая_таблица%ROWTYPE,
где активизирующая_таблица - это таблица, для которой создан триггер.
Пример:
CREATE OR REPLACE TRIGGER DLTTSTR
BEFORE DELETE ON TSTTRIG
FOR EACH ROW
a TSTTRIG.ID%TYPE;
b TSTTRIG.NM%TYPE;
c TSTTRIG.ROD%TYPE;
DECLARE
BEGIN
-- Верно синтаксически!
a = :old.ID;
c = :new.ROD;
b = :old.NM;
...
Думаю понятно, что обращение к псевдозаписям :old и :new должно производиться через
имена полей, по этому они и называются псевдозаписями! Естественно, что все
вышесказанное применимо только к строковым триггерам! Обращение к :old и :new в
операторных триггерах вызовет ошибку компиляции! Давайте опишем некоторые
положения для псевдозаписей :old и :new применимо к операторам DML:
Активизирующий
оператор
INSERT
:OLD
Не определена во всех полях
содержится NULL значения
:NEW
Значения, которые будут
введены после выполнения
оператора.
UPDATE
Исходные значения
содержащиеся в строке перед
обновлением данных
Новые значения которые будут
введены после выполнения
оператора
DELETE
Исходные значения
содержащиеся в строке перед ее
удалением
Не определена во всех полях
содержится NULL значения
Пример автозаполнения:
INSERT INTO TSTTRIG (NM, ROD, INRW)
VALUES ('BLAKE', 'MANAGER', TO_DATE('8-5-1999', 'DD-MM-YYYY'))
(есть ещё ID - Primary key)
CREATE SEQUENCE TRG
START WITH 8000
INCREMENT BY 1
CREATE OR REPLACE TRIGGER INSIDTRG
BEFORE INSERT ON TSTTRIG
FOR EACH ROW
DECLARE
BEGIN
SELECT TRG.NEXTVAL
INTO :NEW.ID
FROM DUAL;
END INSIDTRG;
Модифицированные предыдущие примеры:
CREATE OR REPLACE TRIGGER BFOTSTR
BEFORE UPDATE ON TSTTRIG
FOR EACH ROW
DECLARE
BEGIN
INSERT INTO ADT(USAL, TISP, WDO, PRIM)
VALUES(USER, SYSDATE, :OLD.ROD, 'UPDATE TO '||:new.ROD);
END BFOTSTR;
CREATE OR REPLACE TRIGGER AFTTSTR
AFTER UPDATE ON TSTTRIG
FOR EACH ROW
DECLARE
BEGIN
INSERT INTO ADT(USAL, TISP, WDO, PRIM)
VALUES(USER, SYSDATE, :new.ROD, :old.ROD);
END AFTTSTR;
---
Связь 2-ух таблиц.
Создадим триггер для таблицы MILLER.TSTTRIG, который одновременно будет менять
содержимое таблицы - MILLER.TSTSV реализуя наше бизнес правило для
MILLER.TSTTRIG. Создаем:
CREATE OR REPLACE TRIGGER AFTINSTTRIG
AFTER INSERT ON TSTTRIG
FOR EACH ROW
DECLARE
BEGIN
INSERT INTO MILLER.TSTSV(MILLER.TSTSV.ID, MILLER.TSTSV.IDD, MILLER.TSTSV.ROD,
MILLER.TSTSV.CONS)
VALUES(SV.NEXTVAL, :NEW.NM, :NEW.ROD, :NEW.ID);
END AFTINSTTRIG;
--CREATE OR REPLACE TRIGGER AFTUPDTTRIG
AFTER UPDATE ON TSTTRIG
FOR EACH ROW
DECLARE
BEGIN
UPDATE MILLER.TSTSV
SET
MILLER.TSTSV.IDD = :NEW.NM,
MILLER.TSTSV.ROD = :NEW.ROD,
MILLER.TSTSV.CONS = :NEW.ID
WHERE
MILLER.TSTSV.CONS = :OLD.ID;
END AFTUPDTTRIG;
--CREATE OR REPLACE TRIGGER BFRDELTTRIG
BEFORE DELETE ON TSTTRIG
FOR EACH ROW
DECLARE
BEGIN
DELETE FROM MILLER.TSTSV
WHERE MILLER.TSTSV.CONS = :OLD.ID;
END BFRDELTTRIG;
Условные триггеры.
Рассмотрим такой момент создания триггера БД, кода в нем применяется условие
WHERE! С его помощью можно заставить триггер работать - по условию! Само условие
WHERE в триггере применимо к типу строчных триггеров.
CREATE OR REPLACE TRIGGER WHENTRG
BEFORE INSERT OR UPDATE OF COST ON TSTTRIG
FOR EACH ROW
WHEN (new.COST > 10000)
DECLARE
BEGIN
UPDATE TSTSV
SET TSTSV.ITOG = :new.COST + :old.COST
WHERE TSTSV.CONS = :old.ID;
END WHENTRG;
Обратите внимание на наличие строки OF COST ON TSTTRIG - здесь определяется поле,
на которое устанавливаем условие триггера и собственно само условие WHEN (new.COST
> 10000) - обратите внимание, что псевдозапись new записана как - new, а не :new ! Это
важно! В условии псевдозаписи записываются БЕЗ ДВОЕТОЧИЯ! Запомните! Двоеточие
применяется только в теле триггера! Условие можно строить и по другому, так как нужно
вам. Данный триггер производит довольно глупое действие, но зато наглядное! При
вставке или изменении, он просто запоминает сумму чисел в поле ITOG таблички TSTSV!
Предикаты в триггерах.
В триггерах БД Oracle возможно применение логических операторов - так называемых
предикатов. Они имеют следующие определения INSERTING, UPDATING, DELETING.
Это некие внутренние переменные среды Oracle, которые в зависимости от
воздействующего на таблицу оператора DML принимают одно из значений TRUE или
FALSE. С их помощью можно значительно сэкономить при написании кода, в чем вы в
дальнейшем убедитесь и не плодить слишком большое количество объектов БД.
Кратко их можно описать вот так:
Предикат
Принимаемое значение
INSERTING TRUE если, активизирующий оператор INSERT. FALSE в противном случае.
UPDATING
TRUE если, активизирующий оператор UPDATE. FALSE в противном
случае.
DELETING
TRUE если, активизирующий оператор DELETE. FALSE в противном
случае.
CREATE OR REPLACE TRIGGER AUDT_TSTTRIG
BEFORE INSERT OR UPDATE OR DELETE ON TSTTRIG
FOR EACH ROW
DECLARE
TIP VARCHAR2(10);
BEGIN
IF
INSERTING THEN
TIP := 'INSERT';
ELSIF UPDATING THEN
TIP := 'UPDATE';
ELSIF DELETING THEN
TIP := 'DELETE';
END IF;
INSERT INTO MYAUDIT(MYAUDIT.POLZ, MYAUDIT.VIZM, MYAUDIT.OPER,
MYAUDIT.NZAP, MYAUDIT.HIST)
VALUES (USER, SYSDATE, TIP, :new.ID, 'Old Name: '||:old.NM||'
New Name: '||:new.NM);
END AUDT_TSTTRIG;
Пример автозаполнения
DECLARE
TYPE com_name IS TABLE OF VARCHAR2(200); --INDEX BY
binary_integer;
name com_name := com_name(
'Company 1'
,'Company 2'
,'Company 3'
,'Company 4'
,'Company 5'
);
i number;
BEGIN
i := name.first;
for i in name.first..4*name.count loop
DBMS_OUTPUT.put_line(TO_CHAR(name(i)));
INSERT INTO FROEIGN_LANGUAGE
VALUES (SEQ1.NEXTVAL, TO_CHAR(name(i)), dbms_random.value(1, 6),
dbms_random.value(100, 9999));
end loop;
END;
Download