一对多关系的最大限制-Oracle SQL

Sea*_*Mci 5 sql oracle entity-relationship

我想使用Orcale SQL开发人员来绘制员工与经理之间的关系。但是,一个经理最多只能监督3名员工。

员工表

上面我有一个雇员表,其中经理ID为外键。这与employee表具有一对多关系。

可以将此关系限制为最多3个吗?

谢谢。

GMB*_*GMB 4

这不能通过检查约束来完成。应该可以创建一个物化视图,对每个管理器的出现次数进行计数,并对计数进行检查约束,并在原始表上提交时刷新。正如 Littlefoot 所演示的那样,可以使用复合触发器来实现相同的效果。但这不太可扩展,因为每次提交后都需要扫描整个表以刷新物化视图。

一种替代解决方案是:

  • 创建一个新表来跟踪每个经理出现的次数,例如employee_manager_cnt

  • 在表上设置触发器 employee以保持表employee_manager_cnt最新(无需扫描整个表,只需根据 的新旧值反映更改manager_id

  • 向 中添加一个检查约束,employee_manager_cnt禁止值高于目标计数

这是一个分步演示,其灵感来自nop77svk 对这个问题的回答

原表:

create table employees (
    employee_id number primary key,
    manager_id number
);
Run Code Online (Sandbox Code Playgroud)

插入几条记录:

begin
    insert into employees values(1, null);
    insert into employees values(2, 1);
    insert into employees values(3, 1);
    insert into employees values(4, 1);    -- manager 1 has 3 employees
    insert into employees values(5, null);
    insert into employees values(6, 5);    -- manager 5 has just 1 employee
end;
/
Run Code Online (Sandbox Code Playgroud)

创建新表:

create table employee_manager_cnt (
    manager_id          number not null primary key,
    cnt                 number(1, 0) not null check (cnt <= 3)
);
Run Code Online (Sandbox Code Playgroud)

填充它:

insert into employee_manager_cnt(manager_id, cnt)
select manager_id, count(*) 
from employees 
where manager_id is not null
group by manager_id
Run Code Online (Sandbox Code Playgroud)

检查结果:

MANAGER_ID  CNT
1           3
5           1
Run Code Online (Sandbox Code Playgroud)

现在,创建触发器:

create or replace trigger trg_employee_manager_cnt
    after insert or delete or update of manager_id
    on employees
    for each row
begin

    -- decrease the counter when an employee changes manager or is removed
    if updating or deleting then
        merge into employee_manager_cnt t
        using dual
        on ( t.manager_id = :old.manager_id )
        when matched then
            update set t.cnt = t.cnt - 1
            delete where t.cnt = 0
        ;
    end if;

    -- increase the counter when a employee changes manager or is added
    if inserting or updating then
        merge into employee_manager_cnt T
        using dual
        on ( t.manager_id = :new.manager_id )
        when matched then
            update set t.cnt = t.cnt + 1
        when not matched then
            insert (manager_id, cnt) values (:new.manager_id, 1)
        ;
    end if;
end;
/
Run Code Online (Sandbox Code Playgroud)

现在尝试添加一条引用经理 1(已有 3 名员工)的新记录

insert into employees values(4, 1);
-- error: ORA-00001: unique constraint (FIDDLE_QOWWVSAIOXRDGYREFVKM.SYS_C00276396) violated
Run Code Online (Sandbox Code Playgroud)

同时,仍然有可能影响经理 5 的新员工(他只有一名员工):

insert into employees values(10, 5);
-- 1 rows affected
Run Code Online (Sandbox Code Playgroud)