2011-03-15 65 views
16

我有一個包含一些持久數據的表。現在,當我查詢它時,我也有一個相當複雜的CTE,它計算結果所需的值,並且我需要將缺少的行插入到持久表中。最後,我希望選擇由CTE標識的所有行組成的結果,但如果它們已經在表中,則使用表中的數據,並且我需要這些行是否已插入的信息。SQL MERGE語句中的UPDATE-no-op

簡化了這一工作原理是這樣(下面的代碼運行作爲一個正常的查詢,如果你想嘗試一下):

-- Set-up of test data, this would be the persisted table 
DECLARE @target TABLE (id int NOT NULL PRIMARY KEY) ; 
INSERT INTO @target (id) SELECT v.id FROM (VALUES (1), (2)) v(id); 

-- START OF THE CODE IN QUESTION 
-- The result table variable (will be several columns in the end) 
DECLARE @result TABLE (id int NOT NULL, new bit NOT NULL) ; 

WITH Source AS (
    -- Imagine a fairly expensive, recursive CTE here 
    SELECT * FROM (VALUES (1), (3)) AS Source (id) 
) 
MERGE INTO @target AS Target 
    USING Source 
    ON Target.id = Source.id 
    -- Perform a no-op on the match to get the output record 
    WHEN MATCHED THEN 
     UPDATE SET Target.id=Target.id 
    WHEN NOT MATCHED BY TARGET THEN 
     INSERT (id) VALUES (SOURCE.id) 
    -- select the data to be returned - will be more columns 
    OUTPUT source.id, CASE WHEN $action='INSERT' THEN CONVERT(bit, 1) ELSE CONVERT(bit, 0) END 
     INTO @result ; 

-- Select the result 
SELECT * FROM @result; 

我不喜歡WHEN MATCHED THEN UPDATE部分,我寧願離開冗餘更新但我沒有得到OUTPUT條款中的結果行。

這是完成和返回數據的最有效方式嗎?

或者會有通過預先計算與SELECT,然後將結果進行其是new=0行的INSERT而不MERGE一種更有效的解決方案,例如?我很難解釋查詢計劃,因爲它基本上歸結爲「聚集索引合併」,與單獨的SELECTINSERT變體相比,在性能方面相當模糊。我想知道SQL Server(帶有CU1的2008 R2)是否真的足夠聰明,可以看到UPDATE是無操作的(例如不需要寫入)。

+1

我與with,merge和冗餘更新具有完全相同的設置,同時也在尋找一種不會實際執行更新但仍然返回ID的解決方案。如果你找到一個解決方案,請添加=) – 2011-05-03 14:54:20

+0

RE:非更新更新你可能會更好的做一個沒有OP更新的列不屬於集羣的關鍵(如果可能的話),這裏描述http: //sqlblog.com/blogs/paul_white/archive/2010/08/11/the_2D00_impact_2D00_of_2D00_update_2D00_statements_2D00_that_2D00_don_2D00_t_2D00_change_2D00_data.aspx – 2011-05-03 15:00:06

+0

@DavidMårtensson,感謝您的加入。 :) – Lucero 2011-05-03 16:21:42

回答

23

您可以聲明一個虛擬變量並在WHEN MATCHED子句中設置其值。

DECLARE @dummy int; 
... 
MERGE 
... 
WHEN MATCHED THEN 
    UPDATE SET @dummy = 0 
... 

我相信它應該比實際的表更新更便宜。

+0

這是一個絕妙的主意,它似乎運作良好。我會接受這個答案作爲答案,除非有人想出更好的東西......似乎需要大約三分之一的時間離開MERGE。 – Lucero 2011-05-04 14:15:40

+0

這個解決方案至少解決了我的問題,非常值得100代表獎金=)感謝Andriy和Lucero提供的答案以及帶有示例的好問題。 – 2011-05-05 06:43:12

+0

@大衛,謝謝!這確實是一個很好的問題。像這樣的事情往往值得提前知道,而不是等到有真正需要必要知識的問題時再等。 – 2011-05-05 12:11:29