MySQL understøtter funktionelle nøgledele siden 8.0.13 .
-
Hvis din version er tilstrækkelig ny, kan du definere dit indeks som:
UNIQUE(`user_id`, `test_id`, (IFNULL(`completed_date`, -1)))
Bemærk, at ovenstående indeks også vil forhindre duplikerede datoer for afsluttede henrettelser. Hvis disse skulle være gyldige, ville et let ændret indeks fungere:
UNIQUE(`user_id`, `test_id`, ( CASE WHEN `completed_date` IS NOT NULL THEN NULL ELSE 0 END))
Selvom det så begynder at føles lidt beskidt;)
-
Hvis du mindst har version 5.7 du kan bruge en (virtuel) genereret kolonne som en løsning:
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`) );
-
Hvis du sidder fast på 5.6 derefter en kombination af en almindelig (ikke-virtuel) kolonne og let ændret
INSERT
udsagn ville fungere: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`) );
I dette tilfælde ville du indstille
is_open
tiltrue
for ufuldstændige eksekveringer og tilNULL
efter afslutning, ved at bruge det faktum, at toNULL
s behandles som ulige.