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