Come vengono gestite le chiavi auto_increment in INSERT (SELECT * FROM ...)


12

Ho table1e table2in MySQL. Entrambi hanno una auto_incrementchiave primaria id.

Se gli schemi di tabella corrispondono e io faccio INSERT INTO table1 (SELECT * FROM table2)cosa succede riguardo alle nuove righe inserite in table1? Mantengono i loro vecchi idvalori e generano conflitti quando una riga da table1ha lo stesso id? I nuovi valori sono generati da auto_increment? Dipende dal motore di archiviazione o dal blocco?

Risposte:


13

È possibile inserire in una colonna di incremento automatico e specificare un valore. Questo va bene; sostituisce semplicemente il generatore di incremento automatico.

Se si tenta di inserire un valore NULL o 0 o DEFAULT, o se si omette la colonna di incremento automatico dalle colonne nell'istruzione INSERT, questo attiva il generatore di incremento automatico.

Quindi, va bene INSERT INTO table1 SELECT * FROM table2(a proposito, non hai bisogno delle parentesi). Ciò significa che i valori ID in table2verranno copiati pari pari, e table1saranno senza generare nuovi valori.

Se vuoi table1 generare nuovi valori, non puoi farlo SELECT *. O usi null o 0 per la colonna id:

INSERT INTO table1 SELECT 0, col1, col2, col3, ... FROM table2;

Altrimenti ometti la colonna dall'elenco delle colonne dell'istruzione INSERT e dall'elenco di selezione dell'istruzione SELECT:

-- No id in either case:
INSERT INTO table1 (col1, col2, col3) SELECT col1, col2, col3, ... FROM table2;

Prima di chiedere, non c'è sintassi in SQL per "selezionare * tranne una colonna". Devi precisare l'elenco completo dei nomi delle colonne che desideri inserire.


Non esiste un'opzione che consente / non consente l'inserimento di 0 come valore? (Riguardo al tuo secondo paragrafo)
Sascha Rambeaud,

1
Sì, SQL_MODE = NO_AUTO_VALUE_ON_ZERO , altrimenti non potremmo mai inserire un valore zero letterale in una colonna AI. Se si utilizza questa modalità SQL, NULL funziona comunque per attivare il generatore AI o anche l'omissione della colonna funziona.
Bill Karwin,

@BillKarwin, Riguardo al tuo ultimo paragrafo, dopo aver ottenuto il subresult select * from table, non c'è modo di operare su questo subresult per rimuovere la sua prima colonna?
Pacerier,

@Pacerier, se ho capito bene, mi stai chiedendo se select *può significare select * except for the first column. La risposta è no. select *richiede sempre tutte le colonne da quella tabella. Se si desidera un sottoinsieme, è necessario precisare le colonne desiderate.
Bill Karwin,

@BillKarwin, Hmm, stavo pensando di ruotare il tavolo per fare clausole verticali dove, quindi ruotarlo indietro, ad esempio select*from transpose(select*from(transpose(select*from table where Id=1))where col_name<>Id)o forse in modo più succinto come select*from table where Id=1 and $col<>Id, cosa ne pensi?
Pacerier,

3

L'id dalla selezione avrà lo stesso valore inserito nella tabella. Ciò comporterà un errore se si sta tentando di duplicare le righe esistenti.

Bill Karwin: Prima di chiedere, non c'è sintassi in SQL per "selezionare * tranne una colonna".

Questo può essere ottenuto con un po 'di creatività:

SET @sql = CONCAT('INSERT INTO <table> SELECT null, 
    ', (SELECT GROUP_CONCAT(COLUMN_NAME) 
    FROM information_schema.columns 
    WHERE table_schema = '<database>' 
    AND table_name = '<table>' 
    AND column_name NOT IN ('id')), ' 
from <table> WHERE id = <id>');  

PREPARE stmt1 FROM @sql;
EXECUTE stmt1;

Ciò comporterà che la nuova riga ottenga un ID incrementato automaticamente anziché l'id dalla riga selezionata.


2
Intelligente, ma per me conta come un elenco completo dei nomi delle colonne che si desidera inserire.
Bill Karwin,

1
Beh, è ​​mysql spiegarlo automaticamente anziché farlo manualmente. Se hai tabelle con molte colonne, ti impedirà di mancarne una o di scriverne alcune erroneamente.
curmil,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.