Добавление ограничения в базу данных Oracle - PullRequest
1 голос
/ 04 ноября 2010

Мы хотим добавить ограничение в базу данных Oracle, чтобы проверить, соответствует ли зарплата сотрудника иерархии.У работника есть идентификатор, имя, звание и зарплата.У нас есть 3 ранга (ранг1, ранг2, ранг3), ранг1 превосходит ранг2, а ранг2 превосходит ранг3.При добавлении сотрудника с рангом 2 его зарплата не должна превышать зарплату сотрудника с рангом 1.

Можете ли вы сказать нам, какое решение является лучшим для реализации этого ограничения?Большое спасибо

Ответы [ 2 ]

3 голосов
/ 04 ноября 2010

Это не может быть сделано с проверочным ограничением, потому что они могут смотреть только на значения в строке, которая вставляется или обновляется, а не на другие таблицы или другие строки в той же таблице.

Я экспериментировал сподход с использованием материализованных представлений и проверочных ограничений - см. мой блог .Хитрость заключается в том, чтобы создать материализованное представление исключений из правила - то есть материализованное представление, которое всегда должно быть пустым.Затем добавьте проверочное ограничение к MV, которое всегда терпит неудачу, например, CHECK (1 = 0).

Для вашей ситуации решение будет выглядеть примерно так:

create materialized view emp_emp_mv
refresh complete on commit as
select 1 dummy
from emp e1, emp e2
where e1.empno != e2.empno
and e1.rank < e2.rank
and e1.sal > e2.sal;

alter table emp_emp_mv
add constraint emp_emp_mv_chk
check (1=0) deferrable;

Обратите внимание:

  1. Я не проверял приведенный выше пример
  2. Я никогда не использовал этот подход в «реальной» системе, только в экспериментах.
2 голосов
/ 04 ноября 2010

Я думаю, вам в конечном итоге придется использовать триггер, и, поскольку вам нужно будет ссылаться на данные в той же таблице, для которой существует триггер, он должен быть триггером таблицы, а не триггером строки. Примерно так:

CREATE OR REPLACE TRIGGER EMPLOYEES_AIU
  AFTER INSERT OR UPDATE ON EMPLOYEES
  -- Note: There is no FOR EACH ROW here so 'OLD' and 'NEW' values are not available
DECLARE
  strPrev_rank      EMPLOYEES.RANK%TYPE;
  nPrev_max_salary  EMPLOYEES.SALARY%TYPE;
BEGIN
  FOR aRow IN (SELECT RANK, MAX(SALARY) AS MAX_SALARY
                 FROM EMPLOYEES
                 GROUP BY RANK
                 ORDER BY RANK DESC)
  LOOP
    IF nPrev_max_salary IS NOT NULL AND
         aRow.MAX_SALARY > nPrev_max_salary THEN
      RAISE_APPLICATION_ERROR(-20101, 'Max salary (' || aRow.MAX_SALARY||
                                      ') of rank ' || aRow.RANK ||
                                      ' exceeds max salary (' || nPrev_max_salary ||
                                      ') of rank ' || strPrev_rank);
    END IF;

    strPrev_rank := aRow.RANK;
    nPrev_max_salary := aRow.MAX_SALARY;
  END LOOP;
END EMPLOYEES_AIU;

Я использовал подобные триггеры для проверки достоверности данных и обнаружил, что они хорошо работают.

Делись и наслаждайся.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...