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.
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).
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).
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;
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.
insert into MyTable (uniqueId, column1, column2, referencedUniqueId)
select NewGuid(), // don't know this syntax, sorry
column1,
column2,
uniqueId,
from MyTable where uniqueId = @Id
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
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
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)
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.
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;
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")
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.
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")
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
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)