Como as chaves de incremento automático são tratadas em INSERT (SELECT * FROM…)
12
Eu tenho table1e table2no MySQL. Ambos têm uma auto_incrementchave primária id.
Se os esquemas da tabela corresponderem e eu fizer o INSERT INTO table1 (SELECT * FROM table2)que acontece com relação às novas linhas inseridas em table1? Eles mantêm seus idvalores antigos e geram conflitos quando uma linha table1tem o mesmo id? Os novos valores são gerados pelo auto_increment? Depende do mecanismo de armazenamento ou do bloqueio?
Você pode inserir em uma coluna de incremento automático e especificar um valor. Isto é bom; simplesmente substitui o gerador de incremento automático.
Se você tentar inserir um valor NULL ou 0 ou DEFAULT, ou se omitir a coluna de incremento automático das colunas na sua instrução INSERT, isso ativará o gerador de incremento automático.
Então, tudo bem INSERT INTO table1 SELECT * FROM table2(a propósito, você não precisa dos parênteses). Isto significa que os valores de ID em table2serão copiados na íntegra, e table1irá não geram novos valores.
Se você desejatable1 gerar novos valores, não pode fazer SELECT *. Você usa nulo ou 0 para a coluna do ID:
Ou então, você omite a coluna da lista de colunas da instrução INSERT e da lista de seleção da instrução SELECT:
-- No id in either case:INSERTINTO table1 (col1, col2, col3)SELECT col1, col2, col3,...FROM table2;
Antes de você perguntar, não há sintaxe no SQL para "selecione *, exceto uma coluna". Você precisa especificar a lista completa dos nomes das colunas que deseja inserir.
Não existe uma opção que permita / não permita a inserção de 0 como um valor? (Em relação ao seu segundo parágrafo)
Sascha Rambeaud
1
Sim, SQL_MODE = NO_AUTO_VALUE_ON_ZERO , caso contrário, nunca poderíamos inserir um valor zero literal em uma coluna do AI. Se você usar esse modo SQL, NULL ainda funcionará para ativar o gerador de AI ou omitir a coluna também funcionará.
Bill Karwin
@ BillKarwin, em relação ao seu último parágrafo, depois de obter o sub-resultado select * from table, não há como operar esse sub-resultado para remover sua primeira coluna?
Pacerier 23/02
@ Pacerier, se bem entendi, você está perguntando se isso select *pode significar select * except for the first column. A resposta é não. select *sempre solicita todas as colunas dessa tabela. Se você deseja um subconjunto, deve especificar as colunas que deseja.
precisa
@ BillKarwin, Hmm, eu estava pensando em girar a mesa para fazer cláusulas verticais where, depois girá-la de volta, por exemplo, select*from transpose(select*from(transpose(select*from table where Id=1))where col_name<>Id)ou talvez de forma mais sucinta select*from table where Id=1 and $col<>Id, o que você acha?
Pacerier 24/02
3
O ID da seleção será o mesmo valor inserido na tabela. Isso resultará em um erro se você estiver tentando duplicar as linhas existentes.
Bill Karwin: Antes de você perguntar, não há sintaxe no SQL para "selecione *, exceto uma coluna".
Isso pode ser alcançado com alguma criatividade:
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 NOTIN('id')),'
from <table> WHERE id = <id>');
PREPARE stmt1 FROM@sql;EXECUTE stmt1;
Isso fará com que a nova linha obtenha um ID incrementado automaticamente em vez do ID da linha selecionada.
Inteligente, mas para mim, isso conta como soletrar a lista completa de nomes de colunas que você deseja inserir.
Bill Karwin
1
Bem, é o mysql soletrando automaticamente contra fazê-lo manualmente. Se você tiver tabelas com muitas colunas, isso impedirá que você perca uma ou escreva incorretamente algumas.
select * from table
, não há como operar esse sub-resultado para remover sua primeira coluna?select *
pode significarselect * except for the first column
. A resposta é não.select *
sempre solicita todas as colunas dessa tabela. Se você deseja um subconjunto, deve especificar as colunas que deseja.select*from transpose(select*from(transpose(select*from table where Id=1))where col_name<>Id)
ou talvez de forma mais sucintaselect*from table where Id=1 and $col<>Id
, o que você acha?O ID da seleção será o mesmo valor inserido na tabela. Isso resultará em um erro se você estiver tentando duplicar as linhas existentes.
Isso pode ser alcançado com alguma criatividade:
Isso fará com que a nova linha obtenha um ID incrementado automaticamente em vez do ID da linha selecionada.
fonte