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_producti dette tilfælde. -
Jeg tilføjede
serialkolonner som surrogat primærnøgler . Overvej enIDENTITYi 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 somtextellervarchar. -
Brug ikke navne på grundlæggende datatyper såsom
datesom 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
productat væreproduct(ellerproduct_nameeller 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å enbillville være.bill_idvil nok være tilstrækkeligt i dette tilfælde. -
priceer af datatypennumericat 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_productog er af typennumericsåvel. Igen,integerhvis 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_idellerbill_idskulle ændres, bliver ændringen overført til alle afhængige poster ibill_productog intet går i stykker. Det er kun referencer uden deres egen betydning.
Jeg brugte ogsåON DELETE CASCADEforbill_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 tilproductfor 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åNULLværdier er ikke tilladt. (Ja, alle kolonner - primære nøglekolonner er defineretUNIQUE NOT NULLautomatisk.) Det er fordiNULLvæ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åNULLhåndtering alligevel. Yderligere kolonner kan tilladeNULLværdier, funktioner og joinforbindelser kan introducereNULLværdier i forespørgsler osv. -
Læs kapitlet om
CREATE TABLEi 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_producter på(bill_id, product_id)i mit eksempel vil du måske tilføje endnu et indeks på bareproduct_ideller(product_id, bill_id)hvis du har forespørgsler på udkig efter en givenproduct_idog 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.