Příkazy SQL DDL (data definition language) mohou vypadat takto:
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
);
Udělal jsem pár úprav:
-
Vztah n:m je obvykle implementován samostatnou tabulkou -
bill_product
v tomto případě. -
Přidal jsem
serial
sloupce jako náhradní primární klíče . V Postgres 10 nebo novějších zvažteIDENTITY
sloupec místo toho. Viz:- Bezpečně přejmenovávejte tabulky pomocí sloupců sériového primárního klíče
- Automaticky zvyšovat sloupec tabulky
- https://www.2ndquadrant.com/en/blog/postgresql-10-identity-columns/
Vřele to doporučuji, protože název produktu je stěží jedinečný (není dobrý „přirozený klíč“). Také vynucení jedinečnosti a odkazování na sloupec v cizích klíčích je obvykle levnější se 4bajtovým
integer
(nebo dokonce 8bajtovýbigint
) než s řetězcem uloženým jakotext
nebovarchar
. -
Nepoužívejte názvy základních datových typů jako
date
jako identifikátory . I když je to možné, je to špatný styl a vede k matoucím chybám a chybovým zprávám. Používejte legální identifikátory s malými písmeny, bez uvozovek. Nikdy nepoužívejte vyhrazená slova a pokud můžete, vyhýbejte se dvojitým uvozovkám a smíšeným identifikátorům velkých a malých písmen. -
"jméno" není dobré jméno. Sloupec tabulky jsem přejmenoval na
product
býtproduct
(neboproduct_name
nebo podobné). To je lepší konvence pojmenování . V opačném případě, když spojíte několik tabulek v dotazu – což děláte hodně v relační databázi – skončíte s více sloupci s názvem „jméno“ a budete muset použít aliasy sloupců k vyřešení nepořádku. To není užitečné. Dalším rozšířeným anti-vzorem by bylo pouze „id“ jako název sloupce.
Nejsem si jistý, jak se jmenujebill
bylo by.bill_id
v tomto případě pravděpodobně postačí. -
price
je datového typunumeric
ukládat zlomková čísla přesně tak, jak jsou zadána (typ s libovolnou přesností místo typu s plovoucí desetinnou čárkou). Pokud se zabýváte výhradně celými čísly, udělejte totointeger
. Můžete například uložit ceny v centech . -
amount
("Products"
ve vaší otázce) přejde do propojovací tabulkybill_product
a je typunumeric
také. Opětinteger
pokud pracujete výhradně s celými čísly. -
Vidíte cizí klíče v
bill_product
? Vytvořil jsem oba pro kaskádové změny:ON UPDATE CASCADE
. Pokudproduct_id
nebobill_id
by se měla změnit, změna se promítne do všech závislých položek vbill_product
a nic se nezlomí. To jsou jen odkazy bez vlastního významu.
Také jsem použilON DELETE CASCADE
probill_id
:Pokud je účtenka smazána, její detaily zemřou spolu s ní.
Ne tak pro produkty:Nechcete smazat produkt, který je použit na účtence. Pokud se o to pokusíte, Postgres vyvolá chybu. Doproduct
byste přidali další sloupec místo toho označit zastaralé řádky („soft-delete“). -
Všechny sloupce v tomto základním příkladu skončí jako
NOT NULL
, takžeNULL
hodnoty nejsou povoleny. (Ano, vše sloupce - sloupce primárního klíče jsou definoványUNIQUE NOT NULL
automaticky.) To proto, žeNULL
hodnoty by nedávaly smysl v žádném ze sloupců. Usnadňuje život začátečníka. Ale tak snadno se nedostanete, musíte pochopitNULL
manipulace stejně. Další sloupce mohou umožnitNULL
hodnoty, funkce a spojení mohou zavádětNULL
hodnoty v dotazech atd. -
Přečtěte si kapitolu
CREATE TABLE
v návodu. -
Primární klíče jsou implementovány s jedinečným indexem na klíčových sloupcích, díky čemuž jsou dotazy s podmínkami ve sloupcích PK rychlé. Pořadí klíčových sloupců je však relevantní ve vícesloupcových klíčích. Od PK na
bill_product
je na(bill_id, product_id)
v mém příkladu možná budete chtít přidat další index pouze naproduct_id
nebo(product_id, bill_id)
pokud máte dotazy týkající se danéhoproduct_id
a žádnébill_id
. Viz:- Složený primární klíč PostgreSQL
- Je složený index vhodný také pro dotazy na první pole?
- Práce s indexy v PostgreSQL
-
Přečtěte si kapitolu o rejstřících v příručce.