Как создать «двусторонний» уникальный индекс на двух полях? - PullRequest
5 голосов
/ 23 октября 2008

Как эффективно создать уникальный индекс для двух полей в таблице, например так: создать таблицу t (целое число, целое число b);

, где любая уникальная комбинация двух разных чисел не может появляться более одного раза в одной строке таблицы.

В словах порядка, если строка существует так, что a = 1 и b = 2, не может существовать другая строка, где a = 2 и b = 1 или a = 1 и b = 2. Другими словами, два числа не могут появляться вместе более одного раза в любом порядке.

Понятия не имею, как называется такое ограничение, отсюда и название «двухсторонний уникальный индекс» в заголовке.

Обновление : если у меня есть составной ключ для столбцов (a, b), и в базе данных существует строка (1,2), можно вставить другую строку (2,1) без ошибок. То, что я ищу, - это способ предотвратить повторное использование одной и той же пары чисел в любом порядке ...

Ответы [ 4 ]

6 голосов
/ 23 октября 2008

Как насчет управления тем, что входит в таблицу, чтобы вы всегда сохраняли наименьшее число в первом столбце, а наибольшее - во втором? Пока это «означает» то же самое, конечно. Вероятно, это дешевле сделать, прежде чем он попадет в базу данных.

Если это невозможно, вы можете сохранить поля как есть, но скопировать их в числовом порядке в два ДРУГИХ поля, в которых вы бы создали первичный ключ (псевдокод):

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 )

Это можно легко сделать с помощью триггера (как в ответе Рональда) или обработать в приложении вверх.

3 голосов
/ 23 октября 2008

Я думаю, что это можно сделать только с помощью триггера FOR INSERT (в сочетании с уникальным ограничением на два столбца). Я не очень хорошо разбираюсь в синтаксисе MySql (мой T-SQL лучше), поэтому я предполагаю, что следующее будет содержать некоторые ошибки:

Редактировать: Очистить синтаксис, чтобы он работал для MySQL. Кроме того, обратите внимание, что вы, вероятно, захотите использовать это как BEFORE UPDATE триггер (с другим именем, конечно).

Кроме того, этот метод основан на наличии первичного или иного уникального ключа в двух полях (т. Е. Этот триггер проверяет, что обратное еще не существует). Похоже, нет никакого способа выбросить ошибку триггер, так что я смею сказать, что это так хорошо, как он получает.

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;
2 голосов
/ 23 октября 2008

В Oracle вы можете использовать индекс на основе функций, например:

create unique index mytab_idx on mytab (least(a,b), greatest(a,b));

Я не знаю mySQL, но, возможно, возможно нечто подобное? Например, вы можете добавить в таблицу 2 новых столбца leastab и greatestab с триггером, чтобы поддерживать их значениями наименьшего (a, b) и наибольшего (a, b) соответственно, а затем создать уникальный индекс для (leastab). , greatestab).

1 голос
/ 23 октября 2008
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...