web-dev-qa-db-fra.com

Comment implémenter une relation plusieurs à plusieurs dans PostgreSQL?

Je crois que le titre est explicite. Comment créez-vous la structure de la table dans PostgreSQL pour créer une relation plusieurs à plusieurs?.

Mon exemple:

Product(name, price);
Bill(name, date, Products);
64
Radu Gheorghiu

Les instructions SQL DDL (langage de définition de données) 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 implémentée par une table séparée - bill_product Dans ce cas.

  • J'ai ajouté serial colonnes en tant que clés primaires de substitution . Je le recommande vivement, car le nom d’un produit n’est pas unique. De plus, appliquer un caractère unique et référencer la colonne dans des clés étrangères est beaucoup moins cher avec un integer de 4 octets qu'avec une chaîne stockée sous la forme text ou varchar.
    Dans Postgres 10 ou supérieur, considérons plutôt une colonne IDENTITY . Détails:

  • N'utilisez pas les noms de types de données de base tels que date comme identificateurs . Bien que cela soit possible, le style utilisé est mauvais et conduit à des erreurs de confusion et des messages d'erreur. Utilisez identificateurs légaux, minuscules et non cités . N'utilisez jamais mots réservés et évitez les identifiants de casse mixte double-guillotine si vous le pouvez.

  • name n'est pas un bon nom. J'ai renommé la colonne name de la table product en product. C’est une meilleure convention de dénomination . Sinon, lorsque vous joignez 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ées name et vous devez utiliser column des alias pour régler le désordre. Ce n'est pas utile. Un autre anti-motif répandu serait simplement id comme nom de colonne.
    Je ne suis pas sûr du nom d’un bill. Peut-être que bill_id Peut être le nom dans ce cas.

  • price est de type numeric pour stocker des nombres fractionnaires précisément tels qu'ils ont été entrés (type de précision arbitraire au lieu de type à virgule flottante). Si vous traitez exclusivement avec des nombres entiers, faites ceci integer. Par exemple, vous pourriez économiser des prix exprimés en cents.

  • Le amount ("Products" De votre question) va dans la table de liaison bill_product Et est de type numeric. Encore une fois, integer si vous traitez exclusivement avec des nombres entiers.

  • Vous voyez les clés étrangères dans bill_product? J'ai créé les deux pour modifier en cascade les modifications (ON UPDATE CASCADE): Si un product_id Ou bill_id Devait changer, la modification est appliquée en cascade à toutes les entrées qui en dépendent dans bill_product Et rien pauses.
    J'ai aussi utilisé ON DELETE CASCADE Pour bill_id: Si vous supprimez une facture, les détails sont supprimés.
    Pas le cas pour les produits: vous ne voulez pas supprimer un produit utilisé dans une facture. Postgres lancera une erreur si vous tentez ceci. Vous ajouteriez une autre colonne à product pour marquer les lignes obsolètes.

  • Toutes les colonnes de cet exemple de base finissent par être NOT NULL, donc les valeurs de NULL ne sont pas autorisées. (Oui, tous colonnes - les colonnes utilisées dans une clé primaire sont définies automatiquement UNIQUE NOT NULL.) C'est parce que NULL les valeurs n'auraient de sens dans aucune des colonnes. Cela facilite la vie d'un débutant. Mais vous ne vous échapperez pas si facilement, vous devez comprendre NULL traitement de toute façon. Des colonnes supplémentaires peuvent autoriser les valeurs NULL, les jointures peuvent introduire des valeurs NULL 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 de clés, ce qui rend rapides les requêtes avec des conditions sur la ou les colonnes PK. Cependant, la séquence de colonnes de clé est pertinente dans les clés multicolonnes. Étant donné que la PK sur bill_product Est sur (bill_id, product_id) Dans mon exemple, vous pouvez ajouter un autre index uniquement sur product_id Ou (product_id, bill_id) Si vous avez des requêtes à la recherche de étant donné un product_id et non bill_id. Détails:

  • Lisez le chapitre sur les index dans le manuel .

233
Erwin Brandstetter