Instrukcje SQL DDL (język definicji danych) mogą wyglądać tak:
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
);
Wprowadziłem kilka poprawek:
-
Relacja n:m jest zwykle implementowany przez oddzielną tabelę -
bill_productw tym przypadku. -
Dodałem
serialkolumny jako zastępcze klucze podstawowe . W Postgresie 10 lub nowszym rozważIDENTITYzamiast kolumny. Zobacz:- Bezpiecznie zmieniaj nazwy tabel przy użyciu seryjnych kolumn klucza podstawowego
- Automatyczna inkrementacja kolumny tabeli
- https://www.2ndquadrant.com/en/blog/postgresql-10-identity-columns/
Gorąco polecam, ponieważ nazwa produktu nie jest unikalna (nie jest to dobry „naturalny klucz”). Ponadto wymuszanie unikalności i odwoływanie się do kolumny w kluczach obcych jest zazwyczaj tańsze w przypadku 4-bajtowej
integer(lub nawet 8-bajtowybigint) niż za pomocą ciągu przechowywanego jakotextlubvarchar. -
Nie używaj nazw podstawowych typów danych, takich jak
datejako identyfikatory . Chociaż jest to możliwe, jest to zły styl i prowadzi do mylących błędów i komunikatów o błędach. Używaj legalnych, małych liter, nie cytowanych identyfikatorów. Nigdy nie używaj zastrzeżonych słów i unikaj podwójnych cudzysłowów, jeśli możesz. -
„imię” nie jest dobrym imieniem. Zmieniłem nazwę kolumny tabeli
productbyćproduct(lubproduct_namelub podobne). To jest lepsza konwencja nazewnictwa . W przeciwnym razie, gdy łączysz kilka tabel w zapytaniu – co robisz często w relacyjnej bazie danych - kończysz z wieloma kolumnami o nazwie "nazwa" i musisz użyć aliasów kolumn, aby uporządkować bałagan. To nie jest pomocne. Innym szeroko rozpowszechnionym antywzorcem byłby po prostu „id” jako nazwa kolumny.
Nie jestem pewien, jak nazywa siębillbyłoby.bill_idprawdopodobnie wystarczy w tym przypadku. -
pricema typ danychnumericdo przechowywania liczb ułamkowych dokładnie tak, jak zostały wprowadzone (dowolny typ precyzji zamiast typu zmiennoprzecinkowego). Jeśli zajmujesz się wyłącznie liczbami całkowitymi, ustawinteger. Na przykład możesz zapisać ceny jako centy . -
amount("Products"w Twoim pytaniu) przechodzi do tabeli linkówbill_producti jest typunumerictakże. Ponownie,integerjeśli zajmujesz się wyłącznie liczbami całkowitymi. -
Widzisz klucze obce w
bill_product? Stworzyłem oba do kaskadowych zmian:ON UPDATE CASCADE. Jeśliproduct_idlubbill_idpowinna się zmienić, zmiana jest kaskadowana do wszystkich zależnych wpisów wbill_producti nic się nie psuje. To są tylko referencje, które same w sobie nie mają znaczenia.
Użyłem równieżON DELETE CASCADEdlabill_id:Jeśli rachunek zostanie usunięty, jego szczegóły umrą wraz z nim.
Nie dotyczy to produktów:Nie chcesz usuwać produktu, który jest użyty w rachunku. Postgres zgłosi błąd, jeśli spróbujesz tego. Dodajesz kolejną kolumnę doproductaby zamiast tego zaznaczyć przestarzałe wiersze ("soft-delete"). -
Wszystkie kolumny w tym podstawowym przykładzie mają wartość
NOT NULL, więcNULLwartości są niedozwolone. (Tak, wszystkie kolumny - kolumny klucza głównego są zdefiniowaneUNIQUE NOT NULLautomatycznie.) Dzieje się tak, ponieważNULLwartości nie miałyby sensu w żadnej z kolumn. Ułatwia życie początkującemu. Ale nie uciekniesz tak łatwo, musisz zrozumiećNULLmimo to obsługa. Dodatkowe kolumny mogą pozwolić naNULLwartości, funkcje i złączenia mogą wprowadzićNULLwartości w zapytaniach itp. -
Przeczytaj rozdział o
CREATE TABLEw instrukcji. -
Klucze podstawowe są implementowane z unikalnym indeksem w kolumnach kluczowych, co przyspiesza zapytania z warunkami w kolumnach PK. Jednak kolejność kolumn kluczy ma znaczenie w kluczach wielokolumnowych. Od czasu PK na temat
bill_productjest na(bill_id, product_id)w moim przykładzie możesz chcieć dodać kolejny indeks tylko dlaproduct_idlub(product_id, bill_id)jeśli masz zapytania dotyczące danegoproduct_idi bezbill_id. Zobacz:- Złożony klucz podstawowy PostgreSQL
- Czy indeks złożony jest również odpowiedni dla zapytań w pierwszym polu?
- Praca z indeksami w PostgreSQL
-
Przeczytaj rozdział dotyczący indeksów w podręczniku.