ROB*_*ail 5 sql postgresql database-design one-to-one
我想在两个表之间创建一对一关系:teachers和office(老师是该关系的所有者)。在网上查了一下,我发现了两种不同的方法:
foreign key第一个,在 Office 表中定义并添加约束NOT NULL和UNIQUE。基本上,具有 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)
从功能上来说,在我看来这两种方法的工作原理是相同的。第一个似乎使用了一点额外的内存,因为它多了一行。
我的问题是:每种方法的优点和缺点是什么?一种方法比另一种方法“更好”吗?
我会采用第二种方法,共享主键的完全相同的值。对于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中的运行示例。
如果这确实是 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)
将自动分配的列作为外键引用是没有意义的。
| 归档时间: |
|
| 查看次数: |
13682 次 |
| 最近记录: |