Oracle Trigger с условием, что старое не равно новому, с ошибками PLS-00049, PL / SQL: ORA-00933 - PullRequest
0 голосов
/ 24 октября 2018

Предполагается, что у меня есть данные в главной таблице, называемой СОТРУДНИКАМИ, с данными ниже образца:

СОТРУДНИКИ

+--------+----------+
| EMP_ID | EMP_NAME |
+--------+----------+
|    100 | Smith    |
|    200 | Clark    |
+--------+----------+

Теперь, если таблица вставлена ​​с новыми данными или обновленадля существующих данных;тогда данные выглядят следующим образом: СОТРУДНИКИ

+--------+----------+
| EMP_ID | EMP_NAME |             
+--------+----------+
|    100 | Blake    | <---- UPDATE with different value
|    200 | Clark    | <---- UPDATE with same value
|    300 | Mary     | <---- INSERT
+--------+----------+

Где строки с EMP_ID 100 и 200 являются действием обновления, а EMP_ID с 300 вставляется как его новая запись.

Я написал триггер для захвата вставки или обновления изменений в столбце EMP_NAME, только если OLD emp_name NOT EQUAL TO NEW emp_name для соответствующего EMP_ID.(Я не хочу иметь дубликаты EMP_ID в моей таблице аудита под названием EMPLOYEE_AUDITS).Ниже приведен триггер:

CREATE OR REPLACE TRIGGER employee_audits_tr 
INSERT OR UPDATE ON employees 
FOR EACH ROW 
BEGIN 
IF ( inserting OR updating AND :old.emp_name <> :new.emp_name ) THEN 
    INSERT INTO employee_audits(emp_id, old_emp_name,new_emp_name) 
                         VALUES(emp_id, :old.emp_name, :new.emp_name ) 
                         WHERE emp_id = :new.emp_id; 
END IF; 
END;

Попытка получить вывод для EMPLOYEE_AUDITS, как показано ниже, на основе данных, предоставленных выше EMPLOYEE_AUDITS

+----+--------+--------------+--------------+
| ID | EMP_ID | OLD_EMP_NAME | NEW_EMP_NAME |
+----+--------+--------------+--------------+
|  1 |    100 | Smith        | Blake        |
|  2 |    300 | NULL         | Mary         |
+----+--------+--------------+--------------+

Для следующей итерации, когда СОТРУДНИКИтаблица снова обновляется новыми данными, указанными ниже: СОТРУДНИКИ

+--------+----------+
| EMP_ID | EMP_NAME |                             
+--------+----------+
|    100 | Karla    | <---- UPDATE with NEW value  
|    200 | Clark    | <---- UPDATE with same value
|    300 | James    | <---- UPDATE with NEW value
|    400 | Sofia    | <---- INSERT                
+--------+----------+

EMPLOYEE_AUDITS таблица должна содержать значения, как показано ниже:
EMPLOYEE_AUDITS

+----+--------+--------------+--------------+
| ID | EMP_ID | OLD_EMP_NAME | NEW_EMP_NAME |
+----+--------+--------------+--------------+
|  1 |    100 | Blake        | Karla        |
|  2 |    300 | Mary         | James        |
|  3 |    400 | NULL         | Sofia        |
+----+--------+--------------+--------------+

С помощью триггера я получаю ошибку, как показано ниже:

Ошибки PLS-00049, PL / SQL: ORA-00933

Благодарю всех вас заранееи признателен за любую помощь.

Спасибо,
Рича

1 Ответ

0 голосов
/ 24 октября 2018

Неверный код триггера:

  • в объявлении триггера нет ключевого слова BEFORE
  • , вы уже сказали, что оно сработает перед вставкой или обновлением;вам не нужно помещать это и в IF
  • , если вы все-таки поместите его туда, тогда будьте осторожны: когда есть OR s, вы все испортите, если не заключите операторы вскобка.Это было бы if (updating or inserting) and (:old.emp_name <> :new.emp_name) then ....
  • обратите внимание на значения NULL!Когда вы вставляете, нет значения OLD
  • , в INSERT INTO
  • отсутствует предложение WHERE, которое вы пропустили, чтобы заполнить столбец ID в таблице AUDIT;Я решил использовать последовательность

Сочетание того, что было сказано выше (особенно отсутствует BEGIN и лишнее WHERE), вызвало ошибку ORA-00933 (команда SQL неправильно завершилась).

Вот полный пример:

SQL> create table employees (emp_id number, emp_name varchar2(20));

Table created.

SQL> insert into employees
  2  select 100, 'smith' from dual union all
  3  select 200, 'clark' from dual;

2 rows created.

SQL> create table employee_audits
  2    (id number, emp_id number, old_emp_name varchar2(20), new_emp_name varchar2(20));

Table created.

SQL> create sequence seq_audit;

Sequence created.

SQL>
SQL> create or replace trigger employee_audits_tr
  2    before insert or update on employees
  3    for each row
  4  begin
  5    if nvl(:old.emp_name, '-1') <> nvl(:new.emp_name, '-1')
  6    then
  7       insert into employee_audits
  8         (id, emp_id, old_emp_name, new_emp_name)
  9         values
 10         (seq_audit.nextval, :new.emp_id, :old.emp_name, :new.emp_name);
 11    end if;
 12  end;
 13  /

Trigger created.

Тестирование:

SQL> update employees set emp_name = 'blake' where emp_id = 100;

1 row updated.

SQL> update employees set emp_name = 'clark' where emp_id = 200;

1 row updated.

SQL> insert into employees values (300, 'mary');

1 row created.

SQL> select * From employee_audits;

        ID     EMP_ID OLD_EMP_NAME         NEW_EMP_NAME
---------- ---------- -------------------- --------------------
         1        100 smith                blake
         2        300                      mary

SQL>

[РЕДАКТИРОВАТЬ: сохранить только одну строку на сотрудника]

На мой взгляд, вы не должны этого делать - что это за аудит, если вы потеряли все предыдущие модификации?В любом случае, вот код триггера:

  • сначала он обновляет строку
  • , если EMP_ID не существует, UPDATE ничего не будет делать и SQL%ROWCOUNT будет0
  • в этом случае INSERT строка

.

SQL> create or replace trigger employee_audits_tr
  2    before insert or update on employees
  3    for each row
  4  begin
  5    update employee_audits set
  6      old_emp_name = :old.emp_name,
  7      new_emp_name = :new.emp_name
  8      where emp_id = :new.emp_id ;
  9
 10    if sql%rowcount = 0 then
 11       insert into employee_audits (id, emp_id, old_emp_name, new_emp_name)
 12       values (seq_audit.nextval, :new.emp_id, :old.emp_name, :new.emp_name);
 13    end if;
 14  end;
 15  /

Trigger created.

SQL>
...