¿Cómo copiar una fila e insertarla en la misma tabla con un campo de autoincremento en MySQL?

233

En MySQL estoy tratando de copiar una fila con un incremento automático column ID=1 e insertar los datos en la misma tabla con una nueva fila column ID=2.

¿Cómo puedo hacer esto en una sola consulta?

Navdroid
fuente

Respuestas:

351

Uso INSERT ... SELECT:

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

donde c1, c2, ...están todas las columnas excepto id. Si desea insertar explícitamente con un id2, inclúyalo en su lista de columnas INSERT y su SELECT:

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

Tendrás que ocuparte de un posible duplicado idde 2 en el segundo caso, por supuesto.

mu es demasiado corto
fuente
1
Podrías obtener programáticamente los nombres de las columnas usando INFORMATION_SCHEMA ... Me pregunto si podrías hacerlo como una subconsulta y algunas funciones de cadena. Hmmm ...
Yzmir Ramirez
1
@Yzmir: terminaría teniendo que usar SQL dinámico y eso generalmente requeriría construir un procedimiento almacenado. Parece que hay más problemas de los que vale la pena cuando debería tener una lista de nombres de columnas a mano de todos modos.
mu es demasiado corto
66
De acuerdo ... según mi experiencia, una vez que ingresa al Procedimiento almacenado, no regresa: ahora está casado con esa base de datos y solo aumenta los costos cada vez que desea cambiar.
Yzmir Ramirez
11
@YzmirRamirez, haces que parezca que el matrimonio es inherentemente algo malo. :)
Prof. Falken
1
¿Cómo agregar un valor personalizado en la columna con todos los demás campos copiados?
Manish Kumar
49

En mi opinión, lo mejor parece usar sentencias sql solo para copiar esa fila, mientras que al mismo tiempo solo hace referencia a las columnas que debe y desea cambiar.

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 también av8n.com - Cómo clonar un registro SQL

Beneficios:

  • Las declaraciones SQL 2 mencionan solo los campos que deben cambiarse durante el proceso de clonación. No conocen ni se preocupan por otros campos. Los otros campos simplemente siguen el paseo, sin cambios. Esto hace que las instrucciones SQL sean más fáciles de escribir, más fáciles de leer, más fáciles de mantener y más extensibles.
  • Solo se usan las declaraciones ordinarias de MySQL. No se requieren otras herramientas o lenguajes de programación.
  • Se inserta un registro completamente correcto your_tableen una operación atómica.
parvus
fuente
3
Parece que este buen truco (me gustó, pero no funcionó para mí) no funciona en tablas que contienen columnas TEXT / VARCHAR. Lo probé y obtuve: (1163): el tipo de tabla utilizado no admite columnas BLOB / TEXT. ¡Eso, por supuesto, limita mucho el uso en MySQL! Puede ser que en el futuro estos límites se eliminen o que en otros sistemas db funcionen, pero por ahora es realmente limitado.
Juergen el
Realmente me gusta el uso inteligente de la tabla temporal. ¡Muy útil para tablas con un montón de columnas!
Lasma
1
Se ve bien, pero cuando ejecuto la primera consulta en MySQL, obtengo Error Code: 1113. A table must have at least 1 column.
physicalattraction
3
La mejor respuesta para muchas columnas. Pero SET id=NULLpuede causar un error Column 'id' cannot be null. Debería ser reemplazado porUPDATE temp_table SET id = (SELECT MAX(id) + 1 as id FROM your_table);
Modder
1
@physicalattraction necesita asegurarse de que las dos primeras líneas son una sola declaración.
Samuurai
16

Digamos que la mesa es user(id, user_name, user_email).

Puedes usar esta consulta:

INSERT INTO user (SELECT NULL,user_name, user_email FROM user WHERE id = 1)
Vijay
fuente
29
Usted debe siempre especificar los nombres de columna cuando se utiliza INSERT, de lo contrario obtendrá errores extraños e interesantes cuando su cambios de esquema.
mu es demasiado corto
2
Extraño e interesante, de hecho. : D
sparkyShorts
No funciona con sqlite. Result: near "SELECT": syntax error
kyb
10

Esto ayudó y admite columnas 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
fuente
¿De qué manera esto es mejor que otras respuestas aquí?
Smar
3
Creo que es bastante bueno si tienes una tabla con 100 de campos. Excepto que puede haber una restricción no nula en la identificación que hace que falle
Loïc Faure-Lacroix
Código de error: 1136. El recuento de columnas no coincide con el recuento de valores en la fila 1
Oleksii Kyslytsyn
Esto es mucho mejor si tiene una tabla con cientos de columnas.
Tyler S. Loeper
¿No es esto lo que dijo Parvus, años antes?
ToolmakerSteve
7

Para una solución rápida y limpia que no requiera que nombre columnas, puede usar una declaración preparada como se describe aquí: https://stackoverflow.com/a/23964285/292677

