Como copiar uma linha e inserir na mesma tabela com um campo de incremento automático no MySQL?

233

No MySQL, estou tentando copiar uma linha com um incremento automático column ID=1 e inserir os dados na mesma tabela que uma nova linha column ID=2.

Como posso fazer isso em uma única consulta?

Navdroid
fonte

Respostas:

351

Use INSERT ... SELECT:

insert into your_table (c1, c2, ...)
select c1, c2, ...
from your_table
where id = 1

Onde c1, c2, ...estão todas as colunas, exceto id. Se você deseja inserir explicitamente com um idde 2, inclua-o na lista de colunas INSERT e em SELECT:

insert into your_table (id, c1, c2, ...)
select 2, c1, c2, ...
from your_table
where id = 1

Você terá que cuidar de uma possível duplicata idde 2 no segundo caso, é claro.

mu é muito curto
fonte
1
Você poderia obter programaticamente os nomes das colunas usando o Information_SCHEMA ... Gostaria de saber se você poderia fazer isso como uma subconsulta e algumas funções de string? Hmmm ...
Ýzmir Ramirez
1
@Yzmir: Você acabaria tendo que usar SQL dinâmico e isso normalmente exigiria a criação de um procedimento armazenado. Parece mais problemas do que vale a pena quando você deve ter uma lista de nomes de colunas à mão de qualquer maneira.
mu é muito curto
6
Concordo ... da minha experiência, depois que você faz o procedimento armazenado, você não volta mais - agora está casado com esse banco de dados e apenas aumenta os custos sempre que deseja alterar.
Yzmir Ramirez
11
@YzmirRamirez, você faz parecer que o casamento é inerentemente uma coisa ruim. :)
Prof. Falken 04/04
1
Como adicionar um valor personalizado na coluna com todos os outros campos copiados?
Manish Kumar
49

Na IMO, o melhor parece usar instruções sql apenas para copiar essa linha, enquanto ao mesmo tempo faz referência apenas às colunas que você deve e deseja alterar.

CREATE TEMPORARY TABLE temp_table ENGINE=MEMORY

SELECT * FROM your_table WHERE id=1;
UPDATE temp_table SET id=NULL; /* Update other values at will. */

INSERT INTO your_table SELECT * FROM temp_table;
DROP TABLE temp_table;

Consulte também av8n.com - Como clonar um registro SQL

Benefícios:

  • As instruções SQL 2 mencionam apenas os campos que precisam ser alterados durante o processo de clonagem. Eles não conhecem ou se preocupam com outros campos. Os outros campos seguem o caminho inalterados. Isso torna as instruções SQL mais fáceis de escrever, mais fáceis de ler, mais fáceis de manter e mais extensíveis.
  • Somente instruções MySQL comuns são usadas. Nenhuma outra ferramenta ou linguagem de programação é necessária.
  • Um registro totalmente correto é inserido your_tableem uma operação atômica.
parvus
fonte
3
Parece que esse truque legal (gostei, mas não funcionou para mim) não funciona em tabelas que contêm colunas TEXT / VARCHAR. Eu tentei e obtive: (1163): O tipo de tabela usado não suporta colunas BLOB / TEXT. Isso obviamente limita muito o uso no MySQL! Pode ser que, no futuro, esses limites sejam elevados ou em outros sistemas db, isso funcione, mas, por enquanto, é realmente muito limitado.
precisa
Eu realmente gosto do uso inteligente de mesa temporária. Tão útil para tabelas com uma tonelada de colunas!
Lasma
1
Parece bom, mas quando executo a primeira consulta no MySQL, recebo Error Code: 1113. A table must have at least 1 column.
physicalattraction
3
Melhor resposta para muitas colunas. Mas SET id=NULLpode causar um erro Column 'id' cannot be null. Deve ser substituído porUPDATE temp_table SET id = (SELECT MAX(id) + 1 as id FROM your_table);
Modder
1
@ atração física, você precisa se certificar de que as duas primeiras linhas sejam uma declaração.
Samuurai 18/10
16

Diga que a mesa está user(id, user_name, user_email).

Você pode usar esta consulta:

