database - 如何处理 1 --> 0..1 关系?

标签 database foreign-keys entity-relationship cardinality

我们有一个 Claim 实体,可以通过 EmailVerification 证明,将 MetaCode 放在相关网站或上传 CertificateFile 。现在的问题是, claim 人可以选择使用上述方法的任意组合来证明他们的 claim ,但在每个类别中他们只有一次机会。含义:

 Claim -- 0..1 --> EmialVerification
 Claim -- 0..1 --> MetaCode
 Claim -- 0..1 --> CertificateFile

所以这是有效的:

 Claim #20 --> EmialVerification #12
 Claim #20 --> MetaCode (none)
 Claim #20 --> CertificateFile #124

还有这个:

 Claim #34 --> EmialVerification (none)
 Claim #34 --> MetaCode (none)
 Claim #34 --> CertificateFile (none)

不是这个:

 Claim #34 --> EmialVerification #1034 & #450
 Claim #34 --> MetaCode (none)
 Claim #34 --> CertificateFile (none)

因为 #43 与两个 EmailVerification 相关。

现在我被困在表模式中,因为我不知道如何最好地为 0..1 关系建模:

  • 四个单独的表,带有人工 PK(整数 ID),并且像往常一样使用 1..* 关系
  • 四个独立的表,但只有一个有一个 id,另外 3 个使用这个 id 作为它们自己的 PK 和 FK 到 Claim表?
  • 简单地将其他 3 个表聚合到 Claim 表中并使用 Null 来指示缺乏关系?
  • 还有别的吗?

编辑 看起来问题不是很清楚:Claim 中的一行可以连接到 0(根本没有连接)或其他 3 行中的 1 行,但任何单行Claim 中的 not 不能连接到任何其他 3 个表中的不止一行(如示例中的第 3 种情况)。

编辑 一个可怕的拼写错误潜伏在阴影中(Claim #34 在每个示例的第一行被错误地输入为 Claim #43)!!! .真对不起。顺便提一下,我认为正确答案仍然成立。

最佳答案

经过澄清注释,你好像只需要在各个校验表中存储主键即可。 (您不必使用人工键或代理键。如果“claim_num”是自然键,并且是 varchar(15),请使用“claim_num”。)

create table Claims (
  claim_id integer primary key,
  other_columns_go_here char(1) not null default 'x'
);

create table EmailVerifications (
  claim_id integer primary key references Claims (claim_id),
  email_verification_num integer not null unique,
  other_columns_go_here char(1) not null default 'x'
);

create table MetaCodes (
  claim_id integer primary key references Claims (claim_id),
  metacode_num integer not null unique,
  other_columns_go_here char(1) not null default 'x'
);

create table CertificateFiles (
  claim_id integer primary key references Claims (claim_id),
  certificate_file_num integer not null unique,
  other_columns_go_here char(1) not null default 'x'
);

这些插入会成功。

insert into Claims values (20);
insert into EmailVerifications values (20, 12);
insert into CertificateFiles values (20, 124);

前两个插入会成功。 “EmailVerifications”上的 PRIMARY KEY 约束将使第三个失败。

insert into Claims values (43);
insert into EmailVerifications values (43, 1034);
insert into EmailVerifications values (43, 450);

以下内容与明确的要求不符。将它的持续存在视为一种奖励。

如果我理解正确,您希望 Claims 中的每一行都被零行或仅一行引用。

create table Claims (
  claim_id integer primary key,
  verification_code char(1) not null
    check (verification_code in ('c', 'e', 'm')),
  unique (claim_id, verification_code),
  other_columns_go_here char(1) not null default 'x'
);

create table EmailVerifications (
  claim_id integer not null,
  verification_code char(1) not null default 'e'
    check (verification_code = 'e'),
  primary key (claim_id, verification_code),
  foreign key (claim_id, verification_code)
    references Claims (claim_id, verification_code),
  other_columns_go_here char(1) not null default 'x'
);

create table MetaCodes (
  claim_id integer not null,
  verification_code char(1) not null default 'm'
    check (verification_code = 'm'),
  primary key (claim_id, verification_code),
  foreign key (claim_id, verification_code)
    references Claims (claim_id, verification_code),
  other_columns_go_here char(1) not null default 'x'
);

create table CertificateFiles (
  claim_id integer not null,
  verification_code char(1) not null default 'c'
    check (verification_code = 'c'),
  primary key (claim_id, verification_code),
  foreign key (claim_id, verification_code)
    references Claims (claim_id, verification_code),
  other_columns_go_here char(1) not null default 'x'
);

begin;
  insert into Claims values (1, 'c', 'x');
  insert into CertificateFiles values (1, 'c', 'x');
commit;

begin;
  insert into Claims values (2, 'e', 'x');
  insert into EmailVerifications values (2, 'e', 'x');
commit;

begin;
  insert into Claims values (3, 'm', 'x');
  insert into MetaCodes values (3, 'm', 'x');
commit;

“声明”中重叠的 PRIMARY KEY 和 UNIQUE 约束是必需的。其他表引用“claim_id”和“verification_code”这对列,除非对这对列有 UNIQUE 约束,否则它们不能这样做。

verification_code 及其 CHECK 约束保证外键引用来自正确的表。

-- This insert will fail. 
-- Inserting into EmailVerifications requires 'e', not 'c'.
begin;
  insert into Claims values (4, 'c', 'x');
  insert into EmailVerifications values (4, 'c', 'x');
commit;

-- This insert will fail. (Duplicate row.)
insert into EmailVerifications values (2, 'e', 'x');

-- This insert will fail. (Trying to make two rows reference one row in Claims.)
insert into CertificateFiles values (2, 'e', 'x');

关于database - 如何处理 1 --> 0..1 关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16011259/

相关文章:

database - 雪花比索引更好?

hibernate - 让 Hibernate 生成外键索引

mysql - CakePHP 3.x 保存新记录以及新的关联记录

mysql - 汽车租赁的实体关系图 (MySQL)

mysql - 使用 MySQL 的关系模式

java - SQL 查询 1 :n relation, 查找具有两个匹配子项的所有实体

java - 从存储在数据库中的号码接收短信

python - 通过 PyCogent 列出本地 MySQL EnsEMBL 数据库中的物种名称?

mysql - 外键冗余

mysql - 识别与非识别关系(再次!!!)