Как реализовать двунаправленный уникальный индекс для нескольких столбцов - PullRequest
1 голос
/ 20 сентября 2009

Хорошо, я знаю, что могу сделать это на прикладном уровне, что, вероятно, проще всего сделать, но просто чтобы убедиться, что в БД нет ошибок, у меня серьезный вопрос

У меня есть два столбца X и Y, каждый для хранения двух целых чисел (либо A, либо B в любом из столбцов). Можно ли иметь уникальное ограничение индекса, чтобы ни в коем случае не иметь

  1. Столбец X с A и Столбец Y с B
  2. Столбец X с буквой B и столбец Y с буквой A

Я приведу сценарий

У меня два пользователя, userA имеет идентификатор 678498, а userB имеет идентификатор 679879. Оба пользователя собираются сыграть в игру для двух игроков, которая требует сохранения новой записи для этого сеанса в таблице (tbl_chalenger). Для этого у меня есть таблица со столбцами «хост» и «претендент».

У меня есть уникальное ограничение, добавленное к tbl_challenger как

UNIQUE KEY `UNIQUE_PARTICIPANTS` (`host`,`challenger`)

Брендинг пользователей хостом или претендентом в основном зависит от того, кто инициировал игру. Так что, если пользователь А инициирует игру, у нас будет следующий запрос

INSERT INTO `tbl_challenger` VALUES(678498 , 679879); 

, которая создает новую запись, но, к сожалению, если одновременно пользователь B попытается начать игру с пользователем A, мы получим

INSERT INTO `tbl_challenger` VALUES(679879, 678498 ); 

Создает новую нежелательную строку из тех же участников. Это независимо от УНИКАЛЬНОГО ключевого ограничения.

Таким образом, мой вопрос заключается в том, как иметь ограничение, которое является двунаправленным?, Чтобы "хост-претендент", а также "претендент-хост" не могли иметь одну и ту же пару данных

Ответы [ 2 ]

8 голосов
/ 20 сентября 2009

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

CREATE TABLE tbl_challenger (
  host int,
  challenger int,
  u0 int, u1 int
);

и добавьте пару триггеров, которые устанавливают u0 и u1 к наименьшему и наибольшему из двух:

CREATE TRIGGER uinsert BEFORE INSERT ON tbl_challenger
 FOR EACH ROW SET NEW.u0 = LEAST(NEW.host,NEW.challenger),
  NEW.u1 = GREATEST(NEW.host,NEW.challenger);
CREATE TRIGGER uupdate BEFORE UPDATE ON tbl_challenger
 FOR EACH ROW SET NEW.u0 = LEAST(NEW.host,NEW.challenger),
  NEW.u1 = GREATEST(NEW.host,NEW.challenger);

затем вы добавляете уникальный индекс на (u0,u1)

CREATE UNIQUE INDEX uniqueness ON tbl_challenger(u0,u1);

И теперь вы получите сообщение об ошибке, пытаясь вставить дублирующую пару независимо от порядка.

В приличной СУБД, такой как PostgreSQL, вы можете использовать индекс для выражения:

CREATE UNIQUE INDEX uniqueness ON tbl_challenger
    ( LEAST(host,challenger), GREATEST( host,challenger) );

Итак, переключайтесь, пока не стало слишком поздно; -)

1 голос
/ 20 сентября 2009

Я не думаю, что вы можете сделать это "из коробки", например, с помощью уникального индекса или чего-то подобного.

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

Я довольно давно не работал с триггерами, и это не было в MySQL, поэтому я не смогу привести вам ни одного примера, но вот соответствующая страница руководства: 12.1.19 , CREATE TRIGGER Синтаксис

В качестве обозначения: этот тип ограничения, как вы сказали, обычно применяется на стороне приложения.

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