Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 一列中有许多外键_Sql_Postgresql_Select - Fatal编程技术网

Sql 一列中有许多外键

Sql 一列中有许多外键,sql,postgresql,select,Sql,Postgresql,Select,我在Postgres中有一个图书数据库,我想添加一个authorId列,但当一本书有许多作者时,我不知道如何使它工作 作者表 authorId firstName lastName 1 Terry Pratchett 2 Neil Gaiman 书桌 bookId name authorId 1 Good Omens 1, 2 我如何让它工作?我的第一个

我在Postgres中有一个图书数据库,我想添加一个authorId列,但当一本书有许多作者时,我不知道如何使它工作

作者表

authorId    firstName    lastName
1           Terry        Pratchett
2           Neil         Gaiman
书桌

bookId    name             authorId
1         Good Omens       1, 2
我如何让它工作?我的第一个想法是将authorId存储为数组

我想要的查询应该是这样的

SELECT firstName, lastName 
FROM author 
WHERE authorId IN 
    (SELECT authorId 
     FROM book 
     WHERE bookId=1);
它会返回这个

firstName    lastName
Terry        Pratchett
Neil         Gaiman
但我有一种感觉,这是行不通的,有一种更好的方法可以做到。

m:n关系(一个作者可以写很多书+一本书可以由很多作者写)最好用桥牌表来建模:

  • 作者(作者id、名、姓)
  • 书(书号、书名)
  • 图书作者(图书id,作者id)
获取书籍#1的作者的查询:


教科书上的解决方案将是有一个额外的“映射”表来映射书籍和作者。这样一来,一位作者可能会写几本书,而一本书可能会有几位作者:

CREATE TABLE book_authors (
    author_id INT NOT NULL,
    book_id INT NOT NULL,
    PRIMARY KEY book_authors_pk (author_id, book_id),
    FOREIGN KEY author_fk (author_id) REFERENCES authors (author_id),
    FOREIGN KEY book_fk (book_id) REFERENCES books (book_id)
)
然后,您可以使用
join
查询书籍的作者:

SELECT first_name, last_name
FROM   authors a
JOIN   book_authors ba on a.author_id = ba.author_id
WHERE  book_id = 1
或者,如果您没有该书的id,另一个与
books
的连接将允许您查询其详细信息:

SELECT first_name, last_name
FROM   authors a
JOIN   book_authors ba ON a.author_id = ba.author_id
JOIN   books b ON ba.book_id = b.book_id
WHERE  b.name = 'Good Omens'

是的,使用postgres这一事实为您提供了将Authorid存储为数组的绝佳选择。您可以按如下方式定义表:

CREATE TABLE Book (
 bookId serial not null,
 name varchar,
 authorIds int[]
);
您的select查询应该是

SELECT firstName, lastName 
FROM author 
WHERE authorId IN 
 (SELECT unnest(authorIds) 
  FROM Book 
  WHERE bookId = 1);

那是个可怕的主意。您应该了解规范化我不认为这是一个可怕的想法,规范化并不总是实践中的最佳选择(增加冗余、管理更多的表、更多的连接、较差的性能等等),这就是为什么Postgres有一种广泛用于industry@pedram巴希里:你错了。规范化从不增加冗余,因为规范化的主要目的是减少冗余。它还增加了一致性(在本例中,它保证只将书籍链接到现有的作者ID)。最后但并非最不重要的是:它增加了速度。使用桥接表查找书籍的作者通常非常快(提供了适当的索引),而数组方法往往非常慢,因为在表中查找书籍ID的唯一方法是读取所有记录。@pedram bashiri:至于冗余:是的。我看不出桥接表在哪里增加了任何冗余。没有。至于规范化:数据库应该规范化。然而,数组不一定违反规范化。当您将某个内容存储为字符串时,您不应该对DBMS中的子字符串感兴趣(那么您应该单独存储子字符串)。数组也是如此:当你存储一个数组时,你不应该对该数组的单个元素感兴趣…@pedram bashiri:。。。在本例中,我们对单数组元素非常感兴趣,因为它们甚至是ID。在数组中存储ID不是一个好主意,因为这可能导致不一致。如果你想存储,比如说,备忘录或者类似的东西,数组可以非常方便。至于这个行业:我已经在相当大的数据库(超过1000个表)工作了25年多,我在这里和那里看到了违反规范的情况。这通常是有代价的。
SELECT firstName, lastName 
FROM author 
WHERE authorId IN 
 (SELECT unnest(authorIds) 
  FROM Book 
  WHERE bookId = 1);