web-dev-qa-db-fra.com

Comment copier un enregistrement dans une table SQL tout en échangeant l'identifiant unique de la nouvelle ligne?

Cette question se rapproche de ce dont j'ai besoin, mais mon scénario est légèrement différent. La table source et la table de destination sont identiques et la clé primaire est un identificateur unique (guid). Quand j'essaye ceci:

insert into MyTable
    select * from MyTable where uniqueId = @Id;

J'obtiens évidemment une violation de contrainte de clé primaire, car j'essaie de copier la clé primaire. En fait, je ne veux pas du tout copier la clé primaire. Je veux plutôt en créer un nouveau. De plus, j'aimerais copier de manière sélective certains champs et laisser les autres nuls. Pour rendre les choses plus complexes, je dois prendre la clé primaire de l'enregistrement d'origine et l'insérer dans un autre champ de la copie (champ PreviousId).

Je suis sûr qu'il existe une solution simple à ce problème. Je ne connais tout simplement pas suffisamment de TSQL pour savoir ce que c'est.

110
Kilhoffer

Essaye ça:


insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;

Tous les champs non spécifiés doivent recevoir leur valeur par défaut (qui est généralement NULL si non défini).

168
AaronSieb

Ok, je sais que c'est un problème ancien, mais je poste quand même ma réponse.

J'aime cette solution. Je n'ai qu'à spécifier la ou les colonnes d'identité.

SELECT * INTO TempTable FROM MyTable_T WHERE id = 1;
ALTER TABLE TempTable DROP COLUMN id;
INSERT INTO MyTable_T SELECT * FROM TempTable;
DROP TABLE TempTable;

La colonne "id" est la colonne d'identité et c'est la seule colonne que je dois spécifier. C'est mieux que l'inverse de toute façon. :-)

J'utilise SQL Server. Vous voudrez peut-être utiliser "CREATE TABLE" et "UPDATE TABLE" aux rangées 1 et 2 . Hmm, j'ai vu que je n'avais pas vraiment donné la réponse qu'il voulait. Il voulait également copier l'identifiant dans une autre colonne. Mais cette solution est pratique pour réaliser une copie avec un nouvel identifiant automatique.

J'édite ma solution avec les idéas de Michael Dibbets.

use MyDatabase; 
SELECT * INTO #TempTable FROM [MyTable] WHERE [IndexField] = :id;
ALTER TABLE #TempTable DROP COLUMN [IndexField]; 
INSERT INTO [MyTable] SELECT * FROM #TempTable; 
DROP TABLE #TempTable;

Vous pouvez supprimer plus d'une colonne en les séparant par "," . L'identifiant: id doit être remplacé par l'id de la ligne à copier . MyDatabase, MyTable et IndexField doivent être remplacés par votre nom. (bien sûr). 

75
Jonas

Spécifiez tous les champs sauf votre champ ID.

INSERT INTO MyTable (FIELD2, FIELD3, ..., FIELD529, PreviousId)
SELECT FIELD2, NULL, ..., FIELD529, FIELD1
FROM MyTable
WHERE FIELD1 = @Id;
9
Scott Bevington

J'imagine que vous essayez d'éviter d'écrire tous les noms de colonnes. Si vous utilisez SQL Management Studio, vous pouvez facilement cliquer avec le bouton droit de la souris sur la table et sur Script en tant qu'insertion .. pour modifier votre sortie et créer votre requête.

9
Matt Hinze
insert into MyTable (uniqueId, column1, column2, referencedUniqueId)
select NewGuid(), // don't know this syntax, sorry
  column1,
  column2,
  uniqueId,
from MyTable where uniqueId = @Id
2
Jeffrey L Whitledge

Si "clé" est votre champ PK et qu'il est automatique.

insert into MyTable (field1, field2, field3, parentkey)
select field1, field2, null, key from MyTable where uniqueId = @Id

il va générer un nouvel enregistrement, en copiant les champs1 et champ2 à partir de l'enregistrement d'origine

1
Eduardo Campañó

Je sais que ma réponse est tardive à la fête. Mais la façon dont j'ai résolu est un peu différente de toutes les réponses.

J'ai eu une situation, je dois cloner une ligne dans un tableau, sauf quelques colonnes. Ces quelques-uns auront de nouvelles valeurs. Ce processus devrait prendre en charge automatiquement les modifications futures de la table. Cela implique de cloner l'enregistrement sans spécifier de nom de colonne. 

Mon approche est de

  1. Interrogez Sys.Columns pour obtenir la liste complète des colonnes de la table et inclure les noms Des colonnes à ignorer dans la clause where.
  2. Convertissez cela en CSV en tant que noms de colonnes. 
  3. Build Select ... Insérer dans le script basé sur cela.


