web-dev-qa-db-ja.com

同じテーブルへの2つの外部キーで構成される複合主キーの一意性を強制する方法は?

2つのテーブルがあります。userテーブルとfriendshipテーブルです。 friendshipテーブルが次のようになっているとします。

friendship
------------
user_one_id
user_two_id
other_fields

(user_one_id, user_two_id)の値の組み合わせの一意性を適用し、orderingを無視する必要があるため、次のようにします。

user_one_id | user_two_id
------------+------------
          1 |          2
          2 |          1  -- the DBMS should throw a unique constraint error when trying to insert a row like this one.

もう1つの重要な点は、user_one_idfriendship開始者を表し、user_two_id受信者なので、2つのidsuser_one_idを「小さく」することはできません。

質問

制約を使用してこれを行う方法はありますか、これを他の方法で実装する必要がありますか?

7
maniciam

あなたのコメントに照らして、

私の使用例では、user_one_idは友情の開始者を表し、user_two_idは友情の受信者を表します。 したがって、user_one_idとして最小値を使用することはできません。

まあ、あなたはまだそれを行うことができます。ユースケースでは、それを確実にするために行制約を除外しています。あなたが望むのは、このようなテーブル制約を使用することです。

_CREATE TABLE friendship (
  user_one_id int NOT NULL,
  user_two_id int NOT NULL,
  CHECK (user_one_id != user_two_id ),
  PRIMARY KEY (user_one_id, user_two_id)
);
-- you can do least first if you want. doesn't matter.
CREATE UNIQUE INDEX ON friendship (
  greatest(user_one_id, user_two_id),
  least(user_one_id, user_two_id)
);
_

ここでは多くのことが起こっています。

  1. どちらも_NOT NULL_です
  2. 両方が等しくない
  3. どちらもUNIQUE (user_one_id, user_two_id)です

可換一意性の問題が1つ残っていますが、インデックスで実装されたカスタムの一意のテーブル制約を使用してそれを解決します。

プリンの証明

_INSERT INTO friendship VALUES ( 1,2 );
INSERT 0 1
test=# INSERT INTO friendship VALUES ( 2,1 );
ERROR:  duplicate key value violates unique constraint friendship_greatest_least_idx"
DETAIL:  Key ((GREATEST(user_one_id, user_two_id)), (LEAST(user_one_id, user_two_id)))=(2, 1) already exists.
_

重要な友好的なメモとして、あなたの名前はあらゆる種類のばかげています。関係は結構です。本番環境では、pleaseより良い名前を付けてください。

_friendship
----------
request_initiator
request_target
other_fields
_
8
Evan Carroll

ソリューションは非常に優れています。ただし、最初に2つの列に数値の重複がないことを確認する必要があります。つまり、番号は列に対して一意になります。

次のシンプルトンソリューションをお勧めします。

2つのシーケンスを作成します。

1。

user_one_id_seq:偶数

奇数のuser_two_id_seq

2。

user_one_id_seq:たとえば1から10000までの数字

user_two_id_seqは、たとえば10001から20000までの数値

0
krishna

User_friendshipという名前の交差テーブルを作成して、設計を正規化する必要があります。

create user_friendship(user id int NOT NULL、friendship id int NOT NULL、PRIMARY KEY(user_id、friendship_id)、FOREIGN KEY friendship_id REFERENCES friendship(friendship_id)、FOREIGN KEY user_id REFERENCES user(user_id)
);

0
krishna