我有两张桌子。两者都有相同的列名。为了扩展目的,我需要将数据从一个表迁移到另一个表。我写了以下查询:
INSERT INTO Table1(primaryKey,column1, column2)
SELECT *
FROM Table2
WHERE (<condition>)
导致错误:
当IDENTITY_INSERT设置为OFF时,无法在表'Table1'中为identity列插入显式值
当我谷歌时,所有人都提到使用
SET IDENTITY_INSERT [spider3].[Table1] ON
但是有一些缺点。即使此功能仅对连接有效,我们也无法将IDENTITY_INSERT
内容作为ON
用于多个表。所以我在寻找替代品。
有人可以提出替代解决方案吗?我可以在查询中使用'as'关键字来解决此问题吗?如果是这样的话?
答案 0 :(得分:0)
这些是一些插入语句,用于计算身份插入的可能性。这些可以批量运行,并将动态执行IDENTITY_INSERT
。我通常使用脚本来生成这些语句。
IF (OBJECTPROPERTY(OBJECT_ID('[Production].[ScrapReason]'), 'TableHasIdentity') = 1) SET IDENTITY_INSERT [Production].[ScrapReason] ON; INSERT INTO [AdventureWorks2014].[Production].[ScrapReason] ([ScrapReasonID], [Name], [ModifiedDate]) SELECT * FROM [AdventureWorks2014].[Production].[ScrapReason]; IF (OBJECTPROPERTY(OBJECT_ID('[Production].[ScrapReason]'), 'TableHasIdentity') = 1) SET IDENTITY_INSERT [Production].[ScrapReason] OFF;
IF (OBJECTPROPERTY(OBJECT_ID('[HumanResources].[Shift]'), 'TableHasIdentity') = 1) SET IDENTITY_INSERT [HumanResources].[Shift] ON; INSERT INTO [AdventureWorks2014].[HumanResources].[Shift] ([ShiftID], [Name], [StartTime], [EndTime], [ModifiedDate]) SELECT * FROM [AdventureWorks2014].[HumanResources].[Shift]; IF (OBJECTPROPERTY(OBJECT_ID('[HumanResources].[Shift]'), 'TableHasIdentity') = 1) SET IDENTITY_INSERT [HumanResources].[Shift] OFF;
IF (OBJECTPROPERTY(OBJECT_ID('[Production].[ProductCategory]'), 'TableHasIdentity') = 1) SET IDENTITY_INSERT [Production].[ProductCategory] ON; INSERT INTO [AdventureWorks2014].[Production].[ProductCategory] ([ProductCategoryID], [Name], [rowguid], [ModifiedDate]) SELECT * FROM [AdventureWorks2014].[Production].[ProductCategory]; IF (OBJECTPROPERTY(OBJECT_ID('[Production].[ProductCategory]'), 'TableHasIdentity') = 1) SET IDENTITY_INSERT [Production].[ProductCategory] OFF;
在这种情况下,select和insert都发生在[AdventureWorks2014]
中,显然通常不是这种情况,但我目前只有一个DB可用来演示。如果您对如何生成这些内容感兴趣,请参阅下文。
DECLARE @v_SourceDatabase NVARCHAR(250);
DECLARE @v_DestinationDatabase NVARCHAR(250);
DECLARE @t_TablesToProcess TABLE (FullTableName NVARCHAR(250),
TableName NVARCHAR(250),
TableSchema NVARCHAR(250),
ColumnList NVARCHAR(MAX));
DECLARE @v_ColumnList NVARCHAR(MAX);
DECLARE @v_TableName NVARCHAR(250);
DECLARE @v_TableSchema NVARCHAR(250);
-- -------------------------------------- --
-- Set Source & destination database here --
-- -------------------------------------- --
SET @v_SourceDatabase = N'AdventureWorks2014';
SET @v_DestinationDatabase = N'AdventureWorks2014';
-- Generate tables to process
INSERT INTO @t_TablesToProcess
SELECT CONCAT(QUOTENAME(syssch.name), '.', QUOTENAME(systab.name)) FullTableName
, systab.name
, syssch.name
, NULL
FROM sys.tables systab
INNER JOIN sys.schemas syssch
ON syssch.schema_id = systab.schema_id
WHERE type = 'U';
DECLARE TableList CURSOR FAST_FORWARD FOR
SELECT TableName, TableSchema
FROM @t_TablesToProcess;
OPEN TableList;
FETCH NEXT FROM TableList INTO @v_TableName, @v_TableSchema;
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @v_ColumnList = CONCAT(@v_ColumnList, QUOTENAME(column_name), ', ')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @v_TableName
AND TABLE_SCHEMA = @v_TableSchema
SET @v_ColumnList = LEFT(@v_ColumnList, LEN(@v_ColumnList) - 1);
UPDATE @t_TablesToProcess
SET ColumnList = @v_ColumnList
WHERE TableName = @v_TableName
AND TableSchema = @v_TableSchema;
SET @v_ColumnList = '';
FETCH NEXT FROM TableList INTO @v_TableName, @v_TableSchema;
END
CLOSE TableList;
DEALLOCATE TableList;
-- Generate insert statements
SELECT CONCAT(N'IF (OBJECTPROPERTY(OBJECT_ID(''', FullTableName, '''), ''TableHasIdentity'') = 1) SET IDENTITY_INSERT ', FullTableName, N' ON; '
, N'INSERT INTO ', QUOTENAME(@v_DestinationDatabase), '.', FullTableName
, N' (', ColumnList, N')'
, N' SELECT * FROM ', QUOTENAME(@v_SourceDatabase), N'.', FullTableName, N';'
, N' IF (OBJECTPROPERTY(OBJECT_ID(''', FullTableName, '''), ''TableHasIdentity'') = 1) SET IDENTITY_INSERT ', FullTableName, N' OFF; ')
FROM @t_TablesToProcess;
小注释:编写此脚本时不会通过任何实际测试。有些事情可以明显改善。我处理列名称构建的方式不太理想。使用XML PATH
&amp; STUFF
是更好的选择:
SELECT Chars = STUFF((
SELECT ', ' + [Char]
FROM dbo.Chars
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 2, '')
这是一个可能的方向推动。如果我找到时间,我可能会将其重新编写为更加傻瓜/通用的解决方案。
关于在不使用IDENTITY_INSERT
的情况下进行身份插入的另一种方法,我怀疑是否存在。