declare @columnsToCopyValues varchar(max), @query varchar(max)
SET @columnsToCopyValues = ''

--Get all the columns execpt Identity columns and Other columns to be excluded. Say IndentityColumn, Column1, Column2 Select @columnsToCopyValues = @columnsToCopyValues + [name] + ', ' from sys.columns c where c.object_id = OBJECT_ID('YourTableName') and name not in ('IndentityColumn','Column1','Column2') Select @columnsToCopyValues = SUBSTRING(@columnsToCopyValues, 0, LEN(@columnsToCopyValues)) print @columnsToCopyValues

Select @query = CONCAT('insert into YourTableName (',@columnsToCopyValues,', Column1, Column2) select ', @columnsToCopyValues, ',''Value1'',''Value2'',', ' from YourTableName where IndentityColumn =''' , @searchVariable,'''')

print @query exec (@query)

0
Jeyara

Vous pouvez faire comme ça: 

INSERT INTO DENI/FRIEN01P 
SELECT 
   RCRDID+112,
   PROFESION,
   NAME,
   SURNAME,
   AGE, 
   RCRDTYP, 
   RCRDLCU, 
   RCRDLCT, 
   RCRDLCD 
FROM 
   FRIEN01P      

Là, au lieu de 112, vous devriez mettre un numéro d'identifiant maximum dans la table DENI/FRIEN01P.

0
Denis Kutlubaev

J'ai le même problème lorsque je souhaite qu'un seul script fonctionne avec une table comportant des colonnes ajoutées périodiquement par d'autres développeurs. Non seulement cela, mais je supporte de nombreuses versions différentes de notre base de données car les clients peuvent ne pas être tous à jour avec la version actuelle.

J'ai pris la solution de Jonas et l'ai légèrement modifiée. Cela me permet de faire une copie de la ligne, puis de modifier la clé primaire avant de l'ajouter à la table source d'origine. Ceci est également très pratique pour travailler avec des tables qui n'autorisent pas les valeurs NULL dans les colonnes et vous ne souhaitez pas avoir à spécifier chaque nom de colonne dans l'INSERT.

Ce code copie la ligne de 'ABC' dans 'XYZ'

SELECT * INTO #TempRow FROM SourceTable WHERE KeyColumn = 'ABC';
UPDATE #TempRow SET KeyColumn = 'XYZ';
INSERT INTO SourceTable SELECT * FROM #TempRow;
DELETE #TempRow;

Une fois que vous avez terminé, déposez la table temporaire.

DROP TABLE #TempRow;
0
TonyT

Voici comment je l'ai fait avec ASP classic et je ne pouvais pas le faire fonctionner avec les réponses ci-dessus et je voulais pouvoir copier un produit de notre système vers un nouveau product_id et en avoir besoin fonctionne même lorsque nous ajoutons plus de colonnes à la table.

Cn.Execute("CREATE TEMPORARY TABLE temprow AS SELECT * FROM product WHERE product_id = '12345'")
Cn.Execute("UPDATE temprow SET product_id = '34567'")
Cn.Execute("INSERT INTO product SELECT * FROM temprow")
Cn.Execute("DELETE temprow")
Cn.Execute("DROP TABLE temprow")
0
Daniel Nordh

Ma table contient 100 champs et j'avais besoin d'une requête pour fonctionner. Maintenant, je peux échanger n'importe quel nombre de champs avec une logique conditionnelle de base sans me soucier de sa position ordinale. 

  1. Remplacez le nom de table ci-dessous par votre nom de table

    SQLcolums = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE (TABLE_NAME = 'TABLE-NAME')"
    
    Set GetColumns = Conn.Execute(SQLcolums)
    Do WHILE not GetColumns.eof
    
    colName = GetColumns("COLUMN_NAME")
    
  2. Remplacez le nom du champ d'identité d'origine par votre nom de champ PK

    IF colName = "ORIGINAL-IDENTITY-FIELD-NAME" THEN ' ASSUMING THAT YOUR PRIMARY KEY IS THE FIRST FIELD DONT WORRY ABOUT COMMAS AND SPACES
        columnListSOURCE = colName 
        columnListTARGET = "[PreviousId field name]"
    ELSE
        columnListSOURCE = columnListSOURCE & colName
        columnListTARGET = columnListTARGET & colName
    END IF
    
    GetColumns.movenext
    
    loop
    
    GetColumns.close    
    
  3. Remplacez à nouveau les noms de table (nom de la table cible et nom de la table source); modifier vos conditions where

    SQL = "INSERT INTO TARGET-TABLE-NAME (" & columnListTARGET & ") SELECT " & columnListSOURCE & " FROM SOURCE-TABLE-NAME WHERE (FIELDNAME = FIELDVALUE)" 
    Conn.Execute(SQL)
    
0
Rit Man