在Oracle数据库中添加约束

时间:2010-11-04 11:21:06

标签: sql oracle plsql

我们希望在Oracle数据库中添加约束以检查员工的薪水是否与层次结构相关。 员工有身份证,姓名,职级和薪水。 我们有3个等级(rank1,rank2,rank3),rank1优于rank2,rank2优于rank3。 添加具有rank2的员工时,他的薪水不应高于rank1员工的薪水。

您能告诉我们哪种解决方案最适合实施此约束吗?

非常感谢

2 个答案:

答案 0 :(得分:3)

使用检查约束无法完成,因为这些只能查看正在插入或更新的行中的值,而不能查看同一个表中的其他表或其他行。

我已尝试使用物化视图和检查约束的方法 - 请参阅my blog。诀窍是创建规则例外的物化视图 - 即应该始终为空的物化视图。然后将一个检查约束添加到总是失败的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. 我从未在“真实”系统中使用过这种方法,仅用于实验。

答案 1 :(得分:2)

我认为你最终不得不使用触发器,因为你需要引用存在触发器的同一个表中的数据,所以它需要是一个表触发器而不是行触发器。像这样:

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;

我使用了类似的触发器来检查数据的有效性,并发现它运行良好。

分享并享受。