Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > MySQL > Уникальная комбинация полей


Автор: Ripper 18.12.2011, 13:07
Здравствуйте.
У меня есть таблица предложений контрактов, где есть такие поля:
ID, proposer, target, contract_type, date. 

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

На ум приходит написать что-то вроде insert into contract_suggestion (proposer, target, contract_type, date) values (...) where not exists (select * from contract_suggestion where (proposer={$proposer} and  target={$target})  или как-то так. А, и еще пара должна быть уникальна с обоих сторон, т.е. не должно быть скажем двух пар: 2,5 и 5,2. Но я думаю есть более хорошее решение.

Спасибо заранее.

Автор: Zloxa 18.12.2011, 17:52
Добавить ограничение уникальности (unique constraint) по паре (proposer, target).
Другие способы обеспечения уникальности - от лукавого.

Автор: Ripper 19.12.2011, 02:10
Да, а вот если в случае что пара должна быть уникальна в обоих комбинациях? Например если есть 5,3 то 3,5 уже не должно быть?
В интернете нашел пример с триггером, вроде помогло)

Автор: Akina 19.12.2011, 08:04
Цитата(Ripper @  19.12.2011,  03:10 Найти цитируемый пост)
Например если есть 5,3 то 3,5 уже не должно быть?

Ввести constraint на уникальность CONCAT(MIN(proposer, target), MAX(proposer, target))

Автор: Zloxa 19.12.2011, 08:47
Akina, маська умеет строить ключи по функции? smile 

Цитата(Ripper @  19.12.2011,  02:10 Найти цитируемый пост)
 нашел пример с триггером

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

Автор: Akina 19.12.2011, 09:10
Цитата(Zloxa @  19.12.2011,  09:47 Найти цитируемый пост)
маська умеет строить ключи по функции?

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

Код

mysql> create table test (val int, val2 int);
Query OK, 0 rows affected (0.13 sec)

mysql> select * from test;
Empty set (0.00 sec)

mysql> delimiter @@
mysql> create trigger add_val2 before insert on test
    -> for each row begin
    -> set new.val2 = 5;
    -> end;
    -> @@
Query OK, 0 rows affected (0.03 sec)

mysql> delimiter ;

mysql> insert into test(val) values (1),(2);
Query OK, 2 rows affected (0.03 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from test;
+------+------+
| val  | val2 |
+------+------+
|    1 |    5 |
|    2 |    5 |
+------+------+
2 rows in set (0.00 sec)

mysql>

В примере val2 - как раз такое поле, заполняемое из триггера неявно. Наложите на него UNIQUE - и при дублировании вставка строк обломится. 
Код

mysql> delete from test;
Query OK, 2 rows affected (0.01 sec)

mysql> create unique index unique_val2 on test(val2);
Query OK, 0 rows affected (0.14 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> select * from test;
Empty set (0.00 sec)

mysql> insert into test(val) values (1),(2);
ERROR 1062 (23000): Duplicate entry '5' for key 1

mysql> select * from test;
Empty set (0.00 sec)

mysql> insert into test(val) values (1);
Query OK, 1 row affected (0.02 sec)

mysql> insert into test(val) values (2);
ERROR 1062 (23000): Duplicate entry '5' for key 1

mysql> select * from test;
+------+------+
| val  | val2 |
+------+------+
|    1 |    5 |
+------+------+
1 row in set (0.00 sec)

mysql>

Аналогично создаётся и триггер before update.

Поскольку мы работаем исключительно с таблицей NEW - нам не страшны никакие многопользовательские заморочки. Или, вернее, так - мы не получим никаких ДОПОЛНИТЕЛЬНЫХ граблей.

Автор: Zloxa 19.12.2011, 09:48
Цитата(Akina @  19.12.2011,  09:10 Найти цитируемый пост)
Нет. Но, как всегда, есть путь через задний проход...

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

Цитата(Akina @  19.12.2011,  09:10 Найти цитируемый пост)
Поскольку мы работаем исключительно с таблицей NEW - нам не страшны никакие многопользовательские заморочки. Или, вернее, так - мы не получим никаких ДОПОЛНИТЕЛЬНЫХ граблей.

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

Автор: Akina 19.12.2011, 10:20
Цитата(Zloxa @  19.12.2011,  10:48 Найти цитируемый пост)
Я спросил никак не потому, что хотел там подколоть или что-то вроде

Я знаю.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)