Je pense que le titre est explicite. Comment créer la structure de table dans PostgreSQL pour créer une relation plusieurs-à-plusieurs.
Mon exemple:
Product(name, price);
Bill(name, date, Products);
sql
database
postgresql
database-design
many-to-many
Radu Gheorghiu
la source
la source
Réponses:
Les instructions SQL DDL (langage de définition de données) pourraient ressembler à ceci:
J'ai fait quelques ajustements:
La relation n: m est normalement implémentée par une table séparée -
bill_product
dans ce cas.J'ai ajouté des
serial
colonnes comme clés primaires de substitution . Dans Postgres 10 ou version ultérieure, envisagez plutôt uneIDENTITY
colonne . Voir:Je le recommande vivement, car le nom d'un produit n'est guère unique (pas une bonne "clé naturelle"). En outre, appliquer l'unicité et référencer la colonne dans les clés étrangères est généralement moins cher avec un 4 octets
integer
(ou même un 8 octetsbigint
) qu'avec une chaîne stockée en tant quetext
ouvarchar
.N'utilisez pas de noms de types de données de base
date
comme des identificateurs . Bien que cela soit possible, c'est un mauvais style et conduit à des erreurs et des messages d'erreur déroutants. Utilisez des identifiants légaux, en minuscules et sans guillemets . N'utilisez jamais de mots réservés et évitez les identifiants de casse mixtes entre guillemets si vous le pouvez."nom" n'est pas un bon nom. J'ai renommé la colonne de la table
product
pour êtreproduct
(product_name
ou similaire). C'est une meilleure convention de dénomination . Sinon, lorsque vous joignez quelques tables dans une requête - ce que vous faites souvent dans une base de données relationnelle - vous vous retrouvez avec plusieurs colonnes nommées «nom» et devez utiliser des alias de colonne pour trier le désordre. Cela ne sert à rien. Un autre anti-pattern répandu serait juste "id" comme nom de colonne.Je ne sais pas quel
bill
serait le nom d'un .bill_id
suffira probablement dans ce cas.price
est du type de donnéesnumeric
pour stocker les nombres fractionnaires précisément tels qu'ils ont été saisis (type de précision arbitraire au lieu de type virgule flottante). Si vous traitez exclusivement des nombres entiers, faitesinteger
. Par exemple, vous pouvez enregistrer les prix sous forme de cents .Le
amount
("Products"
dans votre question) entre dans la table de liaisonbill_product
et est également de typenumeric
. Encore une fois,integer
si vous traitez exclusivement des nombres entiers.Vous voyez les clés étrangères dans
bill_product
? J'ai créé à la fois à des changements en cascade:ON UPDATE CASCADE
. Si unproduct_id
oubill_id
doit changer, le changement est appliqué en cascade à toutes les entrées dépendantes debill_product
et rien ne casse. Ce ne sont que des références sans signification propre.J'ai également utilisé
ON DELETE CASCADE
pourbill_id
: Si une facture est supprimée, ses détails meurent avec elle.Ce n'est pas le cas pour les produits: vous ne souhaitez pas supprimer un produit utilisé dans une facture. Postgres lancera une erreur si vous essayez cela. Vous ajouteriez une autre colonne à
product
pour marquer les lignes obsolètes ("soft-delete") à la place.Toutes les colonnes de cet exemple de base finissent par être
NOT NULL
, lesNULL
valeurs ne sont donc pas autorisées. (Oui, toutes les colonnes - les colonnes de clé primaire sont définiesUNIQUE NOT NULL
automatiquement.) C'est parce que lesNULL
valeurs n'ont aucun sens dans aucune des colonnes. Cela facilite la vie d'un débutant. Mais vous ne vous en sortirez pas si facilement, vous devez quand même comprendre laNULL
manipulation . Des colonnes supplémentaires peuvent autoriser desNULL
valeurs, des fonctions et des jointures peuvent introduire desNULL
valeurs dans les requêtes, etc.Lisez 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, ce qui accélère les requêtes avec des conditions sur la ou les colonnes PK. Cependant, la séquence des colonnes clés est pertinente dans les clés multicolonnes. Puisque le PK
bill_product
est activé(bill_id, product_id)
dans mon exemple, vous pouvez ajouter un autre index sur justeproduct_id
ou(product_id, bill_id)
si vous avez des requêtes à la recherche d'unproduct_id
et d'un nonbill_id
. Voir:Lisez le chapitre sur les index dans le manuel .
la source
bill_product
? Normalement , il devrait ressembler à :CREATE INDEX idx_bill_product_id ON booked_rates(bill_id, product_id)
. Est-ce correct?bill
. Nous avons besoin du montant par article ajoutébill_product
.