sql >> Database teknologi >  >> RDS >> PostgreSQL

Hvordan implementerer man et mange-til-mange-forhold i PostgreSQL?

SQL DDL (data definition language)-sætningerne kunne se sådan ud:

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
);

Jeg lavede et par justeringer:

  • n:m-forholdet er normalt implementeret af en separat tabel - bill_product i dette tilfælde.

  • Jeg tilføjede serial kolonner som surrogat primærnøgler . Overvej en IDENTITY i Postgres 10 eller senere kolonne i stedet for. Se:

    • Omdøb tabeller sikkert ved hjælp af serielle primærnøglekolonner
    • Automatisk stigning i tabelkolonnen
    • https://www.2ndquadrant.com/en/blog/postgresql-10-identity-columns/

    Det kan jeg varmt anbefale, for navnet på et produkt er næppe unikt (ikke en god "naturlig nøgle"). Det er også typisk billigere at håndhæve unikhed og henvise til kolonnen i fremmednøgler med et 4-byte integer (eller endda en 8-byte bigint ) end med en streng gemt som text eller varchar .

  • Brug ikke navne på grundlæggende datatyper såsom date som identifikatorer . Selvom dette er muligt, er det dårlig stil og fører til forvirrende fejl og fejlmeddelelser. Brug lovlige, små bogstaver, ikke-citerede identifikatorer. Brug aldrig reserverede ord, og undgå dobbelt-citater, hvis du kan.

  • "navn" er ikke et godt navn. Jeg omdøbte kolonnen i tabellen product at være product (eller product_name eller lignende). Det er en bedre navngivningskonvention . Ellers, når du slutter dig til et par tabeller i en forespørgsel - hvilket du gør meget i en relationsdatabase - du ender med flere kolonner med navnet "navn" og skal bruge kolonnealiaser for at sortere rodet. Det er ikke nyttigt. Et andet udbredt anti-mønster ville bare være "id" som kolonnenavn.
    Jeg er ikke sikker på, hvad navnet på en bill ville være. bill_id vil nok være tilstrækkeligt i dette tilfælde.

  • price er af datatypen numeric at gemme brøktal nøjagtigt som indtastet (vilkårlig præcisionstype i stedet for flydende kommatype). Hvis du udelukkende beskæftiger dig med hele tal, skal du lave det integer . For eksempel kan du spare priser som cents .

  • amount ("Products" i dit spørgsmål) går ind i linkningstabellen bill_product og er af typen numeric såvel. Igen, integer hvis du udelukkende beskæftiger dig med hele tal.

  • Du ser fremmednøglerne i bill_product ? Jeg oprettede begge for at kaskade ændringer:ON UPDATE CASCADE . Hvis et product_id eller bill_id skulle ændres, bliver ændringen overført til alle afhængige poster i bill_product og intet går i stykker. Det er kun referencer uden deres egen betydning.
    Jeg brugte også ON DELETE CASCADE for bill_id :Hvis en regning bliver slettet, dør dens detaljer med den.
    Ikke tilfældet for produkter:Du ønsker ikke at slette et produkt, der er brugt i en regning. Postgres vil give en fejl, hvis du forsøger dette. Du vil tilføje endnu en kolonne til product for at markere forældede rækker ("soft-delete") i stedet.

  • Alle kolonner i dette grundlæggende eksempel ender med at være NOT NULL , så NULL værdier er ikke tilladt. (Ja, alle kolonner - primære nøglekolonner er defineret UNIQUE NOT NULL automatisk.) Det er fordi NULL værdier ville ikke give mening i nogen af ​​kolonnerne. Det gør en begynders liv lettere. Men du slipper ikke så let, du skal forstå NULL håndtering alligevel. Yderligere kolonner kan tillade NULL værdier, funktioner og joinforbindelser kan introducere NULL værdier i forespørgsler osv.

  • Læs kapitlet om CREATE TABLE i manualen.

  • Primære nøgler er implementeret med et unikt indeks på nøglekolonnerne, hvilket gør forespørgsler med betingelser på PK-kolonnen(e) hurtige. Rækkefølgen af ​​nøglekolonner er dog relevant i flerkolonnenøgler. Siden PK på bill_product er på (bill_id, product_id) i mit eksempel vil du måske tilføje endnu et indeks på bare product_id eller (product_id, bill_id) hvis du har forespørgsler på udkig efter en given product_id og ingen bill_id . Se:

    • PostgreSQL sammensat primær nøgle
    • Er et sammensat indeks også godt til forespørgsler i det første felt?
    • Arbejdning af indekser i PostgreSQL
  • Læs kapitlet om indekser i manualen.




  1. Tjek, om et objekt er en tabel, visning eller lagret procedure i SQL Server ved hjælp af OBJECTPROPERTY()-funktionen

  2. Hvordan får man alle kolonnenavne til alle tabellerne i MySQL?

  3. Maksimal størrelse af en varchar(max) variabel

  4. Binære data i MySQL