2009-04-08 35 views
75

He estado buscando por un tiempo pero no puedo encontrar una solución fácil para mi problema. Me gustaría duplicar un registro en una tabla, pero, por supuesto, la clave primaria única debe actualizarse.Duplicar/Copiar registros en la misma tabla MySQL

que tienen esta consulta:

INSERT INTO invoices 
    SELECT * FROM invoices AS iv WHERE iv.ID=XXXXX 
    ON DUPLICATE KEY UPDATE ID = (SELECT MAX(ID)+1 FROM invoices) 

El problema es que esto sólo cambia el ID de la fila en lugar de copiar la fila. Sabe alguien cómo arreglar esto ?

// edit: Me gustaría hacer esto sin escribir todos los nombres de campo porque los nombres de campo pueden cambiar con el tiempo.

Respuesta

115

La forma en que suelo hacerlo es utilizar una tabla temporal. ¡Probablemente no sea computacionalmente eficiente, pero parece funcionar bien! Aquí estoy duplicando el registro 99 en su totalidad, creando el registro 100.

CREATE TEMPORARY TABLE tmp SELECT * FROM invoices WHERE id = 99; 

UPDATE tmp SET id=100 WHERE id = 99; 

INSERT INTO invoices SELECT * FROM tmp WHERE id = 100; 

Espero que funcione bien para usted!

+0

Me gusta, un paso en el medio para estar al tanto de las cosas – SeanDowney

+3

Si está copiando un solo registro, puede colocar la información tanto en la actualización como en la inserción. Luego, puede presionar dos veces en la consola mysql, lo que daría lugar a la penúltima operación en la historia, cambiar la identificación en la actualización que es conveniente al final, presionar enter, presionar hacia arriba, presionar enter nuevamente sin cambiar nada, luego repetir el procedimiento para copias múltiples. Mucho mas rápido. –

+0

muy útil gracias! – Elankeeran

11

que sepa con certeza, que la llave duplicada se disparará, lo que puede seleccionar el MAX (ID) 1 antemano:

INSERT INTO invoices SELECT MAX(ID)+1, ... other fields ... FROM invoices AS iv WHERE iv.ID=XXXXX 
+1

Sí, pero no quiero escribir todos los demás campos (hay más o menos 20, y pueden cambiar con el tiempo). No quiero cambiar el código cada vez que cambia la estructura de la tabla. – Digits

+0

Tendrás que hacerlo. Es mejor hacer una secuencia de comandos que genere la declaración SQL de una lista de campos. Es trivial. – Ingo

+0

La única otra alternativa es usar un desencadenador de inserción (si mysql lo admite). – Ingo

1

que necesitaba esto también; Mi solución fue utilizar SQLYOG (versión gratuita) para exportar el registro deseado como SQL (crea una inserción).

A continuación, edité esto para eliminar el ID, ya que debe ser generado automáticamente y luego copié el inserto en SQLYog para ejecutarlo. Esto fue indoloro Creo que muchas otras GUI de MySQL pueden hacer esto también.

Esto me proporciona un registro que puedo usar para fines de prueba en un sistema en vivo.

Ahora también tengo este inserto para reutilizar, ya que la tabla se reescribe todos los días.

75

La respuesta de Alex necesita cierto cuidado (por ejemplo, bloqueo o una transacción) en entornos de varios clientes.

Suponiendo que el campo AUTO ID es el primero en la tabla (un caso habitual), podemos hacer uso de las transacciones implícitas .

 
    CREATE TEMPORARY TABLE tmp SELECT * from invoices WHERE ...; 
    ALTER TABLE tmp drop ID; # drop autoincrement field 
    # UPDATE tmp SET ...; # just needed to change other unique keys 
    INSERT INTO invoices SELECT 0,tmp.* FROM tmp; 
    DROP TABLE tmp; 

De la documentación de MySQL:

Utilización de AUTO_INCREMENT: También puede asignar explícitamente NULL o 0 a la columna para generar números de secuencia.

+3

Esto fue realmente útil para mí, gracias. – rotanimod

+0

¡Exactamente lo que quería, gracias! – Yos

+0

Esto puso el registro con un ID de 0 para mí, aunque tengo un campo AUTO_INCREMENT.Cambiarlo a nulo funcionó, por lo que sugiero que cambie el código para usar null en lugar de 0. Estoy en MySQL 5.5.35 (Ubuntu). –

2

que tienen un problema similar, y esto es whant que estoy haciendo

