2017-02-06 41 views
0

我正在尋找如何使用NULL檢查來實現唯一約束。如何使用唯一約束在MySQL中使用NULL值

MySQL不應該允許多個空值。

員工:

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

你能分享一下你得到的錯誤嗎? – Sadikhasan

+0

我在問如何實現它。現在它將多個null插入到數據庫中 –

回答

3

不,MySQL是做正確的事,根據SQL-99規範。

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

的唯一約束使得它不可能犯任何的操作, 會導致唯一鍵包含任何非空重複的值。 (多允許空值,因爲空值永遠不會等於 到任何東西,甚至是另一個空值。)

如果你使用一個唯一的約束,但不希望與空多行後,宣佈該列作爲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翻轉nulldeleted_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。不需要插入vconst(但不能,無論如何)。

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

再次插入會引發重複輸入錯誤。

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到索引,或者用一個新的索引,但我會讓負載測試決定。