【问题标题】:Can one table reference another and have extra key values that are not in the referenced table?一个表是否可以引用另一个表并具有引用表中没有的额外键值?
【发布时间】:2021-08-17 10:30:11
【问题描述】:

我想在两个表之间建立关系。

我有一个表 A (project),以 project_id 作为主键。
还有一张桌子 B (organization)。项目可以有多个组织。

问题是表 B 在project_id 中有不在表 A 中的值(但将在即将到来的表中)。

即使有不存在的键,有没有办法允许这种关系?还是我必须从表 B 中删除具有违规值的行?

【问题讨论】:

  • 我不明白你想要达到什么目的。有一个项目表。而一个项目可以有多个组织,但一个组织只能属于一个项目。一个 m:n 关系。是的?然后在组织表中有一个项目 ID。是否存在不属于某个项目的组织?然后使项目 ID 可以为空。但是,在项目表中不存在的组织表中具有项目 ID 可能意味着什么?这似乎没有意义。请详细说明。
  • 似乎您正在寻找一些 SQL 技巧,以便故意在数据库中引入 逻辑错误。不是一个好主意。退一步想一想。

标签: postgresql database-design foreign-keys relational-database ddl


【解决方案1】:

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可以是trueNULL。如果是true,则强制执行 FK 约束,否则不强制执行。实际上,您可以每行打开或关闭 FK。正是你所追求的。

这些是标准 SQL 功能。不过,一定要记录下这个诡计的目的。本着这种精神,我在project_id_valid专栏上加了cmets。

【讨论】:

  • Erwin,请不要为这些含糊不清的问题提供答案。你的答案几乎完全是猜测。 OP 必须告诉我们他们的完整架构,包括声明为键和外键的内容。在表B 中有一个project-Id,有时是外键,有时悬空指针在我看来就像糟糕的架构设计。引入可空列(尤其是键)的味道更糟。根据@Thorsten 的评论,OP 应该在这里解释业务需求是什么。
  • @AntC 当然,an example 总是有助于澄清。但是这个问题对我来说很清楚。您似乎不喜欢可为空的 FK 列。好吧,告诉全世界。我不同意。 Postgres 不同意。 SQL 标准不同意。 FK 约束的默认MATCH SIMPLE 行为就是对此的实现证明。我什至以基础知识和文档链接为首。这里没有任何误导。没有任何理由可以证明评论告诉我不要回答。
猜你喜欢
  • 1970-01-01
  • 2012-02-01
  • 2011-01-11
  • 1970-01-01
  • 2021-01-11
  • 2016-11-06
  • 2015-02-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多