3

mergeステートメントを含むストアド プロシージャを作成しようとしています。mergeステートメントで変数をターゲットとして使用できるようにしたいのです@TargetTableが、テーブル変数を求められています。これは私のコードです:

CREATE PROCEDURE dbo.mergetable
(
    @TargetTable nvarchar(255)
)
AS

SET NOCOUNT ON
BEGIN
MERGE INTO  @TargetTable AS t
USING dbo.SOURCE_TABLE AS s    
        ON t.name = s.name    
    WHEN MATCHED AND (t.record != s.record) THEN
        --Row exists and data is different
        UPDATE SET t.record= s.record
    WHEN NOT MATCHED BY TARGET THEN 
        --Row exists in source but not in target
        INSERT (name, record)
        VALUES (s.name, s.record)
    WHEN NOT MATCHED BY SOURCE THEN 
        --Row exists in target but not in source
       DELETE
        OUTPUT $action as ACTION, 
    DELETED.name AS Targetname, 
DELETED.record AS Targetrecord, 
INSERTED.name AS Sourcename, 
INSERTED.record AS Sourcerecord, 

SELECT @@ROWCOUNT; 
END

@TargetTableデータの1つとして渡すことでテーブル変数を使用しようとしました@TargetTableが、一時テーブルから使用できると思いましたが、コードの書き方がわかりません

    DECLARE @temp TABLE(temp varchar(50));
    INSERT @temp VALUES(@TargetTable)

変数としてではなく、ターゲットテーブルを示す例を見ただけです。

これを行う方法はありますか?

前もって感謝します

4

3 に答える 3

2

私は最近これと同じ問題を抱えており、MERGE ステートメントの作成を自動化し、結果に対して sp_executesql を起動するストアド プロシージャを作成しました。ソース テーブルの CTE の理由は、最終的な作業ストアド プロシージャにありました。増分ロード処理用のログ テーブルにリンクしました。ソースが論理的な削除を使用していたため、ソースの削除ステートメントも削除しました。気軽に追加してください。

以下のブログ投稿と AW に対する SP へのリンクを次に示します。 動的 T-SQL を使用してマージ ステートメントを作成する

/* 
==============================================================================
Author:		    Tommy Swift
Name:           spDynamicMerge
Create date:    5/18/2015
Description:	Stored Procedure to Create MERGE Statements from Source Table
                joining back to target tables on PK columns for CRUD statement
                comparisons
Parameters:     @schemaName - Default = 'dbo' 
				@tableName to be Merged.  
				Schema required if table schema name is other than 'dbo'
Assumptions:    - The parameter table exists on both the Source and Target 
                    and PK's are the same on both DB tables.
                - PK columns will be used to determine record existence.
                - SP resides on the Target database where the filtered list
                    of columns per table occur.  This ensures that only the
                    columns used in the Target are evaluated.
==============================================================================
*/

CREATE PROCEDURE [dbo].[spDynamicMerge]
	@schemaName VARCHAR(100) = 'dbo',
	@tableName VARCHAR(8000)
