PostgreSQL - 一对一 - 哪种方法“更好”?

ROB*_*ail 5 sql postgresql database-design one-to-one

我想在两个表之间创建一对一关系:teachersoffice(老师是该关系的所有者)。在网上查了一下,我发现了两种不同的方法:

foreign key第一个,在 Office 表中定义并添加约束NOT NULLUNIQUE。基本上,具有 UNIQUE 约束的强制性一对多关系:如下所示:

CREATE TABLE office(
    id SERIAL PRIMARY KEY,
    floor SMALLINT CHECK (floor > 0 AND floor <= 10),
    size SMALLINT CHECK (size > 0),
    teacher_id INTEGER NOT NULL UNIQUE REFERENCES teachers(teacher_id)
);
Run Code Online (Sandbox Code Playgroud)

第二个是我们办公桌上的 和 合并为一排就像这样:primary key foreign key

CREATE TABLE office(
    id SERIAL PRIMARY KEY REFERENCES teachers(teacher_id),
    floor SMALLINT CHECK (floor > 0 AND floor <= 10),
    size SMALLINT CHECK (size > 0)
);
Run Code Online (Sandbox Code Playgroud)

从功能上来说,在我看来这两种方法的工作原理是相同的。第一个似乎使用了一点额外的内存,因为它多了一行。

我的问题是:每种方法的优点和缺点是什么?一种方法比另一种方法“更好”吗?

The*_*ler 8

我会采用第二种方法,共享主键的完全相同的值。对于office表来说,主键不应该是自动生成的 ( serial) 而只是一个int.

例如你可以这样做:

create table teachers (
  id int primary key not null,
  name varchar(20) not null
);

create table office (
  id int primary key references teachers (id),
  floor smallint check (floor > 0 and floor <= 10),
  size smallint check (size > 0)
);

alter table teachers
add constraint fk_uq1_teachers_office
foreign key (id) references office (id) deferrable initially deferred;
Run Code Online (Sandbox Code Playgroud)

然后插入数据可能如下所示:

begin transaction;

insert into teachers (id, name) values (100, 'Mary');

insert into office (id, floor, size) values (100, 3, 850);

commit;
Run Code Online (Sandbox Code Playgroud)

请注意,为了强制执行 1-1 关系,您需要有两个外键:一个 from teachersto office,一个 from officeto teachers。否则,应用程序可能会将数据插入到 中teachers,却忘记插入到 中office。幸运的是,您使用的 PostgreSQL 实现了约束延迟性的标准SQL 功能,如上所示。

请参阅DB Fiddle中的运行示例。


Gor*_*off 5

如果这确实是 1-1 关系,为什么不在表中包含描述办公室的列呢teachers

您不想这样做可能是有原因的。一个重要原因是offices可以在没有s的情况下存在teacher。例如,如果您的学校没有夏季课程,那么办公室将继续存在。

这表明办公室独立于教师。因此,您需要一个单独的表,并为它们提供单独的主键。

在你的第二个模型中——主键外键teachers——你本质上是在说办公室是一种教师,而不是一个单独的实体。

不过有两个注意事项:

首先,Postgres 不推荐generated always as identity而是推荐serial. 第二个表不应该使用serial主键列;它应该是int

CREATE TABLE office (
    id int PRIMARY KEY REFERENCES teachers(teacher_id),
    floor SMALLINT CHECK (floor > 0 AND floor <= 10),
    size SMALLINT CHECK (size > 0)
);
Run Code Online (Sandbox Code Playgroud)

将自动分配的列作为外键引用是没有意义的。