INSERT INTO user (SELECT NULL,user_name, user_email FROM user WHERE id = 1)
Vijay
fonte
29
Você sempre deve especificar os nomes das colunas ao usar INSERT, caso contrário, obterá erros estranhos e interessantes quando o seu esquema for alterado.
mu é muito curto
2
Estranho e interessante, de fato. : D
sparkyShorts
Não funciona com sqlite. Result: near "SELECT": syntax error
kyb 22/04
10

Isso ajudou e suporta colunas BLOB / TEXT.

CREATE TEMPORARY TABLE temp_table
AS
SELECT * FROM source_table WHERE id=2;
UPDATE temp_table SET id=NULL WHERE id=2;
INSERT INTO source_table SELECT * FROM temp_table;
DROP TEMPORARY TABLE temp_table;
USE source_table;
Petr Hladík
fonte
De que maneira isso é melhor do que outras respostas aqui?
Smar 22/03
3
Eu acho que é muito bom se você tiver uma mesa com 100 campos. Exceto que pode haver uma restrição não nula no id, o que o faz falhar #
Loïc Faure-Lacroix
Código de erro: 1136. A contagem de colunas não corresponde à contagem de valores na linha 1
Oleksii Kyslytsyn
Isso é muito melhor se você tiver uma tabela com centenas de colunas.
Tyler S. Loeper
Não foi isso que Parvus disse, anos antes?
Home
7

Para uma solução rápida e limpa que não exige que você nomeie colunas, você pode usar uma instrução preparada conforme descrito aqui: https://stackoverflow.com/a/23964285/292677

Se você precisar de uma solução complexa para poder fazer isso com frequência, use este procedimento:

DELIMITER $$

CREATE PROCEDURE `duplicateRows`(_schemaName text, _tableName text, _whereClause text, _omitColumns text)
SQL SECURITY INVOKER
BEGIN
  SELECT IF(TRIM(_omitColumns) <> '', CONCAT('id', ',', TRIM(_omitColumns)), 'id') INTO @omitColumns;

  SELECT GROUP_CONCAT(COLUMN_NAME) FROM information_schema.columns 
  WHERE table_schema = _schemaName AND table_name = _tableName AND FIND_IN_SET(COLUMN_NAME,@omitColumns) = 0 ORDER BY ORDINAL_POSITION INTO @columns;

  SET @sql = CONCAT('INSERT INTO ', _tableName, '(', @columns, ')',
  'SELECT ', @columns, 
  ' FROM ', _schemaName, '.', _tableName, ' ',  _whereClause);

  PREPARE stmt1 FROM @sql;
  EXECUTE stmt1;
END

Você pode executá-lo com:

CALL duplicateRows('database', 'table', 'WHERE condition = optional', 'omit_columns_optional');

Exemplos

duplicateRows('acl', 'users', 'WHERE id = 200'); -- will duplicate the row for the user with id 200
duplicateRows('acl', 'users', 'WHERE id = 200', 'created_ts'); -- same as above but will not copy the created_ts column value    
duplicateRows('acl', 'users', 'WHERE id = 200', 'created_ts,updated_ts'); -- same as above but also omits the updated_ts column
duplicateRows('acl', 'users'); -- will duplicate all records in the table

AVISO LEGAL: Esta solução é apenas para alguém que duplicará repetidamente linhas em muitas tabelas, frequentemente. Pode ser perigoso nas mãos de um usuário não autorizado.

curmil
fonte
3

Você também pode passar '0' como o valor para o incremento automático da coluna; o valor correto será usado quando o registro for criado. Isso é muito mais fácil do que tabelas temporárias.

Fonte: Copiando linhas no MySQL (veja o segundo comentário, por TRiG, ​​para a primeira solução, por Lore)

Mark Pruce
fonte
1
Este método funciona com versões mais recentes do MySQL quando NULL não é aceitável.
err
3

Muitas ótimas respostas aqui. Abaixo está um exemplo do procedimento armazenado que escrevi para realizar esta tarefa para um aplicativo da Web que estou desenvolvendo:

-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON

-- Create Temporary Table
SELECT * INTO #tempTable FROM <YourTable> WHERE Id = Id

--To trigger the auto increment
UPDATE #tempTable SET Id = NULL 

