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_productdans ce cas. -
j'ai ajouté
serialcolonnes 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-octetintegerqu'avec une chaîne stockée commetextouvarchar.
Dans Postgres 10 ou plus tard envisager uneIDENTITYcolonne à la place. Details: -
N'utilisez pas de noms de types de données de base comme
datecomme 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. -
namen'est pas un bon nom. J'ai renommé la colonnenamede la tableproductpour ê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éesnameet devez utiliser des alias de colonne pour trier le désordre. Ce n'est pas utile. Une autre anti-motif répandu serait simplementidcomme nom de colonne.
Je ne suis pas sûr du nom d'unbill. Peut-êtrebill_idpeut être le nom dans ce cas. -
priceest de type de donnéesnumericpour 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_productet est de typenumericainsi. Encore une fois,integersi 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_idoubill_iddoit changer, le changement est en cascade à toutes les entrées en fonction dansbill_productet rien ne casse.
J'ai aussi utiliséON DELETE CASCADEpourbill_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 àproductpour marquer les lignes obsolètes à la place. -
toutes les colonnes de cet exemple de base finissent par être
NOT NULL, ainsi, les valeursNULLne sont pas autorisées. (Oui, toutes les colonnes-les colonnes utilisées dans une clé primaire sont définiesUNIQUE NOT NULLautomatiquement.) C'est parce queNULLvaleurs ç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 comprendreNULLmanipulation de toute façon. Des colonnes supplémentaires pourraient permettre des valeursNULL, des fonctions et des jointures peuvent introduire des valeursNULLdans les requêtes, etc. -
lire le chapitre sur
CREATE TABLEdans 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_productest sur(bill_id, product_id)dans mon exemple, vous pouvez vouloir ajouter un autre index sur justeproduct_idou(product_id, bill_id)si vous avez des requêtes recherchant donné unproduct_idet nonbill_id. Details: -
lire le chapitre sur les index dans le manuel .