Merge 如何在SQL Server中创建带变量的合并语句

Merge 如何在SQL Server中创建带变量的合并语句,merge,sql-server-2008-r2,table-variable,Merge,Sql Server 2008 R2,Table Variable,我试图创建一个包含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 =

我试图创建一个包含
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
作为数据之一来使用表变量,并认为可以从临时表中使用
@TargetTable
,但我不知道如何编写代码

    DECLARE @temp TABLE(temp varchar(50));
    INSERT @temp VALUES(@TargetTable)
我只看到了说明目标表的示例,但没有将其作为变量

有没有办法做到这一点


提前谢谢

谢谢你的回复。我曾尝试使用动态SQL来解决这个问题,我发现这个网站提供了在存储过程中编写动态SQL的良好教程。[1]

我尝试了这两种方法,但使用sp_executesql对我不起作用。使用sp_executesql会给我一个错误,即未声明表变量@TargetTbl

这对我很有用:

CREATE PROCEDURE [dbo].[Update_Table]
(
    @TargetTbl          NVARCHAR(100)
)
AS
SET NOCOUNT ON
DECLARE @SQLquery   NVARCHAR(4000)
SET @SQLquery = 'MERGE INTO ' + @TargetTbl + ' AS t '+
    'USING dbo.SOURCE_TABLE AS s ON t.name = s.name '+
    'WHEN MATCHED AND (t.record != s.record) '+
    'THEN UPDATE SET t.record = s.record '+
    'WHEN NOT MATCHED '+
    'THEN INSERT VALUES (s.name, s.record) '+
    'WHEN NOT MATCHED BY SOURCE THEN DELETE '+
    'OUTPUT $action as ACTION,'+ 
    'DELETED.name AS Targetname,'+ 
    'DELETED.record AS Targetrecord,'+ 
    'INSERTED.name AS Sourcename,'+ 
    'INSERTED.record AS Sourcerecord;'

IF(@@ERROR = 0)     
    EXECUTE(@SQLquery)
ELSE
GoTo ErrorHandler

Set NoCount OFF
Return(0)

ErrorHandler:
    Return(@@ERROR)

每个字符串都必须在NVARCHAR中,代码才能工作

我最近遇到了同样的问题,并编写了一个存储过程来自动创建MERGE语句,并为结果启动sp_executesql。源表上出现CTE的原因是在我的最后一个工作存储过程中,我链接到一个日志表以进行增量加载处理。我还删除了sourcedelete语句,因为我的源代码使用了软删除。请随意添加回来

下面是针对AW的博客文章和SP的链接。

/*
==============================================================================
作者:汤米·斯威夫特
名称:spDynamicMerge
创建日期:2015年5月18日
描述:从源表创建合并语句的存储过程
连接回CRUD语句PK列上的目标表
比较
参数:@schemaName-Default='dbo'
@要合并的表名。
如果表架构名称不是“dbo”,则需要架构
假设:-源和目标上都存在参数表
和PK在两个DB表上是相同的。
-PK列将用于确定记录是否存在。
-SP驻留在筛选列表所在的目标数据库上
出现每个表的列数。这确保只有
将计算目标中使用的列。
==============================================================================
*/
创建过程[dbo]。[spDynamicMerge]
@schemaName VARCHAR(100)=“dbo”,
@表名VARCHAR(8000)
作为
开始交易
不计数;
开始尝试
声明@pkColumnsCompare VARCHAR(8000)
,@nonPKColumnsTarget VARCHAR(8000)
,@nonpkcolumnsource VARCHAR(8000)
,@nonPKColumnsCompare VARCHAR(8000)
,@columnListingSource VARCHAR(8000)
,@columnListingTarget VARCHAR(8000)
,@sqlCommand-NVARCHAR(4000)
--获取用于插入确定的PK列列表
选择@pkColumnsCompare=COALESCE(@pkColumnsCompare+'和','')+'目标'.+c.name+'='+'源'.+c.name'
从sys.i
内部联接sys.index_列ic
在ic.object\u id=i.object\u id上
i.index_id=ic.index_id
内部联接系统c列
在ic.object\u id=c.object\u id上
和ic.column\u id=c.column\u id
内部联接sys.t表
在t.object\u id=c.object\u id上
内部联接sys.s
在s.schema_id=t.schema_id上
其中i.is_primary_key=1
和s.name+'.+t.name=@schemaName+'.+@tableName
--获取用于更新的非PK列的列表
选择@nonPKColumnsTarget=COALESCE(@nonPKColumnsTarget+',','')+'Target.+c.name
,@nonpkcolumnsource=COALESCE(@nonpkcolumnsource+,,,'')+'Source.+c.name
,@nonPKColumnsCompare=COALESCE(@nonPKColumnsCompare+',','')+'Target.+c.name+'='+'Source.+c.name
从…起
(选择不同的c.name
从sys.t表
内部联接sys.s
在s.schema_id=t.schema_id上
左连接sys.c列
在t.object\u id=c.object\u id上
左连接sys.i
在i.object\u id=c.object\u id上
左连接sys.index_列ic
在ic.object\u id=i.object\u id上
和ic.column\u id=c.column\u id
其中ic.object_id为NULL,且
s、 name++'.+t.name=@schemaName++'.++@tableName
)c
--创建逗号分隔的列列表
选择@columnListingTarget=COALESCE(@columnListingTarget+',','')+c.name
,@columnListingSource=COALESCE(@columnListingSource+',','')+'Source.+c.name
从…起
(选择不同的c.name
从sys.t表
内部联接sys.s
在s.schema_id=t.schema_id上
内部联接系统c列
在t.object\u id=c.object\u id上
其中s.name+'.+t.name=@schemaName+'.+@tableName
)c
--选择@pkColumnsCompare、@nonPKColumnsTarget、@nonPKColumnsSource、@nonPKColumnsCompare、@columnListingTarget、@columnListingSource
选择@sqlCommand=
'温度为'+CHAR(13)+CHAR(10)+
“(”+CHAR(13)+CHAR(10)+
'从AdventureWorks2012中选择*。++@schemaName+'。++@tableName+'带(NOLOCK)'+CHAR(13)+CHAR(10)+
“)”+CHAR(13)+CHAR(10)+
“合并DataPatternsStage.++@schemaName++.++@tableName++”作为目标“+CHAR(13)+CHAR(10)+
“使用温度作为源”+字符(13)+字符(10)+
'ON'+@pkColumnsCompare+CHAR(13)+CHAR(10)+
'匹配时,则'+CHAR(13)+CHAR(10)+
“更新集”+@nonPKColumnsCompare+CHAR(13)+CHAR(10)+
'未与目标'+CHAR(13)+CHAR(10)匹配时+
'然后'+字符(13)+字符(10)+
'插入('+
/* 
==============================================================================
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