Si necesita una solución compleja para poder hacer esto con frecuencia, puede usar este procedimiento:

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

Puedes ejecutarlo con:

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

Ejemplos

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

DESCARGO DE RESPONSABILIDAD: Esta solución es solo para alguien que repetidamente repetirá filas en muchas tablas, a menudo. Podría ser peligroso en manos de un usuario deshonesto.

curmil
fuente
3

También puede pasar '0' como valor para que la columna se incremente automáticamente, se usará el valor correcto cuando se cree el registro. Esto es mucho más fácil que las tablas temporales.

Fuente: Copiar filas en MySQL (ver el segundo comentario, por TRiG, ​​a la primera solución, por Lore)

Mark Pruce
fuente
1
Este método funciona con versiones más recientes de MySQL cuando NULL no es aceptable.
err
3

Muchas respuestas geniales aquí. A continuación se muestra una muestra del procedimiento almacenado que escribí para realizar esta tarea para una aplicación web que estoy desarrollando:

-- 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
fuente
en la versión actual de MariaDB / MySQL, la configuración id = nulo da # 1048 - La columna 'id' no puede ser nula, la configuración id = 0 funciona;
Shelbypereira
2
insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;
Programador IR.
fuente
3
¿Cómo es esto mejor que otras respuestas aquí?
Smar
1
@smar imo es más limpio de entender
Satbir Kira
2

Si puede usar MySQL Workbench, puede hacerlo haciendo clic con el botón derecho en la fila y seleccionando 'Copiar fila', y luego haciendo clic con el botón derecho en la fila vacía y seleccionando 'Pegar fila', y luego cambiando la ID, y luego haciendo clic en 'Aplicar'.

Copia la fila:

ingrese la descripción de la imagen aquí

Pegue la fila copiada en la fila en blanco:

ingrese la descripción de la imagen aquí

Cambiar la identificación:

ingrese la descripción de la imagen aquí

Aplicar:

ingrese la descripción de la imagen aquí

Nathan Wailes
fuente
0

Estaba buscando la misma función pero no uso MySQL. Quería copiar TODOS los campos excepto, por supuesto, la clave principal (id). Esta fue una consulta de una sola vez, que no se utilizará en ningún script o código.

Encontré mi camino con PL / SQL, pero estoy seguro de que cualquier otro IDE de SQL lo haría. Hice un básico

SELECT * 
FROM mytable 
WHERE id=42;

Luego expórtelo a un archivo SQL donde podría encontrar el

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

Simplemente lo edité y lo usé:

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

Tiendo a usar una variación de lo que mu es demasiado corto publicado:

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

Siempre que las tablas tengan campos idénticos (excepto el incremento automático en la tabla de registro), esto funciona bien.

Como uso procedimientos almacenados siempre que sea posible (para facilitar la vida a otros programadores que no están demasiado familiarizados con las bases de datos), esto resuelve el problema de tener que volver y actualizar los procedimientos cada vez que agrega un nuevo campo a una tabla.

También garantiza que si agrega nuevos campos a una tabla, comenzarán a aparecer en la tabla de registro inmediatamente sin tener que actualizar las consultas de su base de datos (a menos que, por supuesto, tenga algunas que establezcan un campo explícitamente)

Advertencia: querrá asegurarse de agregar nuevos campos a ambas tablas al mismo tiempo para que el orden de los campos permanezca igual ... de lo contrario, comenzará a obtener errores extraños. Si usted es el único que escribe interfaces de base de datos Y tiene mucho cuidado, entonces esto funciona bien. De lo contrario, mantén el nombre de todos tus campos.

Nota: Pensándolo bien, a menos que esté trabajando en un proyecto en solitario que esté seguro de que no habrá otros trabajando en él, adhiérase a la lista explícita de todos los nombres de campo y actualice sus declaraciones de registro a medida que cambia su esquema. Este atajo probablemente no valga el dolor de cabeza a largo plazo que puede causar ... especialmente en un sistema de producción.

Corsario
fuente
0
INSERTAR EN `dbMyDataBase`.`tblMyTable` 
(
    `IdAutoincrement`, 
    `Column2`, 
    `Column3`, 
    `Column4` 
) 

SELECCIONE 
    NULO,  
    `Column2`, 
    `Column3`, 
    'CustomValue' AS Column4 
DE `dbMyDataBase`.`tblMyTable` 
WHERE `tblMyTable``Column2` = 'UniqueValueOfTheKey' 
; 
/ * mySQL 5.6 * /
Wojciech Skibiński
fuente
3
Intente agregar una explicación más detallada, o cómo esto se expande en las otras respuestas
Azsgy
-1

Vuelque la fila que desea sql y luego use el SQL generado, menos la columna ID para importarlo nuevamente.

Claire
fuente