如何复制SQL表中的记录,但换出新行的唯一ID?


123

这个问题很接近我的需求,但是我的情况略有不同。源表和目标表是相同的,并且主键是唯一标识符(guid)。当我尝试这个:

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

由于试图复制主键,因此我显然遇到了违反主键约束的情况。实际上,我根本不想复制主键。相反,我想创建一个新的。另外,我想选择性地复制某些字段,而将其他字段保留为空。为了使事情变得更复杂,我需要使用原始记录的主键,并将其插入副本中的另一个字段(PreviousId字段)中。

我敢肯定有一个简单的解决方案,我只是对TSQL不够了解而已。

Answers:


186

试试这个:


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

未指定的任何字段都应接收其默认值(未定义时通常为NULL)。


2
太棒了 像魅力一样工作。一旦你写出来,它是如此明显。谢谢!!
Kilhoffer

1
如果您的栏数很少,则可以使用。如果您说20或30列,仍然可以使用此方法,但这将令人生畏。另外,每次添加列并且也要复制该数据时,都需要将该列添加到此脚本中。最好是使用sys表动态生成插入。
Jeyara

93

好的,我知道这是一个老问题,但是无论如何我都会发布答案。

我喜欢这个解决方案。我只需要指定标识列即可。

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;

“ id”列是身份列,这是我必须指定的唯一列。无论如何,它比其他方法要好。:-)

我使用SQL Server。您可能想要在第1行和第2行使用“ CREATE TABLE”和“ UPDATE TABLE”。嗯,我发现我并没有真正给出他想要的答案。他还想将ID复制到另一列。但是此解决方案非常适合使用新的自动ID制作副本。

我用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;

您可以使用“,”分隔多列。:id应该替换为您要复制的行的ID。MyDatabase,MyTable和IndexField应该用您的名字替换(当然)。


1
这很棘手,如何确定在第3行的INSERT INTO期间将正确的ID复制到正确的行?
Erno

id列是一个标识列(在我的表中),因此我不在乎该值。我只想要一条新记录,该记录具有与“旧”记录相同的值。
乔纳斯(Jonas)2013年

9
对于TempTable,使用它不是更好#TempTable,所以它是一个真正的临时表吗?
2014年

3
我以以下格式使用它,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;这样我就知道将尽快清除它,而不会将间歇文件写入光盘。
Tschallacka 2015年

3
$identity如果您不想对身份列名称进行硬编码,也可以使用
Factor Mystic

12

我猜您正在尝试避免写出所有列名。如果您使用的是SQL Management Studio,则可以轻松地右键单击表和“插入脚本”。然后可以将输出弄乱以创建查询。


10

指定除您的ID字段外的所有字段。

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

6

我有一个相同的问题,我希望单个脚本与具有其他开发人员定期添加的列的表一起使用。不仅如此,而且我支持我们数据库的许多不同版本,因为客户可能并非都与当前版本保持最新。

我采用了乔纳斯的解决方案,并对其进行了一些修改。这使我可以复制该行,然后更改主键,然后再将其添加回原始源表中。这对于处理不允许在列中使用NULL值并且您不需要在INSERT中指定每个列名称的表也非常方便。

此代码将“ ABC”行复制到“ XYZ”

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

完成删除操作后,将创建临时表。

DROP TABLE #TempRow;

4

我知道我的回答迟到了。但是我解决的方法与所有答案略有不同。

我有一种情况,除了几列外,我需要在表中克隆一行。那几个将具有新的价值。此过程应自动支持将来对表进行更改。这意味着克隆记录而不指定任何列名。

我的方法是

  1. 查询Sys.Columns以获取表的列的完整列表,并在where子句中包含要跳过的列的名称。
  2. 将其转换为CSV作为列名。
  3. 构建选择...根据此插入脚本。


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)


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

1

如果“ key”是您的PK字段,并且是自动数字。

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

它将生成一个新记录,并从原始记录中复制field1和field2


1

我的表有100个字段,我需要一个查询才能正常工作。现在,我可以使用一些基本的条件逻辑切换任意数量的字段,而不必担心其顺序位置。

  1. 用您的表名替换下面的表名

    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. 用您的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. 再次替换表名(目标表名和源表名);编辑您的where条件

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


0

这是我使用ASP classic进行的操作,无法完全与上面的答案一起使用,我希望能够将系统中的产品复制到新的product_id,并且即使在我们仍然需要它时也能正常工作在表格中添加更多列。

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")

我不认为您需要发出5条单独的SQL命令来完成此操作。而且,您在第二条命令中确定谁的产品ID应该是34567?
Jeyara

34567只是一个例子。您可以将其设置为变量或任何您想要的值。如果您在ASP Classic中有更好的方法,请告诉我。:)
Daniel Nordh

您可以编写一个存储的proc以单行运行所有这些程序。同样,通常PK过去是自动递增值。因此,给自己分配不是一个好主意。
Jeyara

您将如何编写上述程序?请赐教。PK?如果您指的是商品ID,则在我们的系统中,我们会根据商品销售所在的商店来使用商品ID。例如,我们的玩具店的商品编号都从30开始,体育用品店的商品开头是60。此外,我们还节省了空间,获得一种新颜色,例如,我们可以在同类商品的旁边添加商品ID。如前所述,这是我的解决方案在我们的系统中有效。变量的设置方式并不那么重要,大多数程序员都会了解什么对它们及其系统有效。
丹尼尔·诺德

PK代表主键。您的情况是“ 12345”。如果您不知道如何在Classic ASP中使用存储的proc,请参见stackoverflow.com/questions/21561657/…。为此,将所有这些移动到一个存储的proc中,并将您的“ 12345”作为参数传递。目前,建议您采用这种方式,但建议使用参数化脚本。
Jeyara
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.