我想使用存储过程将我的测试数据库中的表复制到具有相同ID /身份的链接服务器,但我无法使其工作。
我已将IDENTITY_INSERT
设置为ON
,但仍然会抱怨ID列。
这是我的程序:
CREATE PROCEDURE [dbo].[TEST2PROD_CopyUIDataSServer]
AS Begin
declare @sql nvarchar(max)
-- First truncate target table
set @sql = 'EXEC [LINKEDSERVER].tempdb.sys.sp_sqlexec' + char(39)+ 'TRUNCATE Table [ProductManager].dbo.[UIData]' + char(39)+ ';'
---- SET IDENTITY_INSERT ON
set @sql = @sql + 'EXEC [LINKEDSERVER].tempdb.sys.sp_sqlexec' + char(39)+ 'SET IDENTITY_INSERT [ProductManager].[dbo].[UIData] ON' + char(39)+ ';'
---- INSERT UIDATA records from DB1 into linked server DB2
set @sql = @sql + 'WITH TestData as (SELECT * from ProductManager.dbo.UIData UID)' + NCHAR(13)+ 'INSERT INTO [LINKEDSERVER].[ProductManager].[dbo].[UIData]' + NCHAR(13) + 'select * from TestData;'
print @sql
exec (@sql)
end
但是当我执行SP时,它会给我以下错误:
链接服务器的OLE DB提供程序“SQLNCLI10”....无法INSERT INTO表“[LINKEDSERVER]。[ProductManager]。[dbo]。[UIData]”因为列“Id”。用户无权写入该列。
链接服务器属性RPC和RPC out设置为true。我希望有些男生可以帮助我吗?
更新:我决定将事情分开,首先我将数据从本地服务器复制到TEMP_TABLE
中的链接服务器,我无需处理IDENTITY
1}}问题。
然后我在链接/远程服务器上编写了一个存储过程,因为我没有使用SELECT *
但是指定了列列表。这可能会在SP中的本地服务器上运行,但我没有时间或兴趣检查它..
USE [ProductManager]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[TEST2PROD_CopyBaseTables]
AS BEGIN
DECLARE @DestTable VARCHAR(50)
DECLARE @DestPath VARCHAR(50)
DECLARE @SrceTable VARCHAR(255)
declare @sql nvarchar(max)
DECLARE @columnList varchar(max)
DECLARE @err int
Begin TRY
declare @comma_delimited_list varchar(4000)
--- FIRST TRY WITH ONE TABLE, EXTENDABLE...
set @comma_delimited_list = 'UIData'
declare @cursor cursor
set @cursor = cursor static for
select * from dbo.Split(@comma_delimited_list,',') a
declare @naam varchar(50)
open @cursor
while 1=1 begin
fetch next from @cursor into @DestTable
if @@fetch_status <> 0 break
--Create tablenames
SET @SrceTable = '[ProductManager].[dbo].TEMP_' + @DestTable
SET @DestPath = '[ProductManager].[dbo].'+ @DestTable
print @srceTable;
print @DestTable;
--Truncate target table
set @sql ='TRUNCATE TABLE '+ @DestPath + ';'
--Insert statement needs column names
set @columnList =''
SELECT @columnList = coalesce(@columnList + '[' + name + '],','') FROM sys.columns Where OBJECT_NAME(OBJECT_ID) = @DestTable
if RIGHT(RTRIM(@columnList),1) = ','
begin
SET @columnList = LEFT(@columnList, LEN(@columnList) - 1)
end
--Transfer data from source table 2 destination
set @sql = @sql + ' SET IDENTITY_INSERT ' + @DestPath + ' ON;' + ' INSERT INTO ' + @DestPath + '(' + @columnList + ') SELECT ' + @columnList + ' FROM ' + @SrceTable
print @sql;
exec (@sql)
end
-- not strictly necessary w/ cursor variables since the will go out of scope like a normal var
close @cursor
deallocate @cursor
End Try
Begin Catch
declare @ErrorMsg nvarchar(MAX);
select @ErrorMsg = ERROR_MESSAGE();
SELECT @err = @@error IF @err <> 0 Return @err
end Catch
END
答案 0 :(得分:20)
IDENTITY_INSERT
不能与链接服务器AFAIK一起使用,除非您在批处理中执行包含SET IDENTITY_INSERT
的动态SQL,或者在远程服务器上执行某些代码(例如Stored Proc)对你而言。
IDENTITY_INSERT
是每会话(请参阅MSDN),当您使用远程服务器时,这可能与您通过[LINKEDSERVER].tempdb.sys.sp_sqlexec
执行的语句处于不同的会话中,导致它当你看到它发生时失败。
答案 1 :(得分:6)
您可以在链接服务器上使用“SWITCH TO”技巧插入一个身份值标识列。< / p>
如果您没有使用“SWITCH TO”技巧来添加和删除列上的标识,那么即使在大型表格上也非常快!
从概念上讲,您只需创建一个新的SCHEMA,就像您想要INSERT
到的表一样,不需要定义的标识。然后将表格切换到该SCHEMA并执行INSERT
。然后切换回定义了标识的SCHEMA
以下示例已在AZURE的链接服务器上进行了测试。
使用“SWITCH TO”的所有注意事项(索引必须相同,删除并重新创建外键等)
要进行测试,您可以在链接的Azure SQL Server数据库上运行以下完整脚本。您需要使用[LINKED_SERVER_NAME]
和[DATABASE_NAME]
进行查找/替换,并替换为您的值。在非Azure数据库上,您可能需要在表创建中添加“ON PRIMARY”。
--Let's setup the example by creating a table with an IDENTITY column on the Linked Server
EXEC('
CREATE TABLE [DATABASE_NAME].[dbo].[Example_Table](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nchar](10) NULL
)
'
) AT [LINKED_SERVER_NAME]
--INSERT some data into the table
INSERT INTO [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table] ([Name]) VALUES ('Travis')
INSERT INTO [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table] ([Name]) VALUES ('Mike')
-- Looks good
SELECT * FROM [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table]
GO
-- Create a TABLE with an identical schema, without the identity defined
EXEC('
CREATE TABLE [DATABASE_NAME].[dbo].[Example_Table_temp](
[ID] [int] NOT NULL,
[Name] [nchar](10) NULL
)
'
) AT [LINKED_SERVER_NAME]
--Now Use the "SWITCH TO" to move the data to the new table
EXEC('
ALTER TABLE [DATABASE_NAME].[dbo].[Example_Table] SWITCH TO [DATABASE_NAME].[dbo].[Example_Table_temp]
'
) AT [LINKED_SERVER_NAME]
--Drop the old table (It should now be empty, but you may want to verify that if you are unsure here)
EXEC('
DROP TABLE [DATABASE_NAME].[dbo].[Example_Table]
'
) AT [LINKED_SERVER_NAME]
--Rename the new table back to the old table name
-- NOTE the lack of database and owner identifiers in the new name
-- NOTE the use of double single qoutes (ESCAPED single quotes)
EXEC('
EXEC sp_rename ''[DATABASE_NAME].[dbo].Example_Table_temp'',''Example_Table''
'
) AT [LINKED_SERVER_NAME]
-- Now do your IDENTITY INSERTs !!!!
INSERT INTO [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table] (ID,[Name]) VALUES (888,'Travis')
INSERT INTO [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table] (ID,[Name]) VALUES (999,'Mike')
--Verify they got put in
SELECT * FROM [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table]
--Now let's switch it back to our SCHEMA with an IDENTITY
EXEC('
CREATE TABLE [DATABASE_NAME].[dbo].[Example_Table_temp](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nchar](10) NULL
)
ALTER TABLE [DATABASE_NAME].[dbo].[Example_Table] SWITCH TO [DATABASE_NAME].[dbo].[Example_Table_temp]
DROP TABLE [DATABASE_NAME].[dbo].[Example_Table]
EXEC sp_rename ''[DATABASE_NAME].[dbo].Example_Table_temp'',''Example_Table''
'
) AT [LINKED_SERVER_NAME]
--Data is still there
SELECT * FROM [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table]
GO
-- And note you can no longer INSERT the IDENTITY
INSERT INTO [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table] (ID,[Name]) VALUES (45,'Travis')
GO
答案 2 :(得分:-1)
您需要执行动态查询示例:
exec [LINKSERVERNAME].[DATABASENAME].[SCHEMANAME].sp_executesql N'Your Query'
如果任何列设置了标识,则需要设置SET IDENTITY_INSERT TargetTable ON
并需要指定列名。示例:
SET IDENTITY_INSERT TargetTable ON;
INSERT INTO TargetTable(Col1, Col2, Col3)
SELECT Col1, Col2, Col3 FROM SourceTable;
SET IDENTITY_INSERT TargetTable OFF;