我相信标题是不言自明的。你如何在PostgreSQL中创建表结构来建立多对多的关系。如何在PostgreSQL中实现多对多的关系?
我的例子:
Product(name, price);
Bill(name, date, Products);
我相信标题是不言自明的。你如何在PostgreSQL中创建表结构来建立多对多的关系。如何在PostgreSQL中实现多对多的关系?
我的例子:
Product(name, price);
Bill(name, date, Products);
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
列为代理主键。我强烈建议,因为产品的名称不是唯一的。此外,在外键中强制实施唯一性和引用列对于使用4字节的integer
比使用存储为text
或varchar
的字符串要便宜得多。
在Postgres 10或更高版本中,请改为使用IDENTITY
column。详细信息:
不要使用基本数据类型的名称,如date
为标识符。虽然这是可能的,但它是不好的风格,并导致错误和错误消息混淆。使用。如果可以的话,切勿使用reserved words并避免使用双引号混合大小写标识符。
name
不是一个好名字。我将表product
的name
列重命名为product
。这是一个更好的命名约定。否则,当你在一个查询中加入几个表时 - 你在关系数据库中做很多 - 你最终会得到多个名为name
的列,并且必须使用列别名来整理混乱。这没有帮助。另一个广泛的反模式将只是id
作为列名。
我不确定bill
会是什么名字。在这种情况下,可能bill_id
可以是名称。
price
是数据类型numeric
来存储小数精确地输入(任意精度类型,而不是浮点型)。如果你专门处理整个号码,那就做integer
。例如,您可以将价格节省作为分销商。
amount
("Products"
在您的问题)进入链接表bill_product
并且类型numeric
以及。如果你专门处理整数,integer
。
你看到外键在bill_product
?我创建了两个级联更改(ON UPDATE CASCADE
):如果product_id
或bill_id
应该更改,则更改会级联到bill_product
中的所有相关条目,并且不会有任何中断。
我还使用ON DELETE CASCADE
代替bill_id
:如果您删除帐单,详细信息将随之删除。
并非如此产品:您不想删除在帐单中使用的产品。如果你尝试这个,Postgres会抛出一个错误。您可以将另一列添加到product
以标记废弃的行。
在这个基本的例子中的所有列最终是NOT NULL
,所以NULL
值是不允许的。 (是的,全部列 - 主键中使用的列自动定义为UNIQUE NOT NULL
)。这是因为NULL
值在任何列中都没有意义。它使初学者的生活更轻松。但你不会轻易离开,无论如何你需要了解NULL
handling。附加列可能允许NULL
价值,功能和连接可以查询等
阅读CREATE TABLE
in the manual章介绍NULL
值。
主键在关键列上使用唯一的索引实现,这使得快速查询PK列中的条件。但是,键列的顺序与多列键相关。由于bill_product
上的PK位于(bill_id, product_id)
,在我的示例中,如果您有查询给定product_id
和bill_id
的查询请求,您可能需要在product_id
或(product_id, bill_id)
上添加另一个索引。详细信息:
主席先生,为了提高答案的质量,即使在几周后,你也绝对不会回来多次。我感谢你成为社区的忠诚贡献者! – 2014-12-05 12:11:53
@RaduGheorghiu:谢谢。我多次提到这个答案,所以我一直在提炼它。 – 2014-12-05 12:33:37
如何为映射表“bill_product”创建索引?通常它看起来应该是这样的:'CREATE INDEX idx_bill_product_id ON booked_rates(bill_id,product_id)'。这是正确的吗? – codyLine 2015-01-05 23:46:04
查询不建立m-t-m关系 - 表结构。 – 2012-03-20 15:30:16
我没有很好地表达自己,我该如何定义我的表格结构? – 2012-03-20 15:32:04
从帐单表中删除产品,创建一个名为“bill_products”的新表,其中有两个字段:一个指向产品,一个指向帐单。使这两个字段成为这个新表的主键。 – 2012-03-20 15:34:56