多个外键作为主键postgres,我应该这样做吗?
multiple foreign keys as primary key postgres, should I do it?
这是其中之一:为什么我应该或为什么不应该。
所以我的图书应用程序有评论,但一个用户不能对同一本书评论超过一次。在我看来,为评论创建 table 并将 user_id 和 book_id (ISBN) 作为评论 table 的主键是有意义的。但是,如果应用程序获得太多评论,在某些时候是否会成为问题,例如,该决定会减慢查询速度吗?
我正在使用 postgres,我不确定下面的代码是否正确:
CREATE TABLE users(
user_id PRIMARY KEY SERIAL,
user_name VARCHAR NOT NULL UNIQUE,
pass_hash VARCHAR NOT NULL,
email VARCHAR NOT NULL UNIQUE,
);
CREATE TABLE books(
book_id PRIMARY KEY BIGINT,
author VARCHAR NOT NULL,
title VARCHAR NOT NULL,
year INT NOT NULL CHECK (year > 1484),
review_count INT DEFAULT 0 NOT NULL,
avrg_score FLOAT,
);
CREATE TABLE reviews(
user_id INT FOREIGN KEY REFERENCES users(user_id) NOT NULL
book_id INT FOREIGN KEY REFERENCES books(book_id) NOT NULL
score INT NOT NULL CHECK (score > 0, score < 11)
PRIMARY KEY (book_id, user_id)
);
这是一个完全有效的设计选择。
您的图书和用户之间存在多对多关系,由 reviews
table 表示。拥有基于两个外键的复合主键可以让您强制执行参照完整性(给定的元组只能出现一次),同时为 table.
提供主键
另一种选择是为桥table设置一个代理主键。如果您需要从另一个 table 引用 reviews
,这会使事情变得更容易,但是您仍然需要对两个外键列进行唯一约束以确保完整性,因此这实际上会导致额外的 space 正在使用中。
关于您的代码,它有几个问题:
primary key
关键字位于数据类型
之后
check
约束的格式不正确
此处和此处缺少或添加逗号
考虑:
CREATE TABLE users(
user_id SERIAL PRIMARY KEY ,
user_name VARCHAR NOT NULL UNIQUE,
pass_hash VARCHAR NOT NULL,
email VARCHAR NOT NULL UNIQUE
);
CREATE TABLE books(
book_id BIGINT PRIMARY KEY,
author VARCHAR NOT NULL,
title VARCHAR NOT NULL,
year INT NOT NULL CHECK (year > 1484),
review_count INT DEFAULT 0 NOT NULL,
avrg_score FLOAT
);
CREATE TABLE reviews(
user_id INT REFERENCES users(user_id) NOT NULL,
book_id INT REFERENCES books(book_id) NOT NULL,
score INT NOT NULL CHECK (score > 0 and score < 11),
PRIMARY KEY (book_id, user_id)
);
我上面的内容很好,但我会从书中删除列 review_count 和 avrg_score。这些在需要时是可推导的。如果您的应用程序需要,那么不要存储它们,而是创建一个视图来派生它们。这避免了维护 运行 值的复杂过程:
create view books_vw as
select b.book_id
, b.author
, b.title
, b.year
, count(r.*) review_count
, avg(r.score) avrg_score
from books b
left join reviews r
on r.book_id = b.book_id
group by
b.book_id
, b.author
, b.title
, b.year
;
这是其中之一:为什么我应该或为什么不应该。
所以我的图书应用程序有评论,但一个用户不能对同一本书评论超过一次。在我看来,为评论创建 table 并将 user_id 和 book_id (ISBN) 作为评论 table 的主键是有意义的。但是,如果应用程序获得太多评论,在某些时候是否会成为问题,例如,该决定会减慢查询速度吗?
我正在使用 postgres,我不确定下面的代码是否正确:
CREATE TABLE users(
user_id PRIMARY KEY SERIAL,
user_name VARCHAR NOT NULL UNIQUE,
pass_hash VARCHAR NOT NULL,
email VARCHAR NOT NULL UNIQUE,
);
CREATE TABLE books(
book_id PRIMARY KEY BIGINT,
author VARCHAR NOT NULL,
title VARCHAR NOT NULL,
year INT NOT NULL CHECK (year > 1484),
review_count INT DEFAULT 0 NOT NULL,
avrg_score FLOAT,
);
CREATE TABLE reviews(
user_id INT FOREIGN KEY REFERENCES users(user_id) NOT NULL
book_id INT FOREIGN KEY REFERENCES books(book_id) NOT NULL
score INT NOT NULL CHECK (score > 0, score < 11)
PRIMARY KEY (book_id, user_id)
);
这是一个完全有效的设计选择。
您的图书和用户之间存在多对多关系,由 reviews
table 表示。拥有基于两个外键的复合主键可以让您强制执行参照完整性(给定的元组只能出现一次),同时为 table.
另一种选择是为桥table设置一个代理主键。如果您需要从另一个 table 引用 reviews
,这会使事情变得更容易,但是您仍然需要对两个外键列进行唯一约束以确保完整性,因此这实际上会导致额外的 space 正在使用中。
关于您的代码,它有几个问题:
primary key
关键字位于数据类型 之后
check
约束的格式不正确此处和此处缺少或添加逗号
考虑:
CREATE TABLE users(
user_id SERIAL PRIMARY KEY ,
user_name VARCHAR NOT NULL UNIQUE,
pass_hash VARCHAR NOT NULL,
email VARCHAR NOT NULL UNIQUE
);
CREATE TABLE books(
book_id BIGINT PRIMARY KEY,
author VARCHAR NOT NULL,
title VARCHAR NOT NULL,
year INT NOT NULL CHECK (year > 1484),
review_count INT DEFAULT 0 NOT NULL,
avrg_score FLOAT
);
CREATE TABLE reviews(
user_id INT REFERENCES users(user_id) NOT NULL,
book_id INT REFERENCES books(book_id) NOT NULL,
score INT NOT NULL CHECK (score > 0 and score < 11),
PRIMARY KEY (book_id, user_id)
);
我上面的内容很好,但我会从书中删除列 review_count 和 avrg_score。这些在需要时是可推导的。如果您的应用程序需要,那么不要存储它们,而是创建一个视图来派生它们。这避免了维护 运行 值的复杂过程:
create view books_vw as
select b.book_id
, b.author
, b.title
, b.year
, count(r.*) review_count
, avg(r.score) avrg_score
from books b
left join reviews r
on r.book_id = b.book_id
group by
b.book_id
, b.author
, b.title
, b.year
;