Myślę, że tytuł jest oczywisty. Jak utworzyć strukturę tabeli w PostgreSQL, aby utworzyć relację wiele do wielu.
Mój przykład:
Product(name, price);
Bill(name, date, Products);
sql
database
postgresql
database-design
many-to-many
Radu Gheorghiu
źródło
źródło
Odpowiedzi:
Instrukcje SQL DDL (język definicji danych) mogą wyglądać następująco:
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 );
Dokonałem kilku poprawek:
N: m związek jest zwykle realizowane przez oddzielne stole -
bill_product
w tym przypadku.Dodałem
serial
kolumny jako zastępcze klucze podstawowe . W Postgres 10 lub nowszym rozważmy zamiast tegoIDENTITY
kolumnę . Widzieć:Bardzo to polecam, ponieważ nazwa produktu nie jest unikalna (nie jest dobrym „naturalnym kluczem”). Ponadto wymuszanie niepowtarzalności i odwoływanie się do kolumny w kluczach obcych jest zwykle tańsze w przypadku 4-bajtowego
integer
(lub nawet 8-bajtowegobigint
) niż w przypadku ciągu przechowywanego jakotext
lubvarchar
.Nie używaj nazw podstawowych typów danych, takich
date
jak 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żyj prawidłowych, małych liter, niecytowanych identyfikatorów . Nigdy nie używaj słów zastrzeżonych i unikaj podwójnych cudzysłowów mieszanych identyfikatorów wielkości liter, jeśli możesz.„imię” nie jest dobrym imieniem. Zmieniłem nazwę kolumny tabeli
product
naproduct
(product_name
lub podobną). To jest lepsza konwencja nazewnictwa . W przeciwnym razie, kiedy łączysz kilka tabel w zapytaniu - co robisz dużo 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 anty-wzorcem byłby po prostu „id” jako nazwa kolumny.Nie jestem pewien, jak
bill
miałoby się nazywać .bill_id
w tym przypadku prawdopodobnie wystarczy.price
jest typu danychnumeric
do przechowywania liczb ułamkowych dokładnie tak, jak zostały wprowadzone (typ o dowolnej precyzji zamiast typu zmiennoprzecinkowego). Jeśli zajmujesz się wyłącznie liczbami całkowitymi, zrób tointeger
. Na przykład możesz zapisać ceny w centach .amount
("Products"
W pytaniu) przechodzi w tabeli łączącejbill_product
i jest typunumeric
, jak również. Ponownie,integer
jeśli masz do czynienia wyłącznie z liczbami całkowitymi.Widać kluczy obcych w
bill_product
? I stworzył zarówno do zmian kaskadowych:ON UPDATE CASCADE
. Jeśli aproduct_id
lubbill_id
powinno się zmienić, zmiana jest kaskadowana do wszystkich zależnych wpisów wbill_product
i nic się nie psuje. To tylko odniesienia bez własnego znaczenia.Użyłem również
ON DELETE CASCADE
dobill_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żywany na rachunku. Postgres zgłosi błąd, jeśli spróbujesz tego. Zamiast tego można dodać kolejną kolumnę do,
product
aby zaznaczyć przestarzałe wiersze („usuwanie nietrwałe”).Wszystkie kolumny w tym podstawowym przykładzie kończą się wartościami
NOT NULL
, więcNULL
wartości nie są dozwolone. (Tak, wszystkie kolumny - kolumny klucza podstawowego są definiowaneUNIQUE NOT NULL
automatycznie). Dzieje się tak, ponieważNULL
wartości nie miałyby sensu w żadnej z kolumn. Ułatwia życie początkującym. Ale nie uciekniesz tak łatwo, i tak musisz zrozumiećNULL
obsługę . Dodatkowe kolumny mogą zezwalać naNULL
wartości, funkcje i łączenia mogą wprowadzaćNULL
wartości w zapytaniach itp.Przeczytaj rozdział
CREATE TABLE
w instrukcji .Klucze podstawowe są implementowane z unikalnym indeksem w kolumnach kluczy, co sprawia, że zapytania z warunkami w kolumnach PK są szybkie. Jednak sekwencja kolumn kluczy jest odpowiednia w przypadku kluczy wielokolumnowych. Ponieważ PK
bill_product
jest włączony(bill_id, product_id)
w moim przykładzie, możesz chcieć dodać kolejny indeks tylkoproduct_id
lub(product_id, bill_id)
jeśli masz zapytania szukające podanegoproduct_id
i niebill_id
. Widzieć:Przeczytaj rozdział dotyczący indeksów w instrukcji .
źródło
bill_product
? Normalnie powinno to wyglądać tak:CREATE INDEX idx_bill_product_id ON booked_rates(bill_id, product_id)
. Czy to jest poprawne?bill
. Potrzebujemy kwoty za dodany przedmiot wbill_product
.