我相信标题是不言而喻的。如何在PostgreSQL中创建表结构以建立多对多关系。
我的例子:
Product(name, price);
Bill(name, date, Products);
我相信标题是不言而喻的。如何在PostgreSQL中创建表结构以建立多对多关系。
我的例子:
Product(name, price);
Bill(name, date, Products);
Answers:
SQL DDL(数据定义语言)语句如下所示:
CREATE TABLE product (
product_id serial PRIMARY KEY -- implicit primary key constraint
, product text NOT NULL
, price numeric NOT NULL DEFAULT 0
);
CREATE TABLE bill (
bill_id serial PRIMARY KEY
, bill text NOT NULL
, billdate date NOT NULL DEFAULT CURRENT_DATE
);
CREATE TABLE bill_product (
bill_id int REFERENCES bill (bill_id) ON UPDATE CASCADE ON DELETE CASCADE
, product_id int REFERENCES product (product_id) ON UPDATE CASCADE
, amount numeric NOT NULL DEFAULT 1
, CONSTRAINT bill_product_pkey PRIMARY KEY (bill_id, product_id) -- explicit pk
);
我做了一些调整:
在N:M关系通常由一个单独的表来实现- bill_product
在这种情况下。
我添加了serial
列作为代理主键。在Postgres 10或更高版本中,请考虑考虑使用一IDENTITY
列。看到:
我强烈建议您这样做,因为产品名称几乎不是唯一的(不是很好的“自然键”)。同样,强制使用唯一性并在外键中引用该列通常比使用存储为或的字符串便宜(4字节integer
(甚至8字节bigint
))。text
varchar
不要使用基本数据类型的名称date
作为标识符。尽管这是可能的,但这是不好的样式,并导致令人困惑的错误和错误消息。使用合法的,小写的,未加引号的标识符。切勿使用保留字,并尽可能避免使用双引号混合大小写标识符。
“名字”不是一个好名字。我将表的列重命名product
为product
(product_name
或类似)。那是更好的命名约定。否则,当您在查询中联接几个表时(在关系数据库中做很多事情),最终会得到多个名为“ name”的列,并且必须使用列别名来解决问题。那没有帮助。另一个广泛使用的反模式将只是“ id”作为列名。
我不确定a的名称是什么bill
。bill_id
在这种情况下可能就足够了。
price
属于数据类型 numeric
,可精确存储输入的分数(任意精度类型,而不是浮点类型)。如果您只处理整数,则使integer
。例如,您可以将价格另存为美分。
在amount
("Products"
你的问题)进入连结表bill_product
,是类型的numeric
为好。同样,integer
如果您只处理整数。
您看到外键了bill_product
吗?我创建了这两者来层叠更改:ON UPDATE CASCADE
。如果a product_id
或bill_id
应该更改,则更改将级联到其中的所有相关条目,bill_product
并且没有中断。这些只是参考,没有意义。
我也用ON DELETE CASCADE
了bill_id
:如果法案被删除,它的细节与它死去。
产品并非如此:您不想删除帐单中使用的产品。如果您尝试这样做,Postgres将抛出错误。您可以添加另一列来product
标记过时的行(“软删除”)。
这个基本示例中的所有列最终都为NOT NULL
,因此NULL
不允许使用值。(是的,所有列-主键列都是UNIQUE NOT NULL
自动定义的。)这是因为NULL
在任何列中值都没有意义。它使初学者的生活更加轻松。但是,您将无法轻松摆脱困境,无论如何您都需要了解NULL
处理方法。其他列可能允许NULL
值,函数和联接可以NULL
在查询等中引入值。
阅读CREATE TABLE
手册中的章节。
主键通过在键列上具有唯一索引来实现,从而可以快速查询带有PK列的条件。但是,键列的顺序与多列键有关。由于在我的示例中PK on bill_product
已打开(bill_id, product_id)
,因此您可能要在just上添加另一个索引,product_id
或者(product_id, bill_id)
如果您有查询在寻找给定product_id
和no的查询bill_id
。看到:
bill_product
?通常情况下,它应类似于:CREATE INDEX idx_bill_product_id ON booked_rates(bill_id, product_id)
。这是正确的吗?
bill
。我们需要在中添加的每个项目的金额bill_product
。