Sql 多个外键作为主键Postgre,我应该这样做吗?

Sql 多个外键作为主键Postgre,我应该这样做吗?,sql,database,postgresql,foreign-keys,primary-key,Sql,Database,Postgresql,Foreign Keys,Primary Key,这就是其中之一:为什么我应该或者为什么我不应该 所以我的图书应用程序有评论,但是一个用户不能对同一本书评论超过一次。在我看来,为评论创建一个表并将用户id和图书id(ISBN)作为评论表的主键是有意义的。但是,如果应用程序得到太多的评论,在某一点上可能会有问题吗?例如,这个决定会减缓查询速度吗 我正在使用postgres,我不确定以下代码是否正确: CREATE TABLE users( user_id PRIMARY KEY SERIAL, user_name VARCHAR

这就是其中之一:为什么我应该或者为什么我不应该

所以我的图书应用程序有评论,但是一个用户不能对同一本书评论超过一次。在我看来,为评论创建一个表并将用户id和图书id(ISBN)作为评论表的主键是有意义的。但是,如果应用程序得到太多的评论,在某一点上可能会有问题吗?例如,这个决定会减缓查询速度吗

我正在使用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)

);
创建表用户(
用户id主键序列号,
用户名VARCHAR非空唯一,
pass_hash VARCHAR不为空,
电子邮件VARCHAR NOT NULL UNIQUE,
);
创建桌面书(
book_id主键BIGINT,
作者VARCHAR不为空,
title VARCHAR不为空,
年份INT非空检查(年份>1484),
review_count INT默认值0不为空,
avrg_分数浮动,
);
创建表评论(
user\u id INT外键引用用户(user\u id)不为NULL
book_id INT外键参考书籍(book_id)不为空
分数整数非空检查(分数>0,分数<11)
主键(图书id、用户id)
);

这是一个非常有效的设计选择

书籍和用户之间存在多对多关系,这一关系由
reviews
表表示。使用基于两个外键的复合主键可以强制引用完整性(给定元组只能出现一次),同时为表提供主键

另一种选择是为桥接表提供代理主键。如果您需要从另一个表中引用
审阅
,这会使事情变得更容易,但是您仍然需要在两个外键列上都有一个唯一的完整性约束,因此这实际上会导致使用额外的空间

当涉及到您的代码时,它有几个问题:

  • 主键
    关键字位于数据类型之后

  • 检查
    约束的格式不正确

  • 此处和此处缺少或添加逗号

考虑:

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)

);
创建表用户(
用户id串行主键,
用户名VARCHAR非空唯一,
pass_hash VARCHAR不为空,
电子邮件VARCHAR非空唯一
);
创建桌面书(
book_id BIGINT主键,
作者VARCHAR不为空,
title VARCHAR不为空,
年份INT非空检查(年份>1484),
review_count INT默认值0不为空,
avrg_分数浮动
);
创建表评论(
user\u id INT引用的用户(user\u id)不为NULL,
图书id INT参考图书(图书id)不为空,
分数INT非空检查(分数>0且分数<11),
主键(图书id、用户id)
);

I上面的内容很好,但我会从书中删除列review\u count和avrg\u 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                  
 ;          

谢谢,这真的很有启发性=道指,很好的观点,我在获取数据时没有考虑这个问题。我认为这很有意义,因为数据库的工作会更好。谢谢大家!=D