MySQL unterstützt funktionale Schlüsselteile seit 8.0.13 .
-
Wenn Ihre Version aktuell genug ist, können Sie Ihren Index wie folgt definieren:
UNIQUE(`user_id`, `test_id`, (IFNULL(`completed_date`, -1)))
Beachten Sie, dass der obige Index auch doppelte Daten für abgeschlossene Ausführungen verhindert. Wenn diese gültig sein sollten, würde ein leicht modifizierter Index funktionieren:
UNIQUE(`user_id`, `test_id`, ( CASE WHEN `completed_date` IS NOT NULL THEN NULL ELSE 0 END))
Allerdings fühlt es sich dann etwas schmutzig an;)
-
Wenn Sie mindestens Version 5.7 haben Sie können eine (virtuelle) generierte Spalte verwenden als Problemumgehung:
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`) );
-
Wenn Sie bei 5.6 hängen bleiben dann eine Kombination aus einer regulären (nicht virtuellen) Spalte und leicht modifiziertem
INSERT
Anweisungen funktionieren würden: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 diesem Fall würden Sie
is_open
setzen auftrue
für unvollständige Ausführungen und aufNULL
nach Abschluss, wobei die Tatsache ausgenutzt wird, dass zweiNULL
s werden als ungleich behandelt.