insert into Preguntas (`EncuestaID`, `Tipo` , `Seccion` , `RespuestaID` , `Texto`) select '23', `Tipo`, `Seccion`, `RespuestaID`, `Texto` from Preguntas where `EncuestaID`= 18 

Preguntas sido:

CREATE TABLE IF NOT EXISTS `Preguntas` (
    `ID` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `EncuestaID` int(11) DEFAULT NULL, 
    `Tipo` char(5) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `Seccion` int(11) DEFAULT NULL, 
    `RespuestaID` bigint(11) DEFAULT NULL, 
    `Texto` text COLLATE utf8_unicode_ci , 
    PRIMARY KEY (`ID`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=522 ; 

Así, el ID se incrementa de forma automática y también estoy usando un valor fijo ('23') para 'EncuestaID

+0

lo siento, me acabo de dar cuenta de que no desea utilizar el nombre de las columnas, por lo que esto no se aplica –

10

Su enfoque es bueno, pero el problema es que utiliza "*" en lugar de alistar el nombre de los campos s.Si coloca todos los nombres de columnas excep primary key, su script funcionará como charm en uno o muchos registros.

INSERT INTO invoices (iv.field_name, iv.field_name,iv.field_name ) SELECT iv.field_name, iv.field_name,iv.field_name FROM invoices AS iv WHERE iv.ID=XXXXX

0

Una pequeña variación, siendo la diferencia principal para establecer el campo de clave principal ("code") en nulo, lo que produce una advertencia, pero funciona. Al establecer la clave primaria en nulo, el autoincremento funciona al insertar el registro en la última declaración.

Este código también limpia los intentos anteriores, y se puede ejecutar más de una vez y sin problemas:

DELETE FROM `tbl` WHERE varname="primary key value for new record"; 
DROP TABLE tmp; 
CREATE TEMPORARY TABLE tmp SELECT * FROM `tbl` WHERE varname="primary key value for old record"; 
UPDATE tmp SET varname=NULL; 
INSERT INTO `tbl` SELECT * FROM tmp; 
1

acabo quería extender gran respuesta de Alex para que sea apropiada si le toca a querer duplicar un entero conjunto de registros:

SET @x=7; 
CREATE TEMPORARY TABLE tmp SELECT * FROM invoices; 
UPDATE tmp SET [email protected]; 
INSERT INTO invoices SELECT * FROM tmp; 

simplemente que tenía que hacer esto y encontré la respuesta de Alex un punto de partida perfecto !. Por supuesto, debe establecer @x en el número de fila más alto de la tabla (estoy seguro de que podría obtenerlo con una consulta). Esto solo es útil en esta situación tan específica, así que tenga cuidado de usarlo cuando no desee duplicar todas las filas. Ajuste las matemáticas según sea necesario.

3

Una respuesta tardía Lo sé, pero sigue siendo una pregunta común, me gustaría agregar otra respuesta que funcionó para mí, con solo utilizar la declaración de línea única insert into, y creo que es sencillo, sin crear ninguna nueva tabla (ya que podría ser un problema con los permisos CREATE TEMPORARY TABLE):

INSERT INTO invoices (col_1, col_2, col_3, ... etc) 
    SELECT 
    t.col_1, 
    t.col_2, 
    t.col_3, 
    ... 
    t.updated_date, 
    FROM invoices t; 

La solución está trabajando para la columna ID AUTO_INCREMENT, de lo contrario, puede agregar la columna ID así a la declaración:

INSERT INTO invoices (ID, col_1, col_2, col_3, ... etc) 
    SELECT 
    MAX(ID)+1, 
    t.col_1, 
    t.col_2, 
    t.col_3, 
    ... etc , 
    FROM invoices t; 

es realmente sencillo y directo, puede actualizar cualquier otra cosa en una sola línea sin ninguna segunda declaración de actualización para más adelante (por ejemplo, actualizar una columna de título con texto adicional o reemplazar una cadena por otra), también puede ser específico con qué es exactamente lo que quiere duplicar, si todo es correcto, si es posible, puede hacerlo.

+1

Esta es también una buena base para modificar algunos campos durante la copia. Acabo de usar 'INSERT en wp_options SELECT NULL, 'theme_mods_twopress', option_value, autocarga FROM wp_options donde option_name = 'theme_mods_onepress';' para copiar al aumentar la entrada (truco 'AUTO_INCREMENT'' NULL' de arriba) y el campo 'option_name' también. –

+0

Sí .. Buena idea para mí. ¡¡Gracias!! –

Cuestiones relacionadas