Comment mettre en œuvre une relation "many-to-many" dans PostgreSQL?
je crois que le titre est explicite. Comment créer la structure de la table dans PostgreSQL pour créer une relation de plusieurs à plusieurs.
mon exemple:
Product(name, price);
Bill(name, date, Products);
1 réponses
les énoncés SQL DDL (data definition language) pourraient ressembler à ceci:
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
);
j'ai fait quelques ajustements:
-
la relation n:m est normalement mise en œuvre par un tableau séparé -
bill_product
dans ce cas. -
j'ai ajouté
serial
colonnes en tant que . Je recommande fortement cela, parce que le nom d'un produit est à peine unique. En outre, l'application de l'unicité et la référence de la colonne dans les clés étrangères est beaucoup moins cher avec un 4-octetinteger
qu'avec une chaîne stockée commetext
ouvarchar
.
Dans Postgres 10 ou plus tard envisager uneIDENTITY
colonne à la place. Details: -
N'utilisez pas de noms de types de données de base comme
date
comme identificateurs . Bien que cela soit possible, c'est un mauvais style et conduit à des erreurs confuses et des messages d'erreur. Utiliser juridique, bas de casse, les identificateurs non cotées . N'utilisez jamais mots réservés et évitez les doubles citations cas mixte identifiants si vous le pouvez. -
name
n'est pas un bon nom. J'ai renommé la colonnename
de la tableproduct
pour êtreproduct
. C'est une meilleure Convention d'appellation . Autrement, lorsque vous rejoignez quelques tables dans une requête - ce que vous faites beaucoup dans une base de données relationnelle - vous vous retrouvez avec plusieurs colonnes nomméesname
et devez utiliser des alias de colonne pour trier le désordre. Ce n'est pas utile. Une autre anti-motif répandu serait simplementid
comme nom de colonne.
Je ne suis pas sûr du nom d'unbill
. Peut-êtrebill_id
peut être le nom dans ce cas. -
price
est de type de donnéesnumeric
pour stocker des nombres fractionnaires c'est justement qu'il est entré (arbitraire type de précision au lieu du type à virgule flottante). Si vous traitez avec des nombres entiers exclusivement, faites queinteger
. Par exemple, vous pouvez économiser prix en Cents . -
le
amount
("Products"
dans votre question) va dans le tableau de liaisonbill_product
et est de typenumeric
ainsi. Encore une fois,integer
si vous traitez avec des nombres entiers exclusivement. -
vous voyez le clés étrangères dans
bill_product
? J'ai créé les deux pour les changements en cascade (ON UPDATE CASCADE
): si unproduct_id
oubill_id
doit changer, le changement est en cascade à toutes les entrées en fonction dansbill_product
et rien ne casse.
J'ai aussi utiliséON DELETE CASCADE
pourbill_id
: si vous supprimez une facture, les détails sont supprimés avec elle.
Pas tellement pour les produits: Vous ne voulez pas supprimer un produit utilisé dans un projet de loi. Postgres lancera une erreur si vous tentez cela. Vous ajouteriez une autre colonne àproduct
pour marquer les lignes obsolètes à la place. -
toutes les colonnes de cet exemple de base finissent par être
NOT NULL
, ainsi, les valeursNULL
ne sont pas autorisées. (Oui, toutes les colonnes-les colonnes utilisées dans une clé primaire sont définiesUNIQUE NOT NULL
automatiquement.) C'est parce queNULL
valeurs ça n'aurait de sens dans aucune des colonnes. Il fait un débutant la vie plus facile. Mais vous ne vous en sortirez pas si facilement, vous devez comprendreNULL
manipulation de toute façon. Des colonnes supplémentaires pourraient permettre des valeursNULL
, des fonctions et des jointures peuvent introduire des valeursNULL
dans les requêtes, etc. -
lire le chapitre sur
CREATE TABLE
dans le manuel . -
les clés primaires sont implémentées avec un index unique sur les colonnes clés, qui rend les requêtes avec des conditions sur la(Les) colonne (s) PK rapide (s). Cependant, la séquence des colonnes de clés est pertinente dans les clés à plusieurs colonnes. Puisque le PK sur
bill_product
est sur(bill_id, product_id)
dans mon exemple, vous pouvez vouloir ajouter un autre index sur justeproduct_id
ou(product_id, bill_id)
si vous avez des requêtes recherchant donné unproduct_id
et nonbill_id
. Details: -
lire le chapitre sur les index dans le manuel .