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 enIDENTITY
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-bytebigint
) än med en sträng lagrad somtext
ellervarchar
. -
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
varaproduct
(ellerproduct_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 enbill
heter. skulle vara.bill_id
kommer förmodligen att räcka i det här fallet. -
price
är av datatypnumeric
för att lagra bråktal precis som de anges (godtycklig precisionstyp istället för flyttalstyp). Om du enbart hanterar heltal, gör detinteger
. Du kan till exempel spara priser som cent . -
amount
("Products"
i din fråga) går in i länkningstabellenbill_product
och är av typennumeric
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 ettproduct_id
ellerbill_id
bör ändras, är ändringen kaskad till alla beroende poster ibill_product
och inget går sönder. Det är bara referenser utan egen betydelse.
Jag använde ocksåON DELETE CASCADE
förbill_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 tillproduct
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 definieradeUNIQUE NOT NULL
automatiskt.) Det beror på attNULL
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åtaNULL
värden, funktioner och kopplingar kan introduceraNULL
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å baraproduct_id
eller(product_id, bill_id)
om du har frågor som letar efter ett givetproduct_id
och ingetbill_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.