2013-08-08 7 views
15

Scenario:Definizione chiave composita con incremento automatico in MySQL

Ho una tabella che fa riferimento a due chiavi esterne, e per ogni combinazione unica di questi chiavi esterne, ha la propria colonna AUTO_INCREMENT. Ho bisogno di attuare una chiave composita che aiuterà identificare la riga univoco utilizzando combinazione di questi tre (uno chiavi esterne ed una colonna auto_increment, e un'altra colonna con valori non uniche)

Tabella:

CREATE TABLE `issue_log` (
`sr_no` INT NOT NULL AUTO_INCREMENT , 
    `app_id` INT NOT NULL , 
    `test_id` INT NOT NULL , 
    `issue_name` VARCHAR(255) NOT NULL , 
primary key (app_id, test_id,sr_no) 
); 

Naturalmente, ci deve essere qualcosa di sbagliato con la mia domanda, a causa del quale l'errore è gettato:

errore 1075: definizione della tabella non corretta; non ci può essere una sola auto colonna e deve essere definito come chiave

Quello che sto cercando di realizzare:

Ho una tabella applicativa (con APP_ID come la sua chiave primaria), ciascuna L'applicazione ha una serie di problemi da risolvere e ogni applicazione ha più test (quindi il campo test_id) Il campo sr_no deve essere incrementato per app_id e test_id univoci.

vale a dire I dati della tabella dovrebbe essere simile:

motore

enter image description here

Il database è InnoDB. Voglio raggiungere questo obiettivo con la massima semplicità possibile (ad esempio, evitare trigger/procedure se possibile), che è stato suggerito per casi simili su altre domande).

risposta

18

Non è possibile avere MySQL per farlo automaticamente per le tabelle InnoDB: è necessario utilizzare un trigger o una procedura oppure utilizzare un altro motore di database come MyISAM. L'incremento automatico può essere eseguito solo per una singola chiave primaria.

qualcosa come il seguente dovrebbe funzionare

DELIMITER $$ 

CREATE TRIGGER xxx BEFORE INSERT ON issue_log 
FOR EACH ROW BEGIN 
    SET NEW.sr_no = (
     SELECT IFNULL(MAX(sr_no), 0) + 1 
     FROM issue_log 
     WHERE app_id = NEW.app_id 
     AND test_id = NEW.test_id 
    ); 
END $$ 

DELIMITER ; 
+0

Ok, e quali cambiamenti devo fare nel mio Creare query di creazione tabella? Non posso fare sr_no una chiave primaria perché non sarà unica. E non posso renderlo Autoincrement senza renderlo chiave primaria ... –

+0

Basta togliere l'autoincremento - non può fare quello che vuoi. La chiave primaria rimane la stessa. – noz

+0

Mi dispiace di non aver lavorato con i trigger e questo codice di trigger sta eliminando "Errore di sintassi" - con nient'altro definito. Puoi pulire il codice, e una volta fatto, metti un commento qui? L'errore è: ERRORE 1064: Hai un errore nella sintassi SQL; controllare il manuale che corrisponde alla versione del server MySQL per la sintassi diritto di utilizzare in prossimità di '.sr_no = (selezionare IFNULL (selezionare max (sr_no) +1 dal issue_log dove APP_ID = new.app_id' at line 3 –

3

È possibile utilizzare una chiave composta unique per sr_no, app_id & test_id. Non è possibile utilizzare incrementale in sr_no in quanto non è univoco.

CREATE TABLE IF NOT EXISTS `issue_log` (
    `sr_no` int(11) NOT NULL, 
    `app_id` int(11) NOT NULL, 
    `test_id` int(11) NOT NULL, 
    `issue_name` varchar(255) NOT NULL, 
    UNIQUE KEY `app_id` (`app_id`,`test_id`,`sr_no`) 
) ENGINE=InnoDB ; 

ho commentata violazione di vincolo unico sql fiddle per dimostrare (rimuovere # in linea 22 dello schema e ricostruire lo schema)

6

È possibile farlo con MyISAM e motori BDB. InnoDB non supporta questo. Citazione dal Manuale di riferimento di MySQL 5.0.

Per le tabelle MyISAM e BDB è possibile specificare AUTO_INCREMENT su una colonna secondaria in un indice a più colonne. In questo caso, il valore generato per la colonna AUTO_INCREMENT viene calcolato come MAX (auto_increment_column) + 1 prefisso WHERE = prefisso dato.

http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html

+0

Solo per vostra informazione, citando le informazioni rilevanti insieme a un link è sempre preferito su Stack Overflow, le risposte possono essere cancellate solo per il riferimento alla domanda di un link. – OGHaza

3

Non capisco completamente il requisito minimo per la colonna test_id, ma se si vuole un ~ sequenza autoincrement che riavvia su ogni combinazione unica di (app_id, test_id), si può fare un INSERT ... SELECT dalla stessa tabella, in questo modo:

mysql> INSERT INTO `issue_log` (`sr_no`, `app_id`, `test_id`, `issue_name`) SELECT 
      IFNULL(MAX(`sr_no`), 0) + 1 /* next sequence number */, 
      3 /* desired app_id */, 
      1 /* desired test_id */, 
      'Name of new row' 
      FROM `issue_log` /* specify the table name as well */ 
     WHERE `app_id` = 3 AND `test_id` = 1 /* same values as in inserted columns */ 

questo presuppone una definizione di tabella con nessuna colonna AUTO_INCREMENT dichiarato. Stai essenzialmente emulando un comportamento di autoincremento con la clausola IFNULL (MAX()) + 1, ma l'emulazione manuale funziona su colonne arbitrarie, a differenza dell'incremento automatico incorporato.

nota che l'inserto ... SELEZIONARE essere una singola query assicura atomicity dell'operazione. InnoDB bloccherà il gap dell'indice appropriato e molti processi concorrenti possono eseguire questo tipo di query mentre continuano a produrre sequenze non in conflitto.

+0

Il progetto è finito. Ma speriamo che questo aiuti qualcuno che inciampa. Non sono sicuro della mia domanda allora: P –

+0

Insert-select non è necessariamente atomico. Dipende dalle impostazioni di blocco/livello di isolamento. Vedi http://stackoverflow.com/questions/21438033/making-an-insert-select-statement-atomic o http://dba.stackexchange.com/questions/73540/mysql-consistent-nonlocking-reads-vs- insert-select. – HardlyKnowEm