単一のテーブルで複数の一意の制約を使用すると、設計が悪いと見なされますか?


8

私はPostgreSQLのINSERT INTO .. ON CONFLICT (..) DO UPDATE ..構文を見ていましたが、それを使用して複数の一意制約チェックを実行することはできません。つまり、複合一意インデックスを列名で参照するかON CONFLICT (Name, Symbol)(一意のインデックスがこれらの2つの列に対して定義されている場合)、または主キーを使用します。列に2つの個別の一意のインデックスを定義する場合、チェックできるのは1つだけです。

CREATE TABLE student
    (Id int primary key, Name varchar(50), Symbol varchar(50),
      CONSTRAINT col1_unique UNIQUE (Name),
      CONSTRAINT col2_unique UNIQUE (Symbol)
    ); 

INSERT INTO student
    (Id, Name, Symbol)
VALUES
    (1, 'John', 'J'),
    (2, 'David', 'D'),
    (3, 'Will', 'W');

INSERT INTO student
    (Id, Name, Symbol)
VALUES
    (4, 'Jeremy', 'J')
   on conflict(Name) DO UPDATE
   set Name = 'Jeremy';

J重複していると言ってエラーをスローする可能性があります。ただし、この例はシンボルが別のテーブルにあり、1対多の関係で生徒のテーブルに接続されている必要があるため、単に悪いデザインです。ですから、PostgreSQL on conflictはこのように設計されたのではないかと思います。一意のインデックスが1つしかない方法で、常にテーブルを再構築できるからです。それは本当ですか、それとも別の理由がありますか?

フィドルの例:http ://www.sqlfiddle.com/#!17/ 9c0ce


EntityAとEntityBがある一意のインデックス1つしかない方法で、常にテーブルを再構築できます。それぞれに2つのインスタンスがあります。任意のEntityAインスタンスは任意のEntityBインスタンスと組み合わせることができるため、すべてのインスタンスが使用される2つの可能な組み合わせがあります。この組み合わせの1つが実現され、それを保存する必要があります。次に、2つの一意のテーブルが存在せず、すべての制約があり、不正なデータを防止するスキームを作成してみます。
Akina

@Akinaあなたのポイントを逃した。2つのエンティティが多対多の関係で接続されている場合、リンクテーブルを作成し、それらの外部キーを格納するため、2つの一意のインデックスを持つテーブルはありません。
appl3r 2018年

1つのインスタンスは1回しか使用できないため、すでに使用されているインスタンスが使用されないようにするには、リンクされたテーブルに2つの一意のインデックス(エンティティごとに個別に)が必要です。
Akina

それは本当ですが、それはかなり面倒です。MichaelGreenの回答のサンプルを参照してください。このような単純なテーブルを4つのテーブルに分割することは、間違いなく頭痛の種です。これは単純な辞書なので、 "ON CONFLICT"オプションを必要とするべきではないようです。
Walfrat 2018年

回答:


8

常に6番目のドメインキー、つまりドメインキーが存在します。ここでは、各非キー列が独自のテーブルになります。したがって、3NFテーブルT(Key、Col1、Col2、..)はT1(Key、Col1)、T2(Key、Col2)などになります。一意性を必要とする新しいテーブルは、それを宣言できます。

ただし、テーブルに複数の一意の制約を設定しても問題ありません。国の表を例にとってみましょう。これには、たとえば、ID、名前、ISOコード、首都などが含まれます。最初の4つはそれぞれ一意です。さらに、私たちのシステムがそれぞれが一意であることを信頼したい場合は、それぞれに一意の制約を定義する必要があると思います。これにより、すべての消費者が信頼できるデータに関する真実が強制されます。


postgresqlの設計は近視眼の結果にすぎないと思いますか?Oracle、SQL Server、DB2などはすべて、このような状況で(MERGEステートメントを使用して)すべての一意のキーを考慮する方法を提供します。pg ON CONFLICT DO UPDATE は9.5でのみ追加され、はるかに制限されています。
appl3r

1
@ appl3rそれは単なる実装の詳細です。ON CONFLICT DO NOTHING一意の制約について言及せずに行うことができ、それらはすべてを考慮します(そして何もしません)。行うON CONFLICT DO UPDATE場合は、列または制約を1つだけ宣言する必要があります。この制限は将来のバージョンで解除される可能性があります。
ypercubeᵀᴹ

私はあなたの最初の段落に少し混乱しています。OPのStudent(Id、Name、Symbol)テーブルをS1(Id、Name)とS2(Id、Symbol)に分割して、それをDK / NFにしようとするとします。S2の(ドメインおよび)キー制約はどのようなものであり、各学生が単一の一意のIDと単一の一意のシンボルの両方を持つことをどのように保証しますか?
Ilmari Karonen

1
質問は、複数のUNIQUEインデックスが罰金であれば、なぜPostgreSQLは、アービタインデックスが指定されていることを必要としない」(種類の)だったON CONFLICT ... DO UPDATEと、残念ながら、この答えはアドレスがないという点。
AndreKR

@AndreKRは(太字)に対応しています:「(このPostgresの機能は)この方法で設計されました。これは、常に単一の一意のインデックスしかない方法でテーブルを再構築できるためです。」あなたは確かにあなたが言及してポイントを扱う、別の答えを追加することができます
ypercubeᵀᴹ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.