如何在PostgreSQL中实现多对多关系? [英] How to implement a many-to-many relationship in PostgreSQL?

查看:1405
本文介绍了如何在PostgreSQL中实现多对多关系?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我相信标题是不言自明的。如何在PostgreSQL中创建表结构以形成多对多关系。



我的示例:

 产品(名称,价格); 
Bill(name,date,Products);


解决方案

DDL语句可能如下所示:

  CREATE TABLE产品(
product_id serial PRIMARY KEY - 隐式主键约束
,产品文本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
);

我做了一些调整:




I believe the title is self-explanatory. How do you create the table structure in PostgreSQL to make a many-to-many relationship.

My example:

Product(name, price);
Bill(name, date, Products);

解决方案

The DDL statements could look like this:

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
);

I made a few adjustments:

  • The n:m relationship is normally implemented by a separate table - bill_product in this case.

  • I added serial columns as surrogate primary keys. I highly recommend that, because the name of a product is hardly unique. Also, enforcing uniqueness and referencing the column in foreign keys is much cheaper with a 4-byte integer than with a string stored as text or varchar.

  • Don't use names of basic data types like date as identifiers. While this is possible, it is bad style and leads to confusing errors and error messages. Use legal, lower case, unquoted identifiers. Never use reserved words and avoid double-quoted mixed case identifiers if you can.

  • name is not a good name. I renamed the name column of the table product to be product. That is a better naming convention. Otherwise, when you join a couple of tables in a query - which you do a lot in a relational database - you end up with multiple columns named name and have to use column aliases to sort out the mess. That's not helpful. Another widespread anti-pattern would be just id as column name.
    I am not sure what the name of a bill would be. Maybe bill_id can be the name in this case.

  • price is of data type numeric to store fractional numbers precisely as entered (arbitrary precision type instead of floating point type). If you deal with whole numbers exclusively, make that integer. For example, you could save prices as Cents.

  • The amount ("Products" in your question) goes into the linking table bill_product and is of type numeric as well. Again, integer if you deal with whole numbers exclusively.

  • You see the foreign keys in bill_product? I created both to cascade changes (ON UPDATE CASCADE): If a product_id or bill_id should change, the change is cascaded to all depending entries in bill_product and nothing breaks.
    I also used ON DELETE CASCADE for bill_id: If you delete a bill, the details are deleted with it.
    Not so for products: You don't want to delete a product that's used in a bill. Postgres will throw an error if you attempt this. You would add another column to product to mark obsolete rows instead.

  • All columns in this basic example end up to be NOT NULL, so NULL values are not allowed. (Yes, all columns - columns used in a primary key are defined UNIQUE NOT NULL automatically.) That's because NULL values wouldn't make sense in any of the columns. It makes a beginner's life easier. But you won't get away so easily, you need to understand NULL handling anyway. Additional columns might allow NULL values, functions and joins can introduce NULL values etc.

  • Read the chapter on CREATE TABLE in the manual.

  • Primary keys are implemented with a unique index on the key columns, that makes queries with conditions on the PK column(s) fast. However, the sequence of key columns is relevant in multicolumn keys. Since the PK on bill_product is on (bill_id, product_id) in my example, you may want to add another index on just product_id or (product_id, bill_id) if you have queries looking for given a product_id and no bill_id. Details:

  • Read the chapter on indexes in the manual.

这篇关于如何在PostgreSQL中实现多对多关系?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