Вопрос

У меня есть таблица с некоторыми постоянными данными.Теперь, когда я запрашиваю его, у меня также есть довольно сложный CTE, который вычисляет значения, необходимые для результата, и мне нужно вставить недостающие строки в постоянную таблицу.В конце концов я хочу выбрать результат, состоящий из всех строк, определенных CTE, но с данными из таблицы, если они уже были в таблице, и мне нужна информация о том, была ли строка только что вставлена ​​или нет.

Упрощенно это работает следующим образом (если вы хотите попробовать, следующий код выполняется как обычный запрос):

-- 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 пункт.

Является ли это наиболее эффективным способом завершения и возврата данных?

Или было бы более эффективное решение без MERGE, например, путем предварительного вычисления результата с помощью SELECT а затем выполните INSERT строк, которые new=0?У меня возникают трудности с интерпретацией плана запроса, поскольку он в основном сводится к «слиянию кластерного индекса», что для меня довольно расплывчато с точки зрения производительности по сравнению с отдельным SELECT с последующим INSERT вариант.И мне интересно, действительно ли SQL Server (2008 R2 с CU1) достаточно умен, чтобы увидеть, что UPDATE является бездействующим (например,писать не требуется).

Это было полезно?

Решение

Вы можете объявить фиктивную переменную и установить ее значение в предложении WHEN MATCHED.

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

Я считаю, что это должно быть дешевле, чем фактическое обновление таблицы.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top