sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQLで多対多の関係を実装するにはどうすればよいですか?

    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を検討してください 代わりに列。参照:

      • シリアル主キー列を使用してテーブルの名前を安全に変更します
      • テーブル列の自動インクリメント
      • https://www.2ndquadrant.com/en/blog/postgresql-10-identity-columns/

      製品の名前はほとんど一意ではないため(適切な「自然キー」ではない)、強くお勧めします。また、一意性を強制し、外部キーで列を参照する方が、通常、4バイトの integerを使用する方が安価です。 (または8バイトの bigint textとして保存された文字列よりも またはvarchar

    • dateのような基本的なデータ型の名前は使用しないでください 識別子として 。これは可能ですが、スタイルが悪く、混乱を招くエラーやエラーメッセージが表示されます。正当な小文字の引用符で囲まれていない識別子を使用します。予約語は絶対に使用せず、可能であれば二重引用符で囲まれた大文字と小文字を区別する識別子は避けてください。

    • 「名前」は良い名前ではありません。テーブルの列の名前をproductに変更しました productになる (または product_name または類似)。それはより良い命名規則です 。それ以外の場合は、クエリでいくつかのテーブルを結合するときに、多くのを実行します。 リレーショナルデータベースでは、「name」という名前の複数の列ができてしまい、列エイリアスを使用して混乱を整理する必要があります。それは役に立ちません。もう1つの一般的なアンチパターンは、列名としての「id」です。
      請求書の名前がわかりません。 だろう。 bill_id この場合はおそらく十分でしょう。

    • 価格 データ型です 数値 小数を入力どおりに正確に保存する (浮動小数点型ではなく任意精度型)。整数のみを扱う場合は、その integerを作成します 。たとえば、価格をセントで節約できます。 。

    • 金額 "Products" あなたの質問では)リンクテーブル bill_productに入ります タイプはnumeric 同じように。繰り返しますが、 integer 整数のみを扱う場合。

    • 外部キーが表示されます bill_productで ?変更をカスケードするために両方を作成しました: ON UPDATE CASCADE product_idの場合 またはbill_id 変更する必要がある場合、変更は bill_productのすべての依存エントリにカスケードされます そして何も壊れません。これらは、それ自体の意味を持たない単なる参照です。
      ON DELETE CASCADEも使用しました bill_idの場合 :請求書が削除されると、その詳細は削除されます。
      製品の場合はそうではありません:請求書で使用されている製品を削除したくありません。これを試みると、Postgresはエラーをスローします。 productに別の列を追加します 代わりに、廃止された行にマークを付ける( "soft-delete")。

    • この基本的な例のすべての列は、最終的に NOT NULL になります 、したがって NULL 値は許可されていません。 (はい、すべて 列-主キー列が定義されていますUNIQUENOT NULL 自動的に。)それは NULL 値はどの列でも意味がありません。それは初心者の生活を楽にします。しかし、あなたはそれほど簡単に逃げることはできません、あなたは NULLを理解する必要があります とにかく処理します。追加の列により、 NULLが許可される場合があります 値、関数、および結合により、 NULLが導入される可能性があります クエリなどの値

    • CREATE TABLEの章を読んでください マニュアルで。

    • 主キーは、一意のインデックスで実装されます キー列で、PK列の条件を使用したクエリを高速化します。ただし、キー列のシーケンスは複数列のキーに関連しています。 bill_productのPK以降 (bill_id、product_id)にあります 私の例では、 product_idだけに別のインデックスを追加することをお勧めします または(product_id、bill_id) 特定のproduct_idを検索するクエリがある場合 bill_idはありません 。参照:

      • PostgreSQL複合主キー
      • 複合インデックスは、最初のフィールドのクエリにも適していますか?
      • PostgreSQLでのインデックスの動作
    • マニュアルのインデックスに関する章を読んでください。




    1. JavaからOracle関数を呼び出す

    2. 複数列のSQLMAX?

    3. ユニオンおよびCLOBフィールドで選択を使用する場合のエラーORA-00932

    4. MySQLでCASE..WHENを適切に使用するにはどうすればよいですか