PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Jak zaimplementować relację wiele-do-wielu w PostgreSQL?

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_product w tym przypadku.

  • Dodałem serial kolumny jako zastępcze klucze podstawowe . W Postgresie 10 lub nowszym rozważ IDENTITY zamiast 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-bajtowy bigint ) niż za pomocą ciągu przechowywanego jako text lub varchar .

  • Nie używaj nazw podstawowych typów danych, takich jak date jako 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 product być product (lub product_name lub 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ę bill byłoby. bill_id prawdopodobnie wystarczy w tym przypadku.

  • price ma typ danych numeric do 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, ustaw integer . Na przykład możesz zapisać ceny jako centy .

  • amount ("Products" w Twoim pytaniu) przechodzi do tabeli linków bill_product i jest typu numeric także. Ponownie, integer jeśli zajmujesz się wyłącznie liczbami całkowitymi.

  • Widzisz klucze obce w bill_product ? Stworzyłem oba do kaskadowych zmian:ON UPDATE CASCADE . Jeśli product_id lub bill_id powinna się zmienić, zmiana jest kaskadowana do wszystkich zależnych wpisów w bill_product i nic się nie psuje. To są tylko referencje, które same w sobie nie mają znaczenia.
    Użyłem również ON DELETE CASCADE dla bill_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ę do product aby zamiast tego zaznaczyć przestarzałe wiersze ("soft-delete").

  • Wszystkie kolumny w tym podstawowym przykładzie mają wartość NOT NULL , więc NULL wartości są niedozwolone. (Tak, wszystkie kolumny - kolumny klucza głównego są zdefiniowane UNIQUE NOT NULL automatycznie.) Dzieje się tak, ponieważ NULL wartości nie miałyby sensu w żadnej z kolumn. Ułatwia życie początkującemu. Ale nie uciekniesz tak łatwo, musisz zrozumieć NULL mimo to obsługa. Dodatkowe kolumny mogą pozwolić na NULL wartości, funkcje i złączenia mogą wprowadzić NULL wartości w zapytaniach itp.

  • Przeczytaj rozdział o CREATE TABLE w 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_product jest na (bill_id, product_id) w moim przykładzie możesz chcieć dodać kolejny indeks tylko dla product_id lub (product_id, bill_id) jeśli masz zapytania dotyczące danego product_id i bez bill_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.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Uzyskaj domyślną wartość szeregową po INSERT wewnątrz PL/pgSQL

  2. Uzyskaj identyfikator z warunkowego INSERT

  3. Typecast string to integer

  4. Jak odświeżyć encje JPA, gdy baza danych zaplecza zmienia się asynchronicznie?

  5. Nie można utworzyć tabeli bazy danych o nazwie „użytkownik” w PostgreSQL