2012-06-27 49 views
11

我有一個包含具有IsActive標誌的項目的目標表,並且我使用MERGE語句從源表插入和更新。如果源表中存在某種東西,那麼它是活動的,如果它不存在,則它不是活動的。邏輯很簡單:我可以在MERGE語句中的目標上應用WHERE子句嗎?

  • 如果它存在於源和目標的行應該有IsActive真正
  • 如果只存在於源,則新行應插入到目標,與IsActive true
  • 如果它只存在於目標中,那麼IsActive應設置爲false。

所有非常直接的,除了目標表還有一個歧視列SourceId它涉及到源表。因此,對於給定的源表,我只希望MERGE與相應的SourceId對應的行。

(我的歸一化的表包含來自多個系統的相同數據類型的行 - I從這些系統檢索數據個別地並且因此需要從一個源同時合併)

下面是一個例子:

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 

我最初的嘗試是在合併條件中包含AND t.[SourceId] = @SourceId,但顯然這不起作用 - 它限制要合併的項目,但不限制目標表格。目標行ID = 3不匹配,所以它將被設置爲無效,無論是否包含附加條件。

最終結果是,無論何時對源系統運行該過程,所有其他系統都將被設置爲非活動狀態。

我的解決方案迄今的MERGE只爲MATCHEDNOT MATCHED BY TARGET運行,然後運行的不匹配的行

UPDATE #target 
SET [IsEnabled] = 0 
WHERE [SourceId] = @SourceId 
AND [ID] NOT IN (SELECT [ID] FROM #source) 

有沒有什麼辦法,包括在MERGE聲明中過濾條件的後續UPDATE?有沒有其他聰明的方法來實現這一目標?

回答

7

所以,你的結果集應該是

1 1 1 
2 1 0  
3 2 1 
4 1 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 [email protected] then update set isactive=0 

完全測試:

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 [email protected] then update set isactive=0; 


SELECT * FROM #target 

drop table #target; 
drop table #source 

結果...

Id   SourceId IsActive 
----------- ----------- -------- 
1   1   1 
2   1   0 
3   2   1 
4   1   1 
+0

如果您嘗試這樣做,您會發現它爲該行提供了「3 2 0」。原因是當你加入't.id = source.id'時,第3行沒有't'。它與第2行一樣被對待,並被標記爲活動。 –

+1

@KirkBroadhurst它不適合我!請參閱上面的完整測試 – podiluska

+0

啊,我看到了,我太快讀了。真棒回答謝謝!我不知道我可以在那裏放置一個條件。 –

相關問題