2017-02-06 17 views
0

Я ищу, как реализовать уникальные ограничения с помощью проверки NULL.Как работать с уникальными ограничениями с NULL-значением в MySQL

MySQL не должен допускать множественное нулевое значение.

Сотрудник:

id | name 
---|----- 
1 | null 
2 | null -> should give error during inserting 2nd row. 
+0

Вы можете поделиться тем, что получаете ошибку? – Sadikhasan

+0

Я спрашиваю, как его достичь. Теперь он вставляет несколько null в db –

ответ

3

Нет, MySQL делает правильно, в соответствии со спецификацией SQL-99.

https://mariadb.com/kb/en/sql-99/constraint_type-unique-constraint/

УНИКАЛЬНЫЙ Constraint делает невозможным совершить какое-либо действие, которое приведет к уникальный ключ, чтобы содержать ненулевые значения дубликатов. (Multiple нулевые значения допускаются, так как нулевое значение никогда не равно ни к чему, даже другое пустое значение.)

Если вы используете UNIQUE ограничение, но не нужно несколько строк с NULL, объявить столбцы как NOT NULL и запретить любой ряд с NULL.

1

MySQL 5.7 допускает наличие обходного:

mysql> CREATE TABLE `null_test` (
    -> `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    -> `const` varchar(255) NOT NULL DEFAULT '', 
    -> `deleted_at` datetime DEFAULT NULL, 
    -> PRIMARY KEY (`id`) 
    ->) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; 
Query OK, 0 rows affected (0.03 sec) 

С мягкими удалений, было бы неплохо, если бы вы могли иметь только один ряд с с deleted_at = NULL на ограничение.

mysql> ALTER TABLE `null_test` ADD `vconst` int(1) GENERATED ALWAYS AS (((NULL = `deleted_at`) or (NULL <=> `deleted_at`))) VIRTUAL; 
Query OK, 0 rows affected (0.01 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

Так что я создал виртуальный столбец, который будет переворачивать от 1 к null когда deleted_at получает набор.

mysql> ALTER TABLE `null_test` ADD UNIQUE KEY `nullable_index` (`const`,`vconst`); 
Query OK, 0 rows affected (0.01 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

Вместо того, в том числе deleted_at на ограничение уникальности добавить виртуальный столбец, vconst.

mysql> INSERT INTO `null_test` SET `const` = 'Ghost'; 
Query OK, 1 row affected (0.00 sec) 

mysql> SELECT * FROM `null_test` WHERE `const` = 'Ghost'; 
+--------+-------+------------+--------+ 
| id  | const | deleted_at | vconst | 
+--------+-------+------------+--------+ 
| 999901 | Ghost | NULL  |  1 | 
+--------+-------+------------+--------+ 
1 row in set (0.01 sec) 

Нет необходимости, чтобы вставить vconst (но вы не можете, так или иначе).

mysql> INSERT INTO `null_test` SET `const` = 'Ghost'; 
ERROR 1062 (23000): Duplicate entry 'Ghost-1' for key 'nullable_index' 

Вставка его снова вызывает ошибку Duplicate entry.

mysql> UPDATE `null_test` SET `deleted_at` = NOW() WHERE `const` = 'Ghost'; 
Query OK, 1 row affected (0.00 sec) 
Rows matched: 1 Changed: 1 Warnings: 0 

То же самое с установкой delete_at, не нужно трогать vconst, он будет переворачивать автоматически.

mysql> SELECT * FROM `null_test` WHERE `const` = 'Ghost'; 
+--------+-------+---------------------+--------+ 
| id  | const | deleted_at   | vconst | 
+--------+-------+---------------------+--------+ 
| 999901 | Ghost | 2017-02-16 22:07:45 | NULL | 
+--------+-------+---------------------+--------+ 
1 row in set (0.00 sec) 

mysql> INSERT INTO `null_test` SET `const` = 'Ghost'; 
Query OK, 1 row affected (0.00 sec) 

Теперь вы можете вставить новую строку с теми же ограничениями!

mysql> SELECT * FROM `null_test` WHERE `const` = 'Ghost'; 
+--------+-------+---------------------+--------+ 
| id  | const | deleted_at   | vconst | 
+--------+-------+---------------------+--------+ 
| 999901 | Ghost | 2017-02-16 22:07:45 | NULL | 
| 999903 | Ghost | NULL    |  1 | 
+--------+-------+---------------------+--------+ 
2 rows in set (0.01 sec) 

В этом случае, в зависимости от того, сколько вы мягкое удаление, установка deleted_at, вы можете включить deleted_at к индексу, или новый индекс с ним, но я дам мои тесты нагрузки решить.