タイトルは一目瞭然だと思います。多対多の関係を作成するために、PostgreSQLでテーブル構造をどのように作成しますか。
私の例:
Product(name, price);
Bill(name, date, Products);
SQL DDL(データ定義言語)ステートメントは次のようになります。
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
);
いくつかの調整を行いました。
n:m関係は通常、個別のテーブル(この場合はbill_product
)によって実装されます。
serial
列を代理主キーとして追加しました。製品の名前はほとんど一意ではないため、これを強くお勧めします。また、4バイトのinteger
を使用すると、text
またはvarchar
として保存された文字列を使用するよりも、一意性を強制して外部キーの列を参照する方がはるかに安価です。
Postgres 10以降では、代わりに IDENTITY
列 を検討してください。詳細:
date
などの基本データ型の名前をidentifiersとして使用しないでください。これは可能ですが、スタイルが悪く、紛らわしいエラーやエラーメッセージにつながります。 正当な小文字の引用符で囲まれていない識別子 を使用します。 予約語 は使用せず、可能であれば二重引用符で囲まれた大文字と小文字の区別を避けてください。
name
は良い名前ではありません。テーブルname
のproduct
列の名前をproduct
に変更しました。それは、より良い命名規則です。それ以外の場合、クエリでいくつかのテーブルを結合する場合-リレーショナルデータベースでa lotを実行すると、name
という名前の複数の列になり、列エイリアスを使用して並べ替える必要があります混乱を。それは役に立たない。別の広範なアンチパターンは、列名としてid
だけです。bill
の名前がわからない。この場合、bill_id
はnameになります。
price
はdata typenumeric
で、小数を保存します入力されたとおりに正確(浮動小数点型ではなく任意の精度型)。整数のみを扱う場合は、integer
にしてください。たとえば、価格はセントとしてと保存できます。
amount
(質問では"Products"
)はリンクテーブルbill_product
に入り、タイプもnumeric
になります。繰り返しますが、整数のみを扱う場合はinteger
です。
bill_product
?にforeign keysが表示されます変更をカスケードするために両方を作成しました(ON UPDATE CASCADE
):product_id
またはbill_id
を変更する必要がある場合、変更はbill_product
の依存するすべてのエントリにカスケードされ、何も壊れません。ON DELETE CASCADE
もbill_id
に使用しました。請求書を削除すると、詳細も一緒に削除されます。
製品についてはそうではありません:請求書で使用されている製品を削除したくありません。これを試みると、Postgresはエラーをスローします。代わりにproduct
に別の列を追加して、古い行をマークします。
この基本的な例のすべての列は最終的にNOT NULL
になるため、NULL
値は許可されません。 (はい、all columns-主キーで使用される列はUNIQUE NOT NULL
で自動的に定義されます。)これは、NULL
値がどの列でも意味をなさないためです。初心者の生活が楽になります。しかし、それほど簡単に逃げることはできません。とにかく NULL
の処理 を理解する必要があります。追加の列により、NULL
値が許可される場合があります。関数および結合では、クエリなどでNULL
値を導入できます。
マニュアルの CREATE TABLE
に関する章を読んでください 。
主キーは、キー列に一意のindexを使用して実装されます。これにより、PK列の条件を持つクエリが高速になります。ただし、キー列の順序は複数列キーに関連しています。 bill_product
のPKは私の例では(bill_id, product_id)
にあるため、product_id
を探して(product_id, bill_id)
を探しているクエリがある場合は、product_id
またはbill_id
だけに別のインデックスを追加できます。詳細:
マニュアルのインデックスに関する の章をお読みください 。