2015-08-08 21 views
6

Ho una tabella di transazioni in cui più righe possono essere archiviate su tre attributi (foo_id, bar_id) e l'ultimo attributo è cancellato_at, il pensiero qui è di garantire che ho solo una riga attiva alla volta (deleted_at = '0000-00-00 00:00:00').MySQL - Chiave univoca composita con datetime

Ma sto ottenendo il seguente errore:

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' 

Ecco lo schema:

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 

L'unica cosa che si distingue subito è che MySQL non può essere considerato la parte relativa all'ora del valore datetime e quindi lamentarsi di un'altra riga con 18-1-2015-08-08.

Qualche idea su come posso mantenere la flessibilità di più righe pur essendo in grado di far rispettare che solo una riga è 'attiva' in un dato momento?

+2

fa '(foo_id = '1' e bar_id IN ('18'))' corrisponde esattamente a una fila? Se effettivamente corrisponde a più di uno, il nuovo valore 'NOW()' causerà una violazione del vincolo di chiave. Se ce ne sono più di uno, ma si desidera scegliere solo uno con 'LIMIT' (che eviterebbe la violazione dell'unicità), in base a quali altri criteri verranno ordinati? –

+0

No, potrebbe esserci un numero X di righe con foo_id = 1, bar_id = 18, l'unica differenza tra loro sarebbe valore delete_at, con solo uno dei tanti che ha cancellato_at = '0000-00-00 00:00:00 ' –

+2

@MikePurcell se hai molte righe con foo_id = 1 e bar_id = 18, la tua dichiarazione di aggiornamento chiede a tutte quelle righe di essere aggiornate con deleted_at = NOW() e quindi causa non univocità. Potresti cambiare la tua clausola where per usare 'e deleted_at = '0000-00-00 00: 00: 00''? – zedfoxus

risposta

7

Passaggio da un commento ad una risposta ...

La dichiarazione:

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

tentativi di impostare deleted_at per tutte le righe con foo_id = 1 e bar_id = 18. Poiché la combinazione foo_id, bar_id e deleted_at è contrassegnata come unica, tale modifica finisce per violare il vincolo univoco.

Solo può essere necessaria una piccola modifica alla dichiarazione in questo modo, sapendo che solo un record può avere 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'); 
Problemi correlati