2011-03-15 151 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