AS
BEGIN TRANSACTION	
	SET NOCOUNT ON;
	BEGIN TRY
    
    DECLARE  @pkColumnsCompare VARCHAR(8000)            
            ,@nonPKColumnsTarget VARCHAR(8000)
            ,@nonPKColumnsSource VARCHAR(8000)
            ,@nonPKColumnsCompare VARCHAR(8000)
            ,@columnListingSource VARCHAR(8000)
            ,@columnListingTarget VARCHAR(8000)
            ,@sqlCommand NVARCHAR(4000)

    
    --Get list of PK columns for Insert determination
    SELECT @pkColumnsCompare = COALESCE(@pkColumnsCompare + ' AND ', '') + 'Target.' + c.name + ' = ' + 'Source.' + c.name           
	FROM sys.indexes i 
        INNER JOIN sys.index_columns ic 
            ON ic.object_id = i.object_id 
				AND i.index_id = ic.index_id 
        INNER JOIN sys.columns c
            ON ic.object_id = c.object_id
                AND ic.column_id = c.column_id  
        INNER JOIN sys.tables t
            ON t.object_id = c.object_id     
		INNER JOIN sys.schemas s
			on s.schema_id = t.schema_id 
    WHERE i.is_primary_key = 1
		AND s.name + '.' + t.name = @schemaName + '.' + @tableName

    
	--Get List of non-PK columns for Updates
    SELECT @nonPKColumnsTarget = COALESCE(@nonPKColumnsTarget + ', ', '') + 'Target.' + c.name
        ,  @nonPKColumnsSource = COALESCE(@nonPKColumnsSource + ', ', '') + 'Source.' + c.name
        ,  @nonPKColumnsCompare = COALESCE(@nonPKColumnsCompare + ', ', '') + 'Target.' + c.name + ' = ' + 'Source.' + c.name
    FROM 
    (SELECT DISTINCT c.name
    FROM sys.tables t
        INNER JOIN sys.schemas s
			on s.schema_id = t.schema_id
		LEFT JOIN sys.columns c
            ON t.object_id = c.object_id  
        LEFT JOIN sys.indexes i
            ON i.object_id = c.object_id    
        LEFT JOIN sys.index_columns ic 
            ON ic.object_id = i.object_id 
                AND ic.column_id = c.column_id  
    WHERE ic.object_id IS NULL AND
        s.name + '.' + t.name = @schemaName + '.' + @tableName         
    ) c

    
    -- Create comma delimited column listing
    SELECT @columnListingTarget = COALESCE(@columnListingTarget + ', ', '') + c.name
        , @columnListingSource = COALESCE(@columnListingSource + ', ', '') + 'Source.'+ c.name    
    FROM 
    (SELECT DISTINCT c.name
    FROM sys.tables t
		INNER JOIN sys.schemas s
			on s.schema_id = t.schema_id
        INNER JOIN sys.columns c
            ON t.object_id = c.object_id      
    WHERE s.name + '.' + t.name = @schemaName + '.' + @tableName         
    ) c

    --select @pkColumnsCompare, @nonPKColumnsTarget, @nonPKColumnsSource, @nonPKColumnsCompare, @columnListingTarget, @columnListingSource

    SELECT @sqlCommand = 
	'WITH temp AS ' + CHAR(13) + CHAR(10) + 
	'(' + CHAR(13) + CHAR(10) +
	' SELECT * FROM AdventureWorks2012.' + @schemaName + '.' + @tableName + ' WITH(NOLOCK) ' + CHAR(13) + CHAR(10) +		
	') ' + CHAR(13) + CHAR(10) +
	'MERGE DataPatternsStage.' + @schemaName + '.' + @tableName  + ' AS Target ' + CHAR(13) + CHAR(10) +
     'USING temp AS Source ' + CHAR(13) + CHAR(10) +
        'ON ' + @pkColumnsCompare + CHAR(13) + CHAR(10) +
    ' WHEN MATCHED THEN ' + CHAR(13) + CHAR(10) +
       'UPDATE SET ' + @nonPKColumnsCompare + CHAR(13) + CHAR(10) +
    ' WHEN NOT MATCHED BY TARGET ' + CHAR(13) + CHAR(10) +
    'THEN ' + CHAR(13) + CHAR(10) +
       'INSERT (' + @columnListingTarget + ') ' + CHAR(13) + CHAR(10) +
       'VALUES (' + @columnListingSource + '); '

    --select @sqlCommand
    
    EXECUTE sp_executesql @sqlCommand

	END TRY

	BEGIN CATCH
		IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;

		DECLARE @ErrorMessage NVARCHAR(4000);
		DECLARE @ErrorSeverity INT;
		DECLARE @ErrorState INT;

		SELECT 
			@ErrorMessage = ERROR_MESSAGE(),
			@ErrorSeverity = ERROR_SEVERITY(),
			@ErrorState = ERROR_STATE();

		RAISERROR (@ErrorMessage, 
				   @ErrorSeverity,
				   @ErrorState
				   );

	END CATCH;

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;

GO

于 2015-05-21T16:38:18.570 に答える
0

トミー・スウィフトの回答を改善して、異なるデータベースで同じスクリプトを使用するようにしました

楽しい

/* 
==============================================================================
Author:         Tommy Swift & Krisnamourt
Name:           spDynamicMerge
Create date:    5/18/2015
Update date:    15/11/2018
Description:    Stored Procedure to Create MERGE Statements from Source Table
                joining back to target tables on PK columns for CRUD statement
                comparisons
Parameters:     @schemaName - Default = 'dbo' 
                @sourceDb source database
                @targetDb target database
                @sourceTb sourde table
                @targetTb to be Merged
                Schema required if table schema name is other than 'dbo'
Assumptions:    - The parameter table exists on both the Source and Target 
                    and PK's are the same on both DB tables.
                - PK columns will be used to determine record existence.
                - SP resides on the Target database where the filtered list
                    of columns per table occur.  This ensures that only the
                    columns used in the Target are evaluated.
==============================================================================
*/

create PROCEDURE [dbo].[spDynamicMerge]
    @sourceDb VARCHAR(100) ,
    @targetDb VARCHAR(100) ,
    @schemaName VARCHAR(100) = 'dbo',
    @sourceTb VARCHAR(8000),
    @targetTb VARCHAR(8000)
