MySQL admite funcional partes clave desde 8.0.13 .
-
Si su versión es lo suficientemente reciente, puede definir su índice como:
UNIQUE(`user_id`, `test_id`, (IFNULL(`completed_date`, -1)))(Demostración en dbfiddle.uk )
Tenga en cuenta que el índice anterior también evitará fechas duplicadas para ejecuciones completadas. Si esos fueran válidos, entonces funcionaría un índice ligeramente modificado:
UNIQUE(`user_id`, `test_id`, ( CASE WHEN `completed_date` IS NOT NULL THEN NULL ELSE 0 END))(Demostración en dbfiddle.uk )
Aunque luego empieza a sentirse un poco sucio;)
-
Si tiene al menos la versión 5.7 puede usar una columna generada (virtual) como solución 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`) ); -
Si está atascado en 5.6 luego una combinación de una columna normal (no virtual) y
INSERTligeramente modificado las declaraciones funcionarían: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`) );En este caso, establecería
is_openatruepara ejecuciones incompletas y paraNULLdespués de la finalización, haciendo uso del hecho de que dosNULLs son tratados como no iguales.