ChatGPT解决这个技术问题 Extra ChatGPT

How do you copy a record in a SQL table but swap out the unique id of the new row?

This question comes close to what I need, but my scenario is slightly different. The source table and destination table are the same and the primary key is a uniqueidentifier (guid). When I try this:

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

I obviously get a primary key constraint violation, since I'm attempting to copy over the primary key. Actually, I don't want to copy over the primary key at all. Rather, I want to create a new one. Additionally, I would like to selectively copy over certain fields, and leave the others null. To make matters more complex, I need to take the primary key of the original record, and insert it into another field in the copy (PreviousId field).

I'm sure there is an easy solution to this, I just don't know enough TSQL to know what it is.


A
AaronSieb

Try this:


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

Any fields not specified should receive their default value (which is usually NULL when not defined).


Awesome. Worked like a charm. It was so obvious once you wrote it out. Thanks!!
This is will work if you have few columns. If you have say 20 or 30 columns, still you can use this method, but it would be daunting. Also, every-time when you add a column and wanted to copy that data too, need to add the column to this script. Best is to generate insert dynamically using sys tables.
J
Jonas

Ok, I know that it's an old issue but I post my answer anyway.

I like this solution. I only have to specify the identity column(s).

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;

The "id"-column is the identity column and that's the only column I have to specify. It's better than the other way around anyway. :-)

I use SQL Server. You may want to use "CREATE TABLE" and "UPDATE TABLE" at row 1 and 2. Hmm, I saw that I did not really give the answer that he wanted. He wanted to copy the id to another column also. But this solution is nice for making a copy with a new auto-id.

I edit my solution with the idéas from 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;

You can drop more than one column by separating them with a ",". The :id should be replaced with the id of the row you want to copy. MyDatabase, MyTable and IndexField should be replaced with your names (of course).


This is tricky, how can you be sure you are copying the correct id to the correct row during the INSERT INTO in line 3?
The id-column is an identity column (in my table) so I don't care about the value. I just want a new record holding the same values as the "old" one.
For TempTable, wouldn't it be better to use #TempTable, so it is a true temporary table?
I am using this in the following format use MyDatabase; SELECT * INTO #TempTable FROM [TABLE] WHERE [indexfield] = :id; ALTER TABLE #TempTable DROP COLUMN [indexfield]; INSERT INTO [TABLE] SELECT * FROM #TempTable; DROP TABLE #TempTable; This way I know it will be cleaned up asap without any delays from writing an intermittend file to disc.
You could also use $identity if you didn't want to hard code your identity column name
M
Matt Hinze

I'm guessing you're trying to avoid writing out all the column names. If you're using SQL Management Studio you can easily right click on the table and Script As Insert.. then you can mess around with that output to create your query.


Love this approach, this trick is simple but work like a charm.
S
Scott Bevington

Specify all fields but your ID field.

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

T
TonyT

I have the same issue where I want a single script to work with a table that has columns added periodically by other developers. Not only that, but I am supporting many different versions of our database as customers may not all be up-to-date with the current version.

I took the solution by Jonas and modified it slightly. This allows me to make a copy of the row and then change the primary key before adding it back into the original source table. This is also really handy for working with tables that do not allow NULL values in columns and you don't want to have to specify each column name in the INSERT.

This code copies the row for 'ABC' to 'XYZ'

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

Once you have finished the drop the temp table.

DROP TABLE #TempRow;

J
Jeyara

I know my answer is late to the party. But the way i solved is bit different than all the answers.

I had a situation, i need to clone a row in a table except few columns. Those few will have new values. This process should support automatically for future changes to the table. This implies, clone the record without specifying any column names.

My approach is to,

Query Sys.Columns to get the full list of columns for the table and include the names of columns to skip in where clause. Convert that in to CSV as column names. Build Select ... Insert into script based on this.


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)


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

E
Eduardo Campañó

If "key" is your PK field and it's autonumeric.

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

it will generate a new record, copying field1 and field2 from the original record


J
Jules

My table has 100 fields, and I needed a query to just work. Now I can switch out any number of fields with some basic conditional logic and not worry about its ordinal position.

Replace the below table name with your table name 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") Replace the original identity field name with your PK field name 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 Replace the table names again (both target table name and source table name); edit your where conditions SQL = "INSERT INTO TARGET-TABLE-NAME (" & columnListTARGET & ") SELECT " & columnListSOURCE & " FROM SOURCE-TABLE-NAME WHERE (FIELDNAME = FIELDVALUE)" Conn.Execute(SQL)


C
Chains

You can do like this:

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

There instead of 112 you should put a number of the maximum id in table DENI/FRIEN01P.


D
Daniel Nordh

Here is how I did it using ASP classic and couldn't quite get it to work with the answers above and I wanted to be able to copy a product in our system to a new product_id and needed it to be able to work even when we add in more columns to the 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")

I dont think you need to issue 5 separate SQL commands to complete this. And also, who do you determine in 2nd command, that product id should be 34567?
34567 is just an example. You can set it to a variable or whatever you want. If you have a better way of doing this in ASP Classic, let me know. :)
you could write a stored proc to run all these in single line. Also, usually PK used to be an auto increment value. So assigning to yourself is not a good idea.
How would you write said procedure? Please enlighten me. PK? If you mean article ID's, in our system we use article ID's based on which store we sell them in. For example our toy store all have article number starting with 30 and our sports store starts with 60. Plus we save spaces so that if we get a new colour in, for example, we can have an article ID next to the others of the same kind. As said, this was my solution that works in our system. How you set variables is not that important and most programmers would understand what works for them and their system.
PK stands for primary key. In your case its '12345'. See stackoverflow.com/questions/21561657/… for how to use stored proc in Classic ASP if you dont know how to. To do this, move all those in to one stored proc and pass your '12345' as parameter. The way you do would work but parameterized Scripts are the recommended these days.