AS
BEGIN TRANSACTION   
    SET NOCOUNT ON;
    BEGIN TRY

    DECLARE  @pkColumnsCompare VARCHAR(8000)            
            ,@nonPKColumnsTarget VARCHAR(8000)
            ,@nonPKColumnsSource VARCHAR(8000)
            ,@nonPKColumnsCompare VARCHAR(8000)
            ,@columnListingSource VARCHAR(8000)
            ,@columnListingTarget VARCHAR(8000)
            ,@sqlCommand NVARCHAR(4000)

    create table #columns (name varchar(400))

    insert into #columns
        exec ('select c.name from '+@targetDb+'.sys.indexes i 
        INNER JOIN '+@targetDb+'.sys.index_columns ic 
            ON ic.object_id = i.object_id 
                AND i.index_id = ic.index_id 
        INNER JOIN '+@targetDb+'.sys.columns c
            ON ic.object_id = c.object_id
                AND ic.column_id = c.column_id  
        INNER JOIN '+@targetDb+'.sys.tables t
            ON t.object_id = c.object_id     
        INNER JOIN '+@targetDb+'.sys.schemas s
            on s.schema_id = t.schema_id 
            WHERE i.is_primary_key = 1
            AND s.name + ''.'' + t.name = '''+@schemaName+'.'+@targetTb+'''')
    select *from #columns
    --Get list of PK columns for Insert determination
    SELECT @pkColumnsCompare = COALESCE(@pkColumnsCompare + ' AND ', '') + 'Target.' + name + ' = ' + 'Source.' + name           
    FROM #columns

    truncate table #columns
    insert into #columns
        exec ('SELECT DISTINCT c.name
    FROM '+@sourceDb+'.sys.tables t
        INNER JOIN '+@sourceDb+'.sys.schemas s
            on s.schema_id = t.schema_id
        LEFT JOIN '+@sourceDb+'.sys.columns c
            ON t.object_id = c.object_id  
        LEFT JOIN '+@sourceDb+'.sys.indexes i
            ON i.object_id = c.object_id    
        LEFT JOIN '+@sourceDb+'.sys.index_columns ic 
            ON ic.object_id = i.object_id 
                AND ic.column_id = c.column_id  
    WHERE ic.object_id IS NULL AND
        s.name + ''.'' + t.name ='''+@schemaName+'.'+@sourceTb+'''')

    --Get List of non-PK columns for Updates
    SELECT @nonPKColumnsTarget = COALESCE(@nonPKColumnsTarget + ', ', '') + 'Target.' + name
        ,  @nonPKColumnsSource = COALESCE(@nonPKColumnsSource + ', ', '') + 'Source.' + name
        ,  @nonPKColumnsCompare = COALESCE(@nonPKColumnsCompare + ', ', '') + 'Target.' + name + ' = ' + 'Source.' + name
    FROM #columns

    truncate table #columns
    insert into #columns
    exec ('SELECT DISTINCT c.name
    FROM '+@sourceDb+'.sys.tables t
        INNER JOIN '+@sourceDb+'.sys.schemas s
            on s.schema_id = t.schema_id
        INNER JOIN  '+@sourceDb+'.sys.columns c
            ON t.object_id = c.object_id      
    WHERE s.name + ''.'' + t.name ='''+@schemaName+'.'+@sourceTb+'''')


    -- Create comma delimited column listing
    SELECT @columnListingTarget = COALESCE(@columnListingTarget + ', ', '') + name
        , @columnListingSource = COALESCE(@columnListingSource + ', ', '') + 'Source.'+ name    
    FROM #columns


    --select @pkColumnsCompare, @nonPKColumnsTarget, @nonPKColumnsSource, @nonPKColumnsCompare, @columnListingTarget, @columnListingSource

    SELECT @sqlCommand = 
    'WITH temp AS ' + CHAR(13) + CHAR(10) + 
    '(' + CHAR(13) + CHAR(10) +
    ' SELECT * FROM '+@sourceDb+'.' + @schemaName + '.' + @sourceTb + ' WITH(NOLOCK) ' + CHAR(13) + CHAR(10) +      
    ') ' + CHAR(13) + CHAR(10) +
    'MERGE '+@targetDb+'.' + @schemaName + '.' + @targetTb  + ' AS Target ' + CHAR(13) + CHAR(10) +
     'USING temp AS Source ' + CHAR(13) + CHAR(10) +
        'ON ' + @pkColumnsCompare + CHAR(13) + CHAR(10) +
    ' WHEN MATCHED THEN ' + CHAR(13) + CHAR(10) +
       'UPDATE SET ' + @nonPKColumnsCompare + CHAR(13) + CHAR(10) +
    ' WHEN NOT MATCHED BY TARGET ' + CHAR(13) + CHAR(10) +
    'THEN ' + CHAR(13) + CHAR(10) +
       'INSERT (' + @columnListingTarget + ') ' + CHAR(13) + CHAR(10) +
       'VALUES (' + @columnListingSource + '); '

    --select @sqlCommand

    EXECUTE sp_executesql @sqlCommand

    drop table #columns

    END TRY

    BEGIN CATCH
        IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;

        DECLARE @ErrorMessage NVARCHAR(4000);
        DECLARE @ErrorSeverity INT;
        DECLARE @ErrorState INT;

        SELECT 
            @ErrorMessage = ERROR_MESSAGE(),
            @ErrorSeverity = ERROR_SEVERITY(),
            @ErrorState = ERROR_STATE();

        RAISERROR (@ErrorMessage, 
                   @ErrorSeverity,
                   @ErrorState
                   );

    END CATCH;

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;

GO
于 2018-11-15T17:24:57.107 に答える