Rad*_*hiu 68 sql database postgresql database-design many-to-many
我相信标题是不言自明的.如何在PostgreSQL中创建表结构以建立多对多关系.
我的例子:
Product(name, price);
Bill(name, date, Products);
Run Code Online (Sandbox Code Playgroud)
Erw*_*ter 243
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
);
Run Code Online (Sandbox Code Playgroud)
我做了一些调整:
在N:M关系通常由一个单独的表来实现- bill_product
在这种情况下.
我添加了serial
列作为代理主键.我强烈建议,因为产品的名称并不是唯一的.此外,强制唯一性和引用外键中的列integer
比使用存储为text
或的字符串便宜得多varchar
.
在Postgres 10或更高版本中,请考虑使用IDENTITY
列.细节:
不要使用基本数据类型的名称,date
如标识符.虽然这是可能的,但它是糟糕的风格,并导致混淆错误和错误消息.使用合法,小写,不带引号的标识符.如果可以,切勿使用保留字并避免使用双引号混合大小写标识符.
name
不是一个好名字.我改名为name
表列product
是product
.这是一个更好的命名约定.否则,当您在查询中连接几个表时 - 您在关系数据库中执行了很多操作 - 最终会得到多个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 示例在我的示例中bill_product
已启用(bill_id, product_id)
,因此您可能希望仅添加另一个索引,product_id
或者(product_id, bill_id)
如果您有查询给定a product_id
和no bill_id
.细节: