Представления Представление – это виртуальная таблица. В действительности представление – всего лишь результат выполнения оператора 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;