タイトルは一目瞭然だと思います。多対多の関係を作成するには、PostgreSQLでテーブル構造をどのように作成しますか。
私の例:
Product(name, price);
Bill(name, date, Products);
タイトルは一目瞭然だと思います。多対多の関係を作成するには、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として列を追加しました。Postgres 10以降では、代わりにカラムを検討してください。見る:IDENTITY
製品の名前はほとんど一意ではないため、これを強くお勧めします(適切な「自然キー」ではありません)。また、一意性の強制と外部キーでの列の参照は、通常、or として格納された文字列よりintegerも4バイト(または8バイトbigint)の方が安価です。textvarchar
などの基本データ型の名前を使用しないでくださいdateとしての識別子。これは可能ですが、スタイルが悪いため、エラーとエラーメッセージがわかりにくくなります。正しい、小文字の引用符で囲まれていない識別子を使用してください。予約語は使用せず、可能であれば、二重引用符で囲まれた大文字と小文字の識別子を避けてください。
「名前」は良い名前ではありません。私は、テーブルの列を名前を変更productするproduct(またはproduct_nameまたは類似)。それはより良い命名規則です。それ以外の場合、クエリでいくつかのテーブルを結合すると(リレーショナルデータベースでは多くのことを行います)、 "name"という名前の複数の列ができ、列のエイリアスを使用して混乱を取り除く必要があります。それは役に立ちません。別の広く普及しているアンチパターンは、列名としての「id」だけです。
の名前がどうなるかわかりませんbill。bill_idこの場合はおそらく十分でしょう。
priceであるデータ・タイプ numeric分数を格納するために入力した正確(任意精度のタイプの代わりに、浮動小数点型)。整数のみを扱う場合は、そのようにしintegerます。たとえば、価格をセントとして保存できます。
amount("Products"あなたの質問で)リンクテーブルに入るbill_productと型であるnumericとしても。繰り返しintegerますが、整数のみを扱う場合。
に外部キーが表示されbill_productますか?変更をカスケードするために両方を作成しましたON UPDATE CASCADE。product_idまたはbill_idを変更する必要がある場合、変更はすべての依存するエントリにカスケードされbill_product、何も壊れません。それらは、それら自体の重要性のない単なる参照です。
私はまた使用しON DELETE CASCADEましたbill_id:請求書が削除された場合、その詳細はそれに伴って死にます。
製品についてはそうではありません。請求書で使用されている製品を削除したくない場合。これを試みるとPostgresはエラーをスローします。product代わりに、もう1つの列を追加して、古い行をマーク(「ソフト削除」)します。
この基本的な例のすべての列はになるNOT NULLため、NULL値は許可されません。(はい、すべての列-主キー列はUNIQUE NOT NULL自動的に定義されます。)これNULLは、どの列でも値が意味をなさないためです。初心者の方の生活を楽にします。しかし、それほど簡単に逃げることはできないので、とにかくNULL取り扱いを理解する必要があります。列を追加すると、NULL値、関数、結合が許可されNULL、クエリなどに値が導入される可能性があります。
CREATE TABLEマニュアルの章をお読みください。
主キーは、キー列に一意のインデックスを使用して実装されるため、PK列の条件を持つクエリが高速になります。ただし、キー列のシーケンスは複数列キーに関連しています。私の例でbill_productはPK on がオン(bill_id, product_id)になっているので、単に、product_idまたは(product_id, bill_id)指定されたproduct_idとnoを検索するクエリがある場合に、別のインデックスを追加することができますbill_id。見る:
マニュアルの索引に関する章を読んでください。
bill_productですか?通常は次のようになりますCREATE INDEX idx_bill_product_id ON booked_rates(bill_id, product_id)。これは正解?
bill。で追加したアイテムごとの金額が必要bill_productです。