24

ストアド プロシージャを使用して、テスト データベースから同じ ID のリンク サーバーにテーブルをコピーしたいのですが、それを機能させることができませIDENTITY_INSERTON。 .

これが私の手順です:

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" は、列 "Id" のため、テーブル "[LINKEDSERVER].[ProductManager].[dbo].[UIData]" に挿入できませんでした。ユーザーには列への書き込み権限がありませんでした。

リンク サーバーのプロパティ RPC および RPC out は true に設定されています。誰かがここで私を助けてくれることを願っていますか?

更新:物事を引き離すことにしました。まず、問題TEMP_TABLEに対処する必要のない場所で、ローカル サーバーからリンク サーバーにデータをコピーしIDENTITYます。

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
4

3 に答える 3

26

IDENTITY_INSERTSET IDENTITY_INSERTバッチに含まれる動的SQLを実行するか、リモートサーバー上にそれを実行するコード(たとえばStored Proc)がない限り、リンクサーバーAFAIKでは機能しません。

IDENTITY_INSERTセッションごと ( MSDNを参照) であり、リモート サーバーを使用する場合、これはおそらく を介して実行されたステートメントとは別のセッション[LINKEDSERVER].tempdb.sys.sp_sqlexecにあるため、発生しているように失敗します。

于 2012-09-12T15:44:52.737 に答える
8

「SWITCH TO」トリックを使用して、リンク サーバー上のID 列を持つテーブルに ID 値を挿入できます。

「SWITCH TO」トリックを使用して列の ID を追加および削除していない場合は、大きなテーブルでも非常に高速です。

概念的には、ID を定義INSERTに、必要なテーブルとまったく同じように新しい SCHEMA を作成するだけです。次に、テーブルをその SCHEMA に切り替えて、INSERT. 次に、ID が定義された SCHEMA に戻ります。
以下のサンプルは、AZURE のリンク サーバーでテストされています。「SWITCH TO」を使用する場合のすべての注意事項が適用されます (インデックスは同じでなければならない、外部キーを削除して再作成するなど)。

テストするには、リンクされた Azure SQL Server データベースで以下の完全なスクリプトを実行できます。[LINKED_SERVER_NAME]およびで検索/置換を実行[DATABASE_NAME]し、値に置き換える必要があります。Azure 以外の DB では、テーブルの作成に "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('USE [DATABASE_NAME];
  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
于 2016-02-11T03:11:05.480 に答える