Дополнительное задание 5.12

Постановка задачи

В таблицу Специальность добавить столбец Шифр_Специальности. Создать Compound-триггер, который при внесении или изменении названия специальности, будет вводить в соответствующую ячейку столбца Шифр_Специальности первые буквы каждого слова в названии специальности. Проверьте работу триггера при одновременном изменении нескольких записей одной командой UPDATE и одновременном внесении нескольких строк командой INSERT..SELECT.

Решение

Добавим столбец Шифр_Специальности:

ALTER TABLE Специальности ADD (Шифр_Специальности VARCHAR2(40));
SELECT * FROM Специальности;
КОД_СПЕЦИАЛЬНОСТИНАЗВАНИЕ_СПЕЦИАЛЬНОСТИШИФР_СПЕЦИАЛЬНОСТИ
1СИСТЕМЫ АВТОМАТИЧЕСКОГО УПРАВЛЕНИЯ(null)
2МАТЕМАТИЧЕСКОЕ ОБЕСПЕЧЕНИЕ ЭВМ(null)
3ВЫЧИСЛИТЕЛЬНЫЕ СЕТИ И СИСТЕМЫ(null)
4ЭКОНОМИКА ПРЕДПРИЯТИЙ(null)

Создадим триггер:

CREATE OR REPLACE TRIGGER Шифр_Специальности_Trg
FOR INSERT OR UPDATE OF Название_Специальности ON Специальности
COMPOUND TRIGGER

  FUNCTION getCipher (specName Специальности.Название_Специальности%TYPE)
  RETURN Специальности.Шифр_Специальности%TYPE IS
    word_re VARCHAR2(256)  := '[[:alpha:]]([-''_[:alpha:][:digit:]]*[''[:alpha:][:digit:]])?';
    letters VARCHAR2(1024) := '';
    word VARCHAR2(1024);
  BEGIN 
    IF specName IS NULL THEN RETURN NULL; END IF;
    FOR i IN 1..REGEXP_COUNT(specName, word_re) LOOP
      word    := REGEXP_SUBSTR(specName, word_re, 1, i);
      letters := letters || REGEXP_SUBSTR(word, '[[:alpha:]]', 1, 1);
    END LOOP;
    RETURN letters;
  END;

  BEFORE EACH ROW IS
  BEGIN
    -- Меняем Шифр_Специальности только если фактические значения
    -- столбцов Название_Специальности различаются
    IF UPDATING AND NOT (
      :OLD.Название_Специальности IS NULL AND :NEW.Название_Специальности IS NULL
    ) AND (
         :OLD.Название_Специальности IS NULL OR :NEW.Название_Специальности IS NULL
      OR :OLD.Название_Специальности != :NEW.Название_Специальности
    )
    THEN
      :NEW.Шифр_Специальности := getCipher(:NEW.Название_Специальности);
    END IF;
    IF INSERTING THEN
      :NEW.Шифр_Специальности := getCipher(:NEW.Название_Специальности);
    END IF;
  END BEFORE EACH ROW;

END Шифр_Специальности_Trg;
/

Результат

Добавим 3 строки:

INSERT INTO Специальности (Код_Специальности, Название_Специальности)
            SELECT 5, 'Программная инженерия'                FROM dual
  UNION ALL SELECT 6, 'Психолого-педагогическое образование' FROM dual
  UNION ALL SELECT 7, 'Ядерные физика и технологии'          FROM dual;

SELECT * FROM Специальности
ORDER BY Код_Специальности;
КОД_СПЕЦИАЛЬНОСТИНАЗВАНИЕ_СПЕЦИАЛЬНОСТИШИФР_СПЕЦИАЛЬНОСТИ
1СИСТЕМЫ АВТОМАТИЧЕСКОГО УПРАВЛЕНИЯ(null)
2МАТЕМАТИЧЕСКОЕ ОБЕСПЕЧЕНИЕ ЭВМ(null)
3ВЫЧИСЛИТЕЛЬНЫЕ СЕТИ И СИСТЕМЫ(null)
4ЭКОНОМИКА ПРЕДПРИЯТИЙ(null)
5Программная инженерияПи
6Психолого-педагогическое образованиеПо
7Ядерные физика и технологииЯфит

Заметим, что специальность «Психолого-педагогическое образование» получила шифр «По», т.к. «психолого-педагогическое» — одно слово в русском языке. Строки, которые были в таблице до INSERT'а не получили новый шифр, т.к. соответствующие фактические значения названий специальностей не изменились.

Обновим все строки таблицы:

UPDATE Специальности
SET Название_Специальности = LOWER(Название_Специальности);

SELECT * FROM Специальности
ORDER BY Код_Специальности;
КОД_СПЕЦИАЛЬНОСТИНАЗВАНИЕ_СПЕЦИАЛЬНОСТИШИФР_СПЕЦИАЛЬНОСТИ
1системы автоматического управлениясау
2математическое обеспечение эвммоэ
3вычислительные сети и системывсис
4экономика предприятийэп
5программная инженерияпи
6психолого-педагогическое образованиепо
7ядерные физика и технологиияфит