Вы не говорите, какая версия SQL Server.Если в SQL Server 2008 вы можете использовать MERGE
Примечание: обычно для объединения используется слияние, которое, как я изначально думал, задавался вопрос, но оно действительно без WHEN MATCHED
предложение и только с предложением WHEN NOT MATCHED
, так что работает и для этого случая.Пример использования.
CREATE TABLE #A(
[id] [int] NOT NULL PRIMARY KEY CLUSTERED,
[C] [varchar](200) NOT NULL)
MERGE #A AS target
USING (SELECT 3, 'C') AS source (id, C)
ON (target.id = source.id)
/*Uncomment for Upsert Semantics
WHEN MATCHED THEN
UPDATE SET C = source.C */
WHEN NOT MATCHED THEN
INSERT (id, C)
VALUES (source.id, source.C);
С точки зрения затрат на выполнение, при выполнении вставки они выглядят примерно одинаково ...
Ссылка на изображения плана для первого запуска
но на втором проходе, когда вставка не выполняется, ответ Мэтью выглядит дешевле.Я не уверен, есть ли способ улучшить это.
Ссылка на изображения плана для второго запуска
Тестовый сценарий
select *
into #testtable
from master.dbo.spt_values
CREATE UNIQUE CLUSTERED INDEX [ix] ON #testtable([type] ASC,[number] ASC,[name] ASC)
declare @name nvarchar(35)= 'zzz'
declare @number int = 50
declare @type nchar(3) = 'A'
declare @low int
declare @high int
declare @status int = 0;
MERGE #testtable AS target
USING (SELECT @name, @number, @type, @low, @high, @status) AS source (name, number, [type], low, high, [status])
ON (target.[type] = source.[type] AND target.[number] = source.[number] and target.[name] = source.[name] )
WHEN NOT MATCHED THEN
INSERT (name, number, [type], low, high, [status])
VALUES (source.name, source.number, source.[type], source.low, source.high, source.[status]);
set @name = 'yyy'
IF NOT EXISTS
(SELECT *
FROM #testtable
WHERE [type] = @type AND [number] = @number and name = @name)
BEGIN
INSERT INTO #testtable
(name, number, [type], low, high, [status])
VALUES (@name, @number, @type, @low, @high, @status);
END