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 enIDENTITY
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-bytebigint
) end med en streng gemt somtext
ellervarchar
. -
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æreproduct
(ellerproduct_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å enbill
ville være.bill_id
vil nok være tilstrækkeligt i dette tilfælde. -
price
er af datatypennumeric
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 detinteger
. For eksempel kan du spare priser som cents . -
amount
("Products"
i dit spørgsmål) går ind i linkningstabellenbill_product
og er af typennumeric
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 etproduct_id
ellerbill_id
skulle ændres, bliver ændringen overført til alle afhængige poster ibill_product
og intet går i stykker. Det er kun referencer uden deres egen betydning.
Jeg brugte ogsåON DELETE CASCADE
forbill_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 tilproduct
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 defineretUNIQUE NOT NULL
automatisk.) Det er fordiNULL
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 tilladeNULL
værdier, funktioner og joinforbindelser kan introducereNULL
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å bareproduct_id
eller(product_id, bill_id)
hvis du har forespørgsler på udkig efter en givenproduct_id
og ingenbill_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.