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
к индексу, или новый индекс с ним, но я дам мои тесты нагрузки решить.
Вы можете поделиться тем, что получаете ошибку? – Sadikhasan
Я спрашиваю, как его достичь. Теперь он вставляет несколько null в db –