如何强制两个外键列都为 null 或都指向 Oracle 中其他 table 中的某行?

How to enforce two foreign key columns to be either both null or both pointing to some row in other table in Oracle?

我有两个 table,Employees 和 Tasks(这当然不是实际的 SQL 代码,只列出了重要的内容):

CREATE TABLE Employees (
    employee_id      NUMBER(6) NOT NULL,
    is_boss          NUMBER(1) DEFAULT 0 NOT NULL,
    name             VARCHAR2(32) NOT NULL,

    CHECK (is_boss IN (0,1)),
    UNIQUE (is_boss, employee_id)
);

CREATE TABLE Tasks (
    task_id          NUMBER(6) NOT NULL,
    name             VARCHAR2(32) NOT NULL,
    is_boss          NUMBER(1),
    employee_id      NUMBER(6),
    finish_date      DATE,

    CHECK (is_boss IN (1)),
    FOREIGN KEY (employee_id) REFERENCES Employees (employee_id),
    FOREIGN KEY (is_boss) REFERENCES Employees (is_boss)
);

因此任务 table 包含一些任务。当它们被添加到 table 时,我们只需要名称和 ID,这就是为什么其他字段可以为 null 的原因。在某个时间点,每个任务都必须由 "boss" 确认,所以一个员工 is_boss == 1 然后才 finish_date ,非常简单。

如果任务同时更新为 is_bossemployee_id,那么这些检查约束和 foreign/unique 键会很好地工作——如果员工不是老板,它会抛出错误,如果也没有这样的员工。但是,如果其中之一为空,则一切都会出错。所以我想要的是以某种方式强制数据库检查这两个字段是否均不为空或均为空。实际上,我希望 3 个字段(finish_date 也是)全部为空或全部不为空。

触发器可能是一个选项,但如果有不同的、更简单的可能性,我的数据库老师非常反对使用它们。所以我的问题是 - 有没有办法在没有触发器的情况下强制执行它?数据库管理系统是 Oracle 11g。

提前致谢。

您需要将两个外键组合成一个外键 - 否则我认为您会发现它们并没有像您认为的那样做。此外,您需要一个检查约束以确保所有三个字段都已设置或所有三个字段都为 NULL。您的任务 table 需要类似于:

CREATE TABLE TASKS (
    TASK_ID          NUMBER(6) NOT NULL,
    NAME             VARCHAR2(32) NOT NULL,
    IS_BOSS          NUMBER(1),
    EMPLOYEE_ID      NUMBER(6),
    FINISH_DATE      DATE,

    CONSTRAINT TASKS_CK1
      CHECK (is_boss IN (1)),
    CONSTRAINT TASKS_FK1
      FOREIGN KEY (IS_BOSS, EMPLOYEE_ID)
        REFERENCES EMPLOYEES (IS_BOSS, EMPLOYEE_ID),
    CONSTRAINT TASKS_CK2
      CHECK((IS_BOSS IS NULL AND
               EMPLOYEE_ID IS NULL AND
               FINISH_DATE IS NULL)
            OR
            (IS_BOSS IS NOT NULL AND
               EMPLOYEE_ID IS NOT NULL AND
               FINISH_DATE IS NOT NULL))
);