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);
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 SQL DDL (data definition language) statements could look like this:
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-byteinteger
than with a string stored astext
orvarchar
.In Postgres 10 or later consider an
IDENTITY
column instead. Details: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 thename
column of the tableproduct
to beproduct
. 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 namedname
and have to use column aliases to sort out the mess. That's not helpful. Another widespread anti-pattern would be justid
as column name.I am not sure what the name of a
bill
would be. Maybebill_id
can be the name in this case.price
is of data typenumeric
to store fractional numbers precisely as entered (arbitrary precision type instead of floating point type). If you deal with whole numbers exclusively, make thatinteger
. For example, you could save prices as Cents.The
amount
("Products"
in your question) goes into the linking tablebill_product
and is of typenumeric
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 aproduct_id
orbill_id
should change, the change is cascaded to all depending entries inbill_product
and nothing breaks.I also used
ON DELETE CASCADE
forbill_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
, soNULL
values are not allowed. (Yes, all columns - columns used in a primary key are definedUNIQUE NOT NULL
automatically.) That's becauseNULL
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 understandNULL
handling anyway. Additional columns might allowNULL
values, functions and joins can introduceNULL
values in queries 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 justproduct_id
or(product_id, bill_id)
if you have queries looking for given aproduct_id
and nobill_id
. Details:Read the chapter on indexes in the manual.