FOREIGN KEY constraint 的全部目的是禁止表 B 中违反约束的行 - 并确保这一点。
也就是说,您可以利用 多列 FK 约束 的默认 MATCH SIMPLE 行为来获得一个优雅的解决方案:如果至少包含一个列,则不强制执行 FK是NULL。见:
您需要一个额外的列,即我的演示中的布尔标志 valid:
CREATE TABLE project (
project_id int NOT NULL GENERATED ALWAYS AS IDENTITY
, project text NOT NULL
, project_id_valid boolean NOT NULL DEFAULT true -- NOT NULL!
, PRIMARY KEY(project_id, project_id_valid) -- !
, CONSTRAINT project_id_always_valid CHECK (project_id_valid) -- only true
);
COMMENT ON COLUMN project.project_id_valid IS 'Redundant column to allow conditional multicolumn FK reference in table organization';
INSERT INTO project(project) VALUES ('project1');
CREATE TABLE organization (
org_id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY
, org text NOT NULL
, project_id integer NOT NULL
, project_id_valid boolean DEFAULT true -- can be NULL!
, CONSTRAINT valid_project_fk FOREIGN KEY (project_id, project_id_valid) REFERENCES project -- !
, CONSTRAINT project_id_valid_or_null CHECK (project_id_valid) -- only true
);
COMMENT ON COLUMN project.project_id_valid IS 'TRUE enforces the FK constraint valid_project_fk.';
db小提琴here
模型已简化。实际的组织会有多个项目,您会使用多对多的实现。见:
CONSTRAINT project_id_always_valid CHECK (valid) 与列上的NOT NULL 组合强制将project.project_id_valid 始终为true,这使其成为噪声列。我们需要它用于多列 PK 以允许我们在 organization 中的多列 FK 约束。 (或者,在 (project_id) 上使用普通 PK 并在 (project_id, project_id_valid) 上添加多列 UNIQUE 约束。)
对应的列organization.valid可以是true或NULL。如果是true,则强制执行 FK 约束,否则不强制执行。实际上,您可以每行打开或关闭 FK。正是你所追求的。
这些是标准 SQL 功能。不过,一定要记录下这个诡计的目的。本着这种精神,我在project_id_valid专栏上加了cmets。