我有一個包含一些持久數據的表。現在,當我查詢它時,我也有一個相當複雜的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
一種更有效的解決方案,例如?我很難解釋查詢計劃,因爲它基本上歸結爲「聚集索引合併」,與單獨的SELECT
和INSERT
變體相比,在性能方面相當模糊。我想知道SQL Server(帶有CU1的2008 R2)是否真的足夠聰明,可以看到UPDATE
是無操作的(例如不需要寫入)。
我與with,merge和冗餘更新具有完全相同的設置,同時也在尋找一種不會實際執行更新但仍然返回ID的解決方案。如果你找到一個解決方案,請添加=) – 2011-05-03 14:54:20
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
@DavidMårtensson,感謝您的加入。 :) – Lucero 2011-05-03 16:21:42