2つのフィールドに「両面」一意インデックスを作成する方法
-
04-07-2019 - |
質問
このようにテーブル内の2つのフィールドに一意のインデックスを効率的に作成するにはどうすればよいですか: テーブルt(整数、b整数)を作成します。
2つの異なる数字の一意の組み合わせは、表の同じ行に複数回表示できません。
順序ワードでは、a = 1およびb = 2のような行が存在する場合、a = 2およびb = 1またはa = 1およびb = 2の別の行は存在できません。言い換えれば、2つの数字を任意の順序で複数回一緒に表示することはできません。
このような制約が何と呼ばれるかわかりません。したがって、タイトルの「両側一意インデックス」の名前です。
更新:列(a、b)に複合キーがあり、データベースに行(1,2)が存在する場合、別の行(2,1 )エラーなし。私が探しているのは、同じ数字のペアが複数回使用されるのを防ぐ方法です。 任意の順序 ...
解決
最初の列に最小の数値を、2番目の列に最大の数値を常に格納するように、テーブルの内容を制御するのはどうですか?もちろん同じことを「意味する」限り。データベースに到達する前に行う方がおそらく低コストです。
これが不可能な場合は、フィールドをそのまま保存することができますが、それらを2つのその他のフィールドに番号順に複製し、そのフィールドで主キー(擬似コードのような)を作成します:
COLUMN A : 2
COLUMN B : 1
COLUMN A_PK : 1 ( if new.a < new.b then new.a else new.b )
COLUMN B_PK : 2 ( if new.b > new.a then new.b else new.a )
これは、Ronaldの応答のように、トリガーを使用して簡単に実行できます。または、アプリケーションで上位に処理できます。
他のヒント
これは、FOR INSERTトリガー(2つの列の一意制約と組み合わせて)を使用してのみ実行できると思います。私はMySql構文にあまり流fluentではありません(私のT-SQLの方が優れています)ので、以下にいくつかのエラーが含まれると思います:
編集: MySQLで機能するように構文を整理しました。また、これをおそらく BEFORE UPDATE
トリガーとして(もちろん別の名前で)配置することに注意してください。
また、このメソッドは、2つのフィールドに主キーまたは一意のキーがあることに依存しています(つまり、このトリガーは、リバースがまだ存在していないことを確認するだけです)。トリガーなので、私はあえてこれが良いと言います。
CREATE TRIGGER tr_CheckDuplicates_insert
BEFORE INSERT ON t
FOR EACH ROW
BEGIN
DECLARE rowCount INT;
SELECT COUNT(*) INTO rowCount
FROM t
WHERE a = NEW.b AND b = NEW.a;
IF rowCount > 0 THEN
-- Oops, we need a temporary variable here. Oh well.
-- Switch the values so that the key will cause the insert to fail.
SET rowCount = NEW.a, NEW.a = NEW.b, NEW.b = rowCount;
END IF;
END;
Oracleでは、次のような関数ベースのインデックスを使用できます。
create unique index mytab_idx on mytab (least(a,b), greatest(a,b));
mySQLはわかりませんが、似たようなことが可能でしょうか?たとえば、最小値と最大値の2つの新しい列をテーブルに追加し、それぞれ最小値(a、b)と最大値(a、b)を保持するトリガーを使用して、一意のインデックスを(leastab 、greatestab)。