简体   繁体   English

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

[英]multiple foreign keys as primary key postgres, should I do it?

This is one of those: why I should or why I should not.这是其中之一:为什么我应该或为什么我不应该。

So my books app has reviews, but one user must not review the same book more than one time.所以我的图书应用程序有评论,但一个用户不得多次评论同一本书。 In my point of view makes sense to create a table for the reviews and make the user_id and the book_id (ISBN) as the PRIMARY KEY for the reviews table.在我看来,为评论创建一个表并将 user_id 和 book_id (ISBN) 作为评论表的主键是有意义的。 But, could it be a problem at some point if the application gets too many reviews, for example, could that decision slow the queries?但是,如果应用程序获得太多评论,是否会在某个时候成为问题,例如,该决定会减慢查询速度吗?

I am using postgres and I am not sure if the following code is correct:我正在使用 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)

);

This is a perfectly valid design choice.这是一个完全有效的设计选择。

You have a many-to-many relationship between books and users, which is represented by the reviews table.书籍和用户之间存在多对多关系,由reviews表表示。 Having a compound primary key based on two foreign keys lets you enforce referential integrity (a given tuple may only appear once), and at the same time provide a primary key for the table.拥有一个基于两个外键的复合主键可以让您强制执行参照完整性(给定的元组可能只出现一次),同时为表提供一个主键。

Another option would be to have a surrogate primary key for the bridge table.另一种选择是为桥表设置代理主键。 This could make things easier if you need to reference the reviews from another table, but you would still need a unique constraint on both foreign key columns for integrity, so this would actually result in extra space being used.如果您需要从另一个表中引用reviews ,这可以使事情变得更容易,但是您仍然需要对两个外键列进行唯一约束以保持完整性,因此这实际上会导致使用额外的空间。

When it comes to your code, it has a few issues:当涉及到您的代码时,它有一些问题:

  • the primary key keyword goes after the datatype primary key关键字在数据类型之后

  • the check constraint is incorrectly formed check约束的格式不正确

  • missing or additional commas here and there此处和那里缺少或附加逗号

Consider:考虑:

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)

);

I the above is good but I would drop columns review_count and avrg_score from books.我上面的内容很好,但我会从书中删除列 review_count 和 avrg_score。 These are derivable when needed.这些是在需要时可导出的。 If needed for your application then instead of storing these create a view to derive them.如果您的应用程序需要,那么不要存储这些,而是创建一个视图来派生它们。 This avoids the always complicated process of maintaining running values:这避免了维护运行值的复杂过程:

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                  
 ;          

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM