Опубликован: 10.09.2004 | Уровень: для всех | Доступ: платный | ВУЗ: Ульяновский государственный университет
Лекция 15:

Триггеры в рекурсивных структурах

< Лекция 14 || Лекция 15: 12 || Лекция 16 >

Добавление записи в рекурсивную структуру

ALTER TRIGGER emp_ins
ON emp_mgr FOR INSERT
AS
--Правило 2
IF EXISTS (SELECT * FROM inserted WHERE mgr=emp)
BEGIN
    ROLLBACK TRAN
    RAISERROR('САМ СЕБЕ НАЧАЛЬНИК',16,10)
    RETURN
END
--Правило 4
IF EXISTS (SELECT * FROM inserted WHERE mgr IS NULL) AND
    EXISTS (SELECT * FROM emp_mgr,inserted 
        WHERE emp_mgr.mgr IS NULL 
		AND emp_mgr.emp<>inserted.emp)
BEGIN
    ROLLBACK TRAN
    RAISERROR('ОДИН ДИРЕКТОР УЖЕ ЕСТЬ',16,10)
    RETURN
END
--Правило 3
IF EXISTS(SELECT * FROM inserted
    WHERE mgr IS NOT NULL) AND
NOT EXISTS(SELECT * FROM inserted,emp_mgr
    WHERE emp_mgr.emp=inserted.mgr)
BEGIN
  RAISERROR('НЕТ ТАКОГО НАЧАЛЬНИКА',16,10)
  ROLLBACK TRAN
  RETURN
END
--Пересчет числа подчиненных у начальника
--добавленного подчиненного
DECLARE @e CHAR(2), @m CHAR(2)
  SELECT @e=emp_mgr.emp FROM emp_mgr, inserted
  WHERE emp_mgr.emp=inserted.mgr
  UPDATE emp_mgr
  SET emp_mgr.NoOfReports=emp_mgr.NoOfReports+1
  WHERE emp_mgr.emp=@e
Пример 15.1. Триггер для добавления записи в таблицу.

Изменение записи в рекурсивной структуре

CREATE TRIGGER emp_upd ON emp_mgr
FOR UPDATE
AS
IF UPDATE(mgr)
BEGIN
--Правило 5
DECLARE @x CHAR(2), @y CHAR(2), @xx CHAR(2)
SELECT @xx=inserted.emp FROM inserted
SELECT @x=@xx
SELECT @y='*'
WHILE @y IS NOT NULL
  BEGIN
  SELECT @y=mgr FROM emp_mgr WHERE emp=@x
  IF @xx=@y
    BEGIN
      RAISERROR('транзитивное замыкание',16,10)
      ROLLBACK TRAN
      RETURN
      END
    ELSE
    SELECT @x=@y
  END
END
--Правило 2
IF EXISTS (SELECT * FROM inserted WHERE mgr=emp)
BEGIN
  ROLLBACK TRAN
  RAISERROR('САМ СЕБЕ НАЧАЛЬНИК',16,10)
  RETURN
END
--Правило 4
IF EXISTS (SELECT * FROM inserted WHERE mgr
  IS NULL) AND EXISTS (SELECT *
  FROM emp_mgr,inserted WHERE emp_mgr.mgr IS NULL
  AND emp_mgr.emp<>inserted.emp)
BEGIN
  ROLLBACK TRAN
  RAISERROR('ОДИН ДИРЕКТОР УЖЕ ЕСТЬ',16,10)
  RETURN
END
--Правило 3
IF UPDATE(mgr)
  IF NOT EXISTS(SELECT * FROM emp_mgr, inserted
    WHERE emp_mgr.emp=inserted.mgr
    OR inserted.mgr IS NULL)
BEGIN
  RAISERROR('НЕТ ТАКОГО НАЧАЛЬНИКА',16,10)
  ROLLBACK TRAN
  RETURN
END
IF UPDATE(mgr)
--пересчет числа подчиненных у старого и нового
--начальников
BEGIN
  UPDATE emp_mgr
    SET emp_mgr.NoOfReports=emp_mgr.NoOfReports+1
    FROM inserted WHERE emp_mgr.emp=inserted.mgr
    UPDATE emp_mgr
    SET emp_mgr.NoOfReports=emp_mgr.NoOfReports-1
    FROM deleted WHERE emp_mgr.emp=deleted.mgr
