web-dev-qa-db-fra.com

Comment copier une ligne et l'insérer dans la même table avec un champ auto-incrémenté dans MySQL?

J'ai une table Eg-tab. Ce que j'essaie de faire est de copier une ligne avec un identifiant de colonne auto-incrémenté = 1 et d'insérer les données dans la même table avec un identifiant de ligne et de colonne = 2.

Utiliser MySql. Comment puis-je faire cela en une seule requête? S'il vous plaît aider

203
Navdroid

Utilisez INSERT ... SELECT:

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

c1, c2, ... sont toutes les colonnes sauf id. Si vous voulez explicitement insérer avec un id sur 2, incluez-le dans votre liste de colonnes INSERT et votre SELECT:

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

Vous devrez vous occuper d'un éventuel doublon id sur 2 dans le deuxième cas bien sûr.

308
mu is too short

IMO, le mieux semble utiliser les instructions SQL uniquement pour copier cette ligne, tout en ne référençant que les colonnes que vous devez et que vous souhaitez modifier.

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;

Voir aussi av8n.com - Comment cloner un enregistrement SQL

Avantages:

  • Les instructions SQL 2 ne mentionnent que les champs à modifier lors du processus de clonage. Ils ne connaissent ni ne s'intéressent à d’autres domaines. Les autres champs suivent la promenade sans changement. Cela rend les instructions SQL plus faciles à écrire, plus faciles à lire, plus faciles à gérer et plus extensibles.
  • Seules les instructions MySQL ordinaires sont utilisées. Aucun autre outil ou langage de programmation n'est requis.
  • Un enregistrement totalement correct est inséré dans your_table en une seule opération atomique.
42
parvus

Disons que la table est user(id, user_name, user_email).

Vous pouvez utiliser cette requête:

INSERT INTO user (SELECT NULL,user_name, user_email FROM user WHERE id = 1)
14
Vijay

Cela a aidé et prend en charge les colonnes 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;
9
Petr Hladík

Pour une solution rapide et propre ne nécessitant pas de nom de colonne, vous pouvez utiliser une instruction préparée comme décrit ici: https://stackoverflow.com/a/23964285/292677

Si vous avez besoin d'une solution complexe pour pouvoir le faire souvent, vous pouvez utiliser cette procédure:

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

Vous pouvez le lancer avec:

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

Exemples

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

CLAUSE DE NON-RESPONSABILITÉ: cette solution est réservée à une personne qui dupliquera régulièrement des lignes dans de nombreuses tables. Cela pourrait être dangereux entre les mains d'un utilisateur malhonnête.

7
curmil

Beaucoup de bonnes réponses ici. Voici un exemple de la procédure stockée que j'ai écrite pour accomplir cette tâche pour une application Web que je suis en train de développer:

-- 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
2
RBILLC

Vous pouvez également indiquer "0" comme valeur d'incrémentation automatique de la colonne. La valeur correcte sera utilisée lors de la création de l'enregistrement. C'est tellement plus facile que les tables temporaires.

Source: Copier des lignes dans MySQL (voir le deuxième commentaire de TRiG sur la première solution de Lore)

2
Mark Pruce
insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;
2
IR.Programmer

J'ai tendance à utiliser une variante de ce que mu est trop court posté:

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

Tant que les tables ont des champs identiques (à l'exception de l'incrémentation automatique sur la table de journal), cela fonctionne bien.

Etant donné que j'utilise des procédures stockées chaque fois que cela est possible (pour simplifier la vie des autres programmeurs qui ne sont pas trop familiarisés avec les bases de données), cela résout le problème de devoir revenir en arrière et mettre à jour les procédures chaque fois que vous ajoutez un nouveau champ à une table.

Cela garantit également que, si vous ajoutez de nouveaux champs à une table, ils apparaîtront immédiatement dans la table de journal sans avoir à mettre à jour vos requêtes de base de données (sauf si vous en avez bien défini explicitement un champ).

Attention: Vous voudrez vous assurer d'ajouter de nouveaux champs aux deux tables en même temps afin que l'ordre des champs reste le même ... sinon, vous commencerez à avoir des bugs impairs. Si vous êtes le seul à écrire des interfaces de base de données ET que vous soyez très prudent, cela fonctionne bien. Sinon, continuez à nommer tous vos champs.

Remarque: À la réflexion, à moins que vous ne travailliez sur un projet solo dont vous êtes sûrs, aucun autre ne travaillera dessus, ne vous contenterez plus de lister explicitement tous les noms de champs et de mettre à jour vos instructions de journal à mesure que votre schéma change. Ce raccourci ne vaut probablement pas le mal de tête à long terme qu’il peut causer ... surtout sur un système de production.

0
Privateer

Videz la ligne que vous souhaitez utiliser SQL, puis utilisez le code SQL généré, moins la colonne ID dans laquelle le réimporter.

0
Claire

Je cherchais la même fonctionnalité mais je n’utilise pas MySQL. Je voulais copier TOUS les champs sauf bien sûr la clé primaire (id). Il s'agissait d'une requête unique, à ne pas utiliser dans aucun script ou code.

Je me suis débrouillé avec PL/SQL mais je suis sûr que n'importe quel autre SQL IDE ferait l'affaire. J'ai fait une base

SELECT * 
FROM mytable 
WHERE id=42;

Puis exportez-le dans un fichier SQL où je pourrais trouver le

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

Je viens de l'éditer et je l'ai utilisé:

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (mysequence.nextval, 2, 3, ..., 42);
0
SabineA
 INSERT INTO `dbMyDataBase`.`tblMyTable` 
 (
` IdAutoincrement`, 
 `Column2`, 
` Column3`, 
 `Column4` 
) 
 
 SELECT 
 NULL, 
` Column2`, 
 'Column3`, 
 'CustomValue' AS Column4 
 FROM `dbMyDataBase`.`tblMyTable` 
 WHERE` tblMyTable` .`Column2` = 'UniqueValueOfTheKey' 
; 
/* MySQL 5.6 */
0
Wojciech Skibiński