--Update new data row in #tempTable here!

--Insert duplicate row with modified data back into your table
INSERT INTO <YourTable> SELECT * FROM #tempTable

-- Drop Temporary Table
DROP TABLE #tempTable
RBILLC
fonte
na versão atual do ID de configuração MariaDB / MySQL = null fornece # 1048 - A coluna 'id' não pode ser nula, a configuração de id = 0 funciona;
shelbypereira
2
insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;
Programador de IR
fonte
3
Como isso é melhor do que outras respostas aqui?
Smar 22/03
1
@smar imo é mais limpo para entender
Satbir Kira
2

Se você pode usar o MySQL Workbench, você pode fazer isso clicando com o botão direito do mouse na linha e selecionando 'Copiar linha' e, em seguida, clicando com o botão direito do mouse na linha vazia e selecionando 'Colar linha' e, em seguida, alterando o ID e, em seguida, clicando em 'Aplicar'.

Copie a linha:

insira a descrição da imagem aqui

Cole a linha copiada na linha em branco:

insira a descrição da imagem aqui

Mude o ID:

insira a descrição da imagem aqui

Aplique:

insira a descrição da imagem aqui

Nathan Wailes
fonte
0

Eu estava procurando o mesmo recurso, mas não uso o MySQL. Eu queria copiar TODOS os campos, exceto, é claro, a chave primária (id). Esta foi uma consulta única, que não deve ser usada em nenhum script ou código.

Encontrei o caminho com PL / SQL, mas tenho certeza de que qualquer outro IDE SQL faria. Eu fiz um básico

SELECT * 
FROM mytable 
WHERE id=42;

Em seguida, exporte-o para um arquivo SQL onde eu possa encontrar o

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (1, 2, 3, ..., 42);

Eu apenas editei e usei:

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (mysequence.nextval, 2, 3, ..., 42);
SabineA
fonte
0

Costumo usar uma variação do que mu é muito curto postado:

INSERT INTO something_log
SELECT NULL, s.*
FROM something AS s
WHERE s.id = 1;

Contanto que as tabelas tenham campos idênticos (exceto o incremento automático na tabela de log), isso funcionará bem.

Como uso procedimentos armazenados sempre que possível (para facilitar a vida de outros programadores que não estão muito familiarizados com bancos de dados), isso resolve o problema de ter que voltar e atualizar procedimentos toda vez que você adiciona um novo campo a uma tabela.

Também garante que, se você adicionar novos campos a uma tabela, eles começarão a aparecer na tabela de log imediatamente sem precisar atualizar suas consultas ao banco de dados (a menos que você tenha algumas que definam um campo explicitamente)

Aviso: Você deseja adicionar novos campos às duas tabelas ao mesmo tempo, para que a ordem dos campos permaneça a mesma ... caso contrário, você começará a receber bugs estranhos. Se você é o único que escreve interfaces de banco de dados E você é muito cuidadoso, isso funciona muito bem. Caso contrário, continue nomeando todos os seus campos.

Nota: Pensando bem, a menos que você esteja trabalhando em um projeto solo, você tem certeza de que não haverá outros trabalhando nele para listar todos os nomes de campos explicitamente e atualizar suas instruções de log conforme o esquema muda. Esse atalho provavelmente não vale a dor de cabeça a longo prazo que pode causar ... especialmente em um sistema de produção.

Corsário
fonte
0
INSERIR EM `dbMyDataBase`.`tblMyTable` 
(
    `IdAutoincrement`, 
    `Coluna2`, 
    `Coluna3`, 
    `Coluna4` 
) 

SELECT 
    NULO,  
    `Coluna2`, 
    `Coluna3`, 
    'CustomValue' AS Column4 
FROM `dbMyDataBase` .tblMyTable` 
WHERE `tblMyTable`.`Column2` = 'UniqueValueOfTheKey' 
; 
/ * mySQL 5.6 * /
Wojciech Skibiński
fonte
3
Tente adicionar uma explicação mais detalhada, ou como isso se expande nas outras respostas
Azsgy 2/02/18
-1

Despeje a linha na qual você deseja sql e use o SQL gerado, menos a coluna ID para importá-la novamente.

Claire
fonte