怎么做1 - > 0..1的关系?

时间:2013-04-15 08:58:25

标签: database foreign-keys entity-relationship cardinality

我们有一个Claim实体,可以通过EmailVerification证明,将MetaCode放入相关网站或上传CertificateFile。现在的问题是,请求者可以选择通过使用所提到的方法的任何组合来证明他们的主张,但是在每个类别中他们只得到一次。含义:

 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中的任何一行1}} 可以连接到任何其他3个表中的多个行(如示例中的第3个案例)。

编辑一个可怕的拼写错误潜伏在阴影中(Claim #34在每个例子的第一行错误地输入Claim #43)!!! 。真对不起。我认为正确的答案仍然适用。

1 个答案:

答案 0 :(得分:1)

在澄清评论之后,您似乎只需要将主键存储在各种验证表中。 (您不必使用人工或代理键。如果“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);

以下内容与澄清的要求不符。考虑其继续存在奖金。

如果我理解正确,您希望声明中的每一行都被零行引用,或者只引用一行而只引用一行。

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;

“Claims”中的重叠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');