MySQL поддържа функционални ключови части от 8.0.13 .
-
Ако вашата версия е достатъчно нова, можете да дефинирате своя индекс като:
UNIQUE(`user_id`, `test_id`, (IFNULL(`completed_date`, -1)))
Имайте предвид, че горният индекс също ще предотврати дублиране на дати за завършени екзекуции. Ако те трябва да са валидни, тогава леко модифициран индекс ще работи:
UNIQUE(`user_id`, `test_id`, ( CASE WHEN `completed_date` IS NOT NULL THEN NULL ELSE 0 END))
Въпреки че след това започва да се чувства малко мръсен;)
-
Ако имате поне версия 5.7 можете да използвате (виртуална) генерирана колона като заобиколно решение:
CREATE TABLE `executed_tests` ( `id` INTEGER AUTO_INCREMENT NOT NULL, `user_id` INTEGER NOT NULL, `test_id` INTEGER NOT NULL, `start_date` DATE NOT NULL, `completed_date` DATE, `_helper` CHAR(11) AS (IFNULL(`completed_date`, -1)), PRIMARY KEY (`id`), UNIQUE(`user_id`, `test_id`, `_helper`) );
-
Ако сте заседнали на 5.6 след това комбинация от обикновена (невиртуална) колона и леко модифициран
INSERT
изразите биха работили:CREATE TABLE `executed_tests` ( `id` INTEGER AUTO_INCREMENT NOT NULL, `user_id` INTEGER NOT NULL, `test_id` INTEGER NOT NULL, `start_date` DATE NOT NULL, `completed_date` DATE, `is_open` BOOLEAN, PRIMARY KEY (`id`), UNIQUE(`user_id`, `test_id`, `is_open`) );
В този случай бихте задали
is_open
наtrue
за непълни изпълнения и къмNULL
след завършване, използвайки факта, че двеNULL
s се третират като неравни.