END
IF UPDATE(emp)
--если изменилось имя сотрудника, следует изменить
--имя начальника у всех его подчиненных
UPDATE emp_mgr SET emp_mgr.mgr=inserted.emp
FROM emp_mgr, inserted, deleted WHERE
emp_mgr.mgr=deleted.emp
Пример 15.2. Триггер для изменения записи в таблице.

Попытка подчинить сотрудника с именем ‘b’ начальнику с именем ‘e’ будет сервером отвергнута, иначе в организации сложилась бы такая ситуация: сотрудник ‘e’ подчинятся сотруднику ‘b’, а сотрудник ‘b’ подчиняется сотруднику ‘e’.

UPDATE emp_mgr SET mgr='e' WHERE emp='b'
Server: Msg 50000, Level 16, State 10,
  Procedure emp_upd, 
  Line 15 транзитивное замыкание

Выполнение команды

UPDATE emp_mgr SET mgr='f' WHERE emp='e'

и команды

UPDATE emp_mgr SET mgr='a' WHERE emp='g'

приведет к следующему изменению первоначальной иерархической структуры:

emp    mgr    NoOfReports
-------------------------
a      NULL   4
b      a      1
c      a      1
d      a      1
e      f      0
f      b      1
g      a      0
i      c      0
k      d      0

Удаление записи из рекурсивной структуры

ALTER TRIGGER emp_del
ON emp_mgr
FOR DELETE
AS
DECLARE @e CHAR(2), @m CHAR(2), @r INT
SELECT @e=emp,@m=mgr,@r=NoOfReports FROM deleted
IF @m IS NOT NULL
-- удаляется сотрудник, не являющийся директором
 BEGIN
   IF @r=0
-- удаляется сотрудник, у которого нет подчиненных
-- уменьшается число подчиненных у начальника
-- удаляемого сотрудника
   UPDATE emp_mgr SET NoOfReports=
                      NoOfReports-1
   WHERE emp=@m
  ELSE
    BEGIN
-- удаляется сотрудник, у которого есть подчиненные
-- переподчиним его подчиненных его начальнику,
-- т.е. начальником подчиненных удаляемого сотрудника
-- становится его начальник
   UPDATE emp_mgr SET NoOfReports=
                      NoOfReports+@r-1
   WHERE emp=@m
        UPDATE emp_mgr SET mgr=@m
        WHERE mgr=@e
    END
 END
 ELSE
-- Правило 4
   IF EXISTS(SELECT * FROM emp_mgr)
     BEGIN
        ROLLBACK TRAN
                 RAISERROR('НЕЛЬЗЯ УДАЛЯТЬ
                            ДИРЕКТОРА',16,10)
        RETURN
     END
Пример 15.3. Триггер для удаления записи из таблицы.

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

DELETE FROM emp_mgr WHERE emp='a'
Server: Msg 50000, Level 16, State 10,
  Procedure emp_del, Line 24
НЕЛЬЗЯ УДАЛЯТЬ ДИРЕКТОРА

В результате удаления рядового сотрудника с именем b его подчиненные e, f и g станут подчиненными сотрудника с именем a.

DELETE FROM emp_mgr WHERE emp='b'

Первоначальное содержимое таблицы emp_mgr изменится следующим образом:

emp    mgr    NoOfReports
-------------------------
a      NULL   5
c      a      1
d      a      1
e      a      0
f      a      0
g      a      0
i      c      0
k      d      0
< Лекция 14 || Лекция 15: 12 || Лекция 16 >
Федор Антонов
Федор Антонов

Здравствуйте!

Записался на ваш курс, но не понимаю как произвести оплату.

Надо ли писать заявление и, если да, то куда отправлять?

как я получу диплом о профессиональной переподготовке?

Ирина Мельник
Ирина Мельник

Здравствуйте, записалась на курс основы SQL, подскажите, стоимость курса.

Сергей Пантелеев
Сергей Пантелеев
Россия, Москва
Ахмет Арчаков
Ахмет Арчаков
Россия, Магас