Kir*_*rst 13 t-sql sql-server merge
我有一个目标表包含一个具有IsActive
标志的项目,我使用MERGE
语句从源表插入和更新.如果源表中存在某些内容,则它处于活动状态,如果不存在,则表示它不活动.逻辑非常简单:
IsActive
trueIsActive
trueIsActive
则应设置为false.一切都非常简单,除了目标表还有一个SourceId
与源表相关的区别列.因此对于给定的源表,我只想MERGE
对应具有相应的行SourceId
.
(我的规范化表包含来自多个系统的相同数据类型的行 - 我从这些系统中单独检索数据,因此需要一次从一个源合并)
这是一个例子:
IF OBJECT_ID('tempdb..#target') IS NOT NULL DROP TABLE #target
IF OBJECT_ID('tempdb..#source') IS NOT NULL DROP TABLE #source
CREATE TABLE #target ( Id INT, SourceId INT, IsActive BIT )
INSERT #target VALUES (1, 1, 0)
INSERT #target VALUES (2, 1, 1)
INSERT #target VALUES (3, 2, 1)
CREATE TABLE #source ( Id INT )
INSERT #source VALUES (1)
INSERT #source VALUES (4)
DECLARE @SourceId INT = 1;
SELECT * FROM #target
MERGE INTO #target t
USING
(
SELECT [Id] FROM #source
) AS s
ON t.[Id] = s.[Id] AND t.[SourceId] = @SourceId
WHEN MATCHED THEN UPDATE SET [IsActive] = 1
WHEN NOT MATCHED BY TARGET THEN INSERT VALUES ([Id], @SourceId, 1)
WHEN NOT MATCHED BY SOURCE THEN UPDATE SET [IsActive] = 0;
SELECT * FROM #target
Run Code Online (Sandbox Code Playgroud)
我最初的尝试是AND t.[SourceId] = @SourceId
在合并条件中包含,但显然这不起作用 - 它限制了要合并的项目,而不是目标表.目标行ID = 3将不匹配,因此无论是否包含该附加条件,它都将设置为非活动状态.
最终结果是,无论何时为源系统运行过程,所有其他系统都将设置为非活动状态.
我的解决方法到目前为止是运行MERGE
只MATCHED
和NOT MATCHED BY TARGET
,然后运行后续UPDATE
的不匹配的行
UPDATE #target
SET [IsEnabled] = 0
WHERE [SourceId] = @SourceId
AND [ID] NOT IN (SELECT [ID] FROM #source)
Run Code Online (Sandbox Code Playgroud)
有没有办法在MERGE
语句中包含这个过滤条件?有没有其他聪明的方法来实现这一目标?
所以你的结果集应该是
1 1 1
2 1 0
3 2 1
4 1 1
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您的合并声明应该是
merge #target as t
using #source as source
on (t.id=source.id)
when matched then update set isactive=1
when not matched by target then insert values (id, @sourceid,1)
when not matched by source and SourceID=@sourceID then update set isactive=0
Run Code Online (Sandbox Code Playgroud)
全面测试:
CREATE TABLE #target ( Id INT, SourceId INT, IsActive BIT )
INSERT #target VALUES (1, 1, 0)
INSERT #target VALUES (2, 1, 1)
INSERT #target VALUES (3, 2, 1)
CREATE TABLE #source ( Id INT )
INSERT #source VALUES (1)
INSERT #source VALUES (4)
DECLARE @SourceId INT
select @SourceId = 1;
merge #target as t
using #source as source
on (t.id=source.id)
when matched then update set isactive=1
when not matched by target then insert values (id, @sourceid,1)
when not matched by source and SourceID=@SourceID then update set isactive=0;
SELECT * FROM #target
drop table #target;
drop table #source
Run Code Online (Sandbox Code Playgroud)
结果...
Id SourceId IsActive
----------- ----------- --------
1 1 1
2 1 0
3 2 1
4 1 1
Run Code Online (Sandbox Code Playgroud)