如何使用1个可选的默认值建模m:n?

时间:2009-08-12 04:41:39

标签: sql database-design

下面是两个模式,我相信它会获得相同的结果,即m:n与默认/首选值选项的关系。有没有理由使用其中一个?

架构#1

CREATE TABLE people (
  id serial,
  primary key (id)
);

CREATE TABLE names (
  id serial,
  first_name text not null,
  last_name text not null,
  primary key (id)
);

CREATE TABLE person_has_name (
  person_id integer not null references people (id),
  name_id integer not null references names (id),
  is_default boolean not null default false,
  primary key (person_id, name_id)
);

架构#2

CREATE TABLE people (
  id serial,
  default_name_id integer references names (id),
  primary key (id)
);

-- this table has not changed
CREATE TABLE names (
  id serial,
  first_name text not null,
  last_name text not null,
  primary key (id)
);

CREATE TABLE person_has_name (
      person_id integer not null references people (id),
      name_id integer not null references names (id),
      primary key (person_id, name_id)
);

3 个答案:

答案 0 :(得分:1)

让我们分析一下:

  • 第二个架构阻止您将多个name设置为默认值,但不要阻止您将某些不相关的名称设置为默认name
  • 第一个架构发生了相反的情况。

我向你(对你的僵尸用户)建议解决数学问题的第三个模式:

CREATE TABLE people (
  id serial,
  default_name_id integer , 
  primary key (id),
  constraint default_person_name_fk          --<--HERE
    foreign key (id, default_name_id)
    references person_has_name  (person_id, name_id)
);

-- this table has not changed
CREATE TABLE names (
  id serial,
  first_name text not null,
  last_name text not null,
  primary key (id)
);

CREATE TABLE person_has_name (
   person_id integer not null references people (id),
   name_id integer not null references names (id),
   primary key (person_id, name_id)

);

对延迟感到抱歉和抱歉,我迟到了;)

答案 1 :(得分:0)

使用第二个架构,您无法在不知道其名称的情况下添加人员。只要这是可以的(即你知道无论什么时候添加一个人,他们都必须透露他们的名字),那么我会说这些模式中的任何一个都很好,并且模式#2甚至可能在您只需要查询默认名称的方案。

答案 2 :(得分:0)

我不会使用这两个。

解决方案1不会阻止您拥有2个人的默认名称。

解决方案2不会阻止具有默认名称的人不是他的。您可以将外键从default_name_id references names(id)更改为(person_id, default_name_id) references person_has_name(person_id, name_id),但之后您将获得循环引用,这是另一个难以解决的问题。

你可以使用它,类似于你的第二个解决方案:

CREATE TABLE people (
  id serial, 
                           --- no  default_name_id as foreign key here
  primary key (id)
);

CREATE TABLE names (
  id serial,
  first_name text not null,
  last_name text not null,
  primary key (id)
);

CREATE TABLE person_has_name (
  person_id integer not null references people (id),
  name_id integer not null references names (id),
  primary key (person_id, name_id)
);

使用此额外表格,对于那些具有默认名称的人:

CREATE TABLE person_default_name (
  person_id integer not null,
  name_id integer not null,
  primary key (person_id),
  foreign key (person_id, name_id) 
    references person_has_name (person_id, name_id) 
);