sql >> Databasteknik >  >> RDS >> PostgreSQL

Hur implementerar man en många-till-många-relation i PostgreSQL?

SQL DDL-satser (data definition language) kan se ut så här:

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

Jag gjorde några justeringar:

  • n:m-relationen implementeras normalt av en separat tabell - bill_product i det här fallet.

  • Jag lade till serial kolumner som surrogat primärnycklar . Överväg en IDENTITY i Postgres 10 eller senare kolumn istället. Se:

    • Ändra namn på tabeller på ett säkert sätt med seriella primärnyckelkolumner
    • Automatisk ökning av tabellkolumnen
    • https://www.2ndquadrant.com/en/blog/postgresql-10-identity-columns/

    Jag rekommenderar det starkt, eftersom namnet på en produkt knappast är unikt (inte en bra "naturlig nyckel"). Att upprätthålla unikhet och referera till kolumnen i främmande nycklar är också vanligtvis billigare med ett 4-byte integer (eller till och med en 8-byte bigint ) än med en sträng lagrad som text eller varchar .

  • Använd inte namn på grundläggande datatyper som date som identifierare . Även om detta är möjligt, är det dålig stil och leder till förvirrande fel och felmeddelanden. Använd juridiska, gemener, icke-citerade identifierare. Använd aldrig reserverade ord och undvik dubbla citattecken om du kan.

  • "namn" är inte ett bra namn. Jag döpte om kolumnen i tabellen product vara product (eller product_name eller liknande). Det är en bättre namnkonvention . Annars, när du går med i ett par tabeller i en fråga - vilket du gör mycket i en relationsdatabas - du får flera kolumner som heter "namn" och måste använda kolumnalias för att reda ut röran. Det är inte till hjälp. Ett annat utbrett antimönster skulle bara vara "id" som kolumnnamn.
    Jag är inte säker på vad en bill heter. skulle vara. bill_id kommer förmodligen att räcka i det här fallet.

  • price är av datatyp numeric för att lagra bråktal precis som de anges (godtycklig precisionstyp istället för flyttalstyp). Om du enbart hanterar heltal, gör det integer . Du kan till exempel spara priser som cent .

  • amount ("Products" i din fråga) går in i länkningstabellen bill_product och är av typen numeric också. Återigen, integer om du enbart sysslar med heltal.

  • Du ser främmande nycklar i bill_product ? Jag skapade båda för att kaskadändringar:ON UPDATE CASCADE . Om ett product_id eller bill_id bör ändras, är ändringen kaskad till alla beroende poster i bill_product och inget går sönder. Det är bara referenser utan egen betydelse.
    Jag använde också ON DELETE CASCADE för bill_id :Om en faktura raderas dör dess uppgifter med den.
    Inte så för produkter:Du vill inte ta bort en produkt som används i en faktura. Postgres kommer att skicka ett felmeddelande om du försöker detta. Du skulle lägga till ytterligare en kolumn till product för att markera föråldrade rader ("soft-delete") istället.

  • Alla kolumner i detta grundläggande exempel blir NOT NULL , alltså NULL värden är inte tillåtna. (Ja, alla kolumner - primärnyckelkolumner är definierade UNIQUE NOT NULL automatiskt.) Det beror på att NULL värden skulle inte vara vettiga i någon av kolumnerna. Det gör livet enklare för en nybörjare. Men du kommer inte undan så lätt, du måste förstå NULL hantering i alla fall. Ytterligare kolumner kan tillåta NULL värden, funktioner och kopplingar kan introducera NULL värden i frågor etc.

  • Läs kapitlet om CREATE TABLE i manualen.

  • Primära nycklar implementeras med ett unikt index på nyckelkolumnerna, vilket gör frågor med villkor på PK-kolumn(erna) snabba. Däremot är sekvensen av nyckelkolumner relevant i flerkolumnnycklar. Sedan PK på bill_product är på (bill_id, product_id) i mitt exempel kanske du vill lägga till ytterligare ett index på bara product_id eller (product_id, bill_id) om du har frågor som letar efter ett givet product_id och inget bill_id . Se:

    • PostgreSQL sammansatt primärnyckel
    • Är ett sammansatt index också bra för frågor i det första fältet?
    • Arbeta med index i PostgreSQL
  • Läs kapitlet om index i manualen.




  1. T-sql - bestäm om värdet är heltal

  2. Halloweenproblemet – del 2

  3. Hur kör man en lagrad procedur varje dag i SQL Server Express Edition?

  4. Hur man lagrar sqlite-databas direkt på sdcard