sql >> Databáze >  >> RDS >> PostgreSQL

Jak implementovat vztah many-to-many v PostgreSQL?

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žte IDENTITY 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 jako text nebo varchar .

  • 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ýt product (nebo product_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 jmenuje bill bylo by. bill_id v tomto případě pravděpodobně postačí.

  • price je datového typu numeric 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 toto integer . Můžete například uložit ceny v centech .

  • amount ("Products" ve vaší otázce) přejde do propojovací tabulky bill_product a je typu numeric také. Opět integer 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 . Pokud product_id nebo bill_id by se měla změnit, změna se promítne do všech závislých položek v bill_product a nic se nezlomí. To jsou jen odkazy bez vlastního významu.
    Také jsem použil ON DELETE CASCADE pro bill_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. Do product 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že NULL hodnoty nejsou povoleny. (Ano, vše sloupce - sloupce primárního klíče jsou definovány UNIQUE NOT NULL automaticky.) To proto, že NULL hodnoty by nedávaly smysl v žádném ze sloupců. Usnadňuje život začátečníka. Ale tak snadno se nedostanete, musíte pochopit NULL manipulace stejně. Další sloupce mohou umožnit NULL hodnoty, funkce a spojení mohou zavádět NULL 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 na product_id nebo (product_id, bill_id) pokud máte dotazy týkající se daného product_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.




  1. nelze vytvořit autoinkrementační primární klíč pomocí flask-sqlalchemy

  2. Jak make_date() funguje v PostgreSQL

  3. Import CSV do MySQL

  4. Jak UNION funguje v PostgreSQL