127 votes

Dans MySQL, puis-je copier une ligne à insérer dans le même tableau?

insert into table select * from table where primarykey=1

Je veux juste copier une ligne à insérer dans le même tableau (c'est à dire, je veux dupliquer une ligne existante dans la table), mais je veux le faire sans avoir à la liste de toutes les colonnes après le "select", parce que ce tableau a trop de colonnes.

Mais quand je fais cela, j'obtiens l'erreur:

Duplicate entry 'xxx' for key 1

Je peux gérer cela par la création d'une autre table avec les mêmes colonnes, à titre temporaire, un conteneur pour l'enregistrement je veux copier:

create table oldtable_temp like oldtable;
insert into oldtable_temp select * from oldtable where key=1;
update oldtable_tem set key=2;
insert into oldtable select * from oldtable where key=2;

Est-il un moyen plus simple de résoudre ce problème?

163voto

Grim... Points 5973

J'ai utilisé Leonard Challis technique avec quelques modifications:

CREATE TEMPORARY TABLE tmptable_1 SELECT * FROM table WHERE primarykey = 1;
UPDATE tmptable_1 SET primarykey = NULL;
INSERT INTO table SELECT * FROM tmptable_1;
DROP TEMPORARY TABLE IF EXISTS tmptable_1;

Comme une table temporaire, il ne devrait jamais y avoir plus d'un enregistrement, de sorte que vous n'avez pas à vous soucier de la clé primaire. Le paramètre null MySQL permet de choisir la valeur elle-même, donc il n'y a aucun risque de créer un doublon.

Si vous voulez être super assurer que vous obtenez seulement une ligne à insérer, vous pouvez ajouter 1 à la fin de la plaquette EN ligne.

Notez que j'ai aussi ajouté de la valeur de la clé primaire (1 dans ce cas) à mon nom de la table temporaire.

56voto

LeonardChallis Points 3747

Mise à jour 07/07/2014 - La réponse repose sur de ma réponse, par Grim..., est une meilleure solution, car cela améliore ma solution ci-dessous, je vous suggère d'utiliser.

Vous pouvez le faire sans faire une liste de toutes les colonnes avec la syntaxe suivante:

CREATE TEMPORARY TABLE tmptable SELECT * FROM table WHERE primarykey = 1;
UPDATE tmptable SET primarykey = 2 WHERE primarykey = 1;
INSERT INTO table SELECT * FROM tmptable WHERE primarykey = 2;

Vous pouvez décider de modifier la clé primaire d'une autre manière.

35voto

Jordan Points 26741

Je suis en supposant que vous voulez que l'enregistrement d'un nouveau primarykey? Si primarykey est AUTO_INCREMENT puis il suffit de faire ceci:

INSERT INTO table (col1, col2, col3, ...)
SELECT col1, col2, col3, ... FROM table
  WHERE primarykey = 1

...où est - col1, col2, col3, ... est de toutes les colonnes dans le tableau , sauf pour primarykey.

Si ce n'est pas un AUTO_INCREMENT colonne et vous voulez être en mesure de choisir la nouvelle valeur de primarykey c'est la même chose:

INSERT INTO table (primarykey, col2, col3, ...)
SELECT 567, col2, col3, ... FROM table
  WHERE primarykey = 1

...où est - 567 est la nouvelle valeur de primarykey.

7voto

Vous pouvez également essayer de dumping de la table, la conclusion de la commande d'insertion et édition:

mysqldump -umyuser -p mydatabase --skip-extended-insert mytable > outfile.sql

L' --skip-extended-insert vous donne un insert de commande par ligne. Vous pouvez ensuite trouver la ligne dans votre éditeur de texte favori, extrait de la commande et de modifier la clé primaire de "par défaut".

5voto

Piotr Kaczmarek Points 21

Cette procédure suppose que:

  • vous n'avez pas _duplicate_temp_table
  • votre clé primaire est de type int
  • vous avez accès à créer une table

Bien sûr, ce n'est pas parfait, mais dans certains (probablement la majorité) des cas, il fonctionne.

DELIMITER $$
CREATE PROCEDURE DUPLICATE_ROW(copytable VARCHAR(255), primarykey VARCHAR(255), copyid INT, out newid INT)
BEGIN
        DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @error=1;
        SET @temptable = '_duplicate_temp_table';
        SET @sql_text = CONCAT('CREATE TABLE ', @temptable, ' LIKE ', copytable);
        PREPARE stmt FROM @sql_text;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SET @sql_text = CONCAT('INSERT INTO ', @temptable, ' SELECT * FROM ', copytable, ' where ', primarykey,'=', copyid);
        PREPARE stmt FROM @sql_text;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SET @sql_text = CONCAT('SELECT max(', primarykey, ')+1 FROM ', copytable, ' INTO @newid');
        PREPARE stmt FROM @sql_text;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SET @sql_text = CONCAT('UPDATE ', @temptable, ' SET ', primarykey, '=@newid');
        PREPARE stmt FROM @sql_text;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SET @sql_text = CONCAT('INSERT INTO ', copytable, ' SELECT * FROM ', @temptable, '');
        PREPARE stmt FROM @sql_text;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SET @sql_text = CONCAT('DROP TABLE ', @temptable);
        PREPARE stmt FROM @sql_text;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SELECT @newid INTO newid;
END $$
DELIMITER ;

CALL DUPLICATE_ROW('table', 'primarykey', 1, @duplicate_id);
SELECT @duplicate_id;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by: