2015-08-08 10 views
6

Mam tabelę transakcji, w której można przechowywać kilka wierszy w odniesieniu do trzech atrybutów (foo_id, bar_id), a ostatni atrybut jest usunięty, myślę tutaj, aby upewnić się, że mam tylko jeden aktywny wiersz naraz (deleted_at = '0000-00-00 00:00:00').MySQL - unikalny klucz złożony z datetime

Ale ja otrzymuję następujący błąd:

mysql> UPDATE epic_table SET deleted_at = NOW() WHERE (foo_id = '1' AND bar_id IN ('18')); 
ERROR 1062 (23000): Duplicate entry '18-1-2015-08-08 16:35:46' for key 'epic_table_ibuk_1' 

Oto schemat:

CREATE TABLE `epic_table` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
    `foo_id` bigint(20) unsigned NOT NULL, 
    `bar_id` bigint(20) unsigned NOT NULL, 
    `created_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
    `deleted_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `epic_table_ibuk_1` (`foo_id`,`bar_id`,`deleted_at`), 
    KEY `epic_table_ibfk_1` (`foo_id`), 
    KEY `epic_table_ibfk_2` (`bar_id`), 
    CONSTRAINT `epic_table_ibfk_1` FOREIGN KEY (`foo_id`) REFERENCES `foo` (`id`), 
    CONSTRAINT `epic_table_ibfk_2` FOREIGN KEY (`bar_id`) REFERENCES `bar` (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8 

Jedyną rzeczą, która natychmiast wyróżnia to, że MySQL nie może być brane pod uwagę część porze wartość datetime, a zatem narzekanie na inny wiersz z 18-1-2015-08-08.

Jakieś pomysły, w jaki sposób mogę utrzymać elastyczność w wielu wierszach, jednocześnie będąc w stanie wyegzekwować, że tylko jeden wiersz jest "aktywny" w danym momencie?

+2

Does '(foo_id = '1' AND bar_id IN ('18'))' dopasować dokładnie _one_ wiersz? Jeśli faktycznie pasuje do więcej niż jednego, nowa wartość 'NOW()' spowoduje naruszenie ograniczenia klucza. Jeśli jest więcej niż jeden, ale chcesz wybrać tylko jeden z 'LIMIT' (który uniknie naruszenia unikalności), na jakie inne kryteria byś je posortował? –

+0

Nie, może być X liczba wierszy z foo_id = 1, bar_id = 18, jedyną różnicą między nimi byłaby wartość deleted_at, przy czym tylko jeden z wielu miałby usunięty_at = '0000-00-00 00:00:00 " –

+2

@MikePurcell, jeśli masz wiele wierszy z foo_id = 1 i bar_id = 18, instrukcja aktualizacji prosi wszystkie wiersze, aby zostały zaktualizowane za pomocą metody deleted_at = NOW(), a tym samym powodując nieunikalność. Czy mógłbyś zmienić klauzulę where, aby użyć 'and deleted_at = '0000-00-00 00: 00: 00''? – zedfoxus

Odpowiedz

7

Zmiana z komentarzem do odpowiedzi ...

Oświadczenie:

UPDATE epic_table SET deleted_at = NOW() 
WHERE (foo_id = '1' AND bar_id IN ('18')); 

próbuje ustawić deleted_at dla wszystkich wierszy z foo_id = 1 i bar_id = 18. Ponieważ kombinacja foo_id, bar_id i deleted_at jest oznaczona jako unikalna, taka zmiana kończy się naruszeniem wyjątkowego ograniczenia.

Tylko niewielka zmiana może być potrzebne do rachunku jak tak, wiedząc, że tylko jeden rekord może mieć deleted_at = '0000-00-00 00:00:00':

UPDATE epic_table SET deleted_at = NOW() 
WHERE (foo_id = '1' AND bar_id IN ('18') and deleted_at = '0000-00-00 00:00:00'); 
Powiązane problemy