我们希望在Oracle数据库中添加约束以检查员工的薪水是否与层次结构相关。 员工有身份证,姓名,职级和薪水。 我们有3个等级(rank1,rank2,rank3),rank1优于rank2,rank2优于rank3。 添加具有rank2的员工时,他的薪水不应高于rank1员工的薪水。
您能告诉我们哪种解决方案最适合实施此约束吗?
非常感谢
答案 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)
我认为你最终不得不使用触发器,因为你需要引用存在触发器的同一个表中的数据,所以它需要是一个表触发器而不是行触发器。像这样:
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;
我使用了类似的触发器来检查数据的有效性,并发现它运行良好。
分享并享受。