MySQL supporta funzionali parti chiave da 8.0.13 .
-
Se la tua versione è sufficientemente recente puoi definire il tuo indice come:
UNIQUE(`user_id`, `test_id`, (IFNULL(`completed_date`, -1)))
Si noti che l'indice sopra eviterà anche la duplicazione delle date per le esecuzioni completate. Se quelli dovessero essere validi, allora un indice leggermente modificato funzionerebbe:
UNIQUE(`user_id`, `test_id`, ( CASE WHEN `completed_date` IS NOT NULL THEN NULL ELSE 0 END))
Anche se poi inizia a sembrare un po' sporco;)
-
Se hai almeno la versione 5.7 puoi utilizzare una colonna generata (virtuale) come soluzione alternativa:
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`) );
-
Se sei bloccato su 5.6 quindi una combinazione di una colonna normale (non virtuale) e
INSERT
leggermente modificato le dichiarazioni funzionerebbero: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`) );
In questo caso dovresti impostare
is_open
sutrue
per esecuzioni incomplete e suNULL
dopo il completamento, sfruttando il fatto che dueNULL
s sono trattati come non uguali.