在插入命令T-SQL之前检查

时间:2013-12-30 19:15:21

标签: sql-server stored-procedures insert sql-update

我有一个存储过程执行更新命令来刷新过去八周的数据,然后我运行一个插入来添加昨天的数据,这些数据在更新时不会出现。

但是,我觉得我的代码中应该有一些检查类型,在运行插入之前检查昨天是否已经存在,以防万一我想再次运行该程序(我认为插入会重复数据) ) - 这有意义吗?

感谢您提供的任何帮助。

戴夫

1 个答案:

答案 0 :(得分:3)

它被称为UPSERT(UPdate或inSERT)。

如果您使用的是SQL Server 2008或更高版本,则可以使用MERGE语法。有关here的更多信息:

如果您使用的是旧版本,则必须使用主键检查记录是否存在,然后执行INSERT(如果不存在)或UPDATE(如果有)确实

以下是两种方法的示例:

[注意:使用MERGE选项可能会导致竞争条件,并可能导致无法预测的情况per this article。 (感谢@Bohdan提示)。 ]

USE AdventureWorks2012;
GO

CREATE PROCEDURE dbo.InsertUnitMeasure
    @UnitMeasureCode nchar(3),
    @Name nvarchar(25)
AS 
BEGIN
    SET NOCOUNT ON;
-- Update the row if it exists.    
    UPDATE Production.UnitMeasure
    SET Name = @Name
    WHERE UnitMeasureCode = @UnitMeasureCode
-- Insert the row if the UPDATE statement failed.   
    IF (@@ROWCOUNT = 0 )
    BEGIN
        INSERT INTO Production.UnitMeasure (UnitMeasureCode, Name)
        VALUES (@UnitMeasureCode, @Name)
    END
END;
GO

-- Test the procedure and return the results.
EXEC InsertUnitMeasure @UnitMeasureCode = 'ABC', @Name = 'Test Value';
SELECT UnitMeasureCode, Name FROM Production.UnitMeasure
WHERE UnitMeasureCode = 'ABC';
GO

-- Rewrite the procedure to perform the same operations using the MERGE statement.
-- Create a temporary table to hold the updated or inserted values from the OUTPUT clause.

CREATE TABLE #MyTempTable
    (ExistingCode nchar(3),
     ExistingName nvarchar(50),
     ExistingDate datetime,
     ActionTaken nvarchar(10),
     NewCode nchar(3),
     NewName nvarchar(50),
     NewDate datetime
    );
GO

ALTER PROCEDURE dbo.InsertUnitMeasure
    @UnitMeasureCode nchar(3),
    @Name nvarchar(25)
AS 
BEGIN
    SET NOCOUNT ON;

    MERGE Production.UnitMeasure AS target
    USING (SELECT @UnitMeasureCode, @Name) AS source (UnitMeasureCode, Name)
    ON (target.UnitMeasureCode = source.UnitMeasureCode)
    WHEN MATCHED THEN 
        UPDATE SET Name = source.Name
    WHEN NOT MATCHED THEN   
        INSERT (UnitMeasureCode, Name)
        VALUES (source.UnitMeasureCode, source.Name)
        OUTPUT deleted.*, $action, inserted.* INTO #MyTempTable;
END;
GO

-- Test the procedure and return the results.
EXEC InsertUnitMeasure @UnitMeasureCode = 'ABC', @Name = 'New Test Value';
EXEC InsertUnitMeasure @UnitMeasureCode = 'XYZ', @Name = 'Test Value';
EXEC InsertUnitMeasure @UnitMeasureCode = 'ABC', @Name = 'Another Test Value';

SELECT * FROM #MyTempTable;
-- Cleanup 
DELETE FROM Production.UnitMeasure WHERE UnitMeasureCode IN ('ABC','XYZ');
DROP TABLE #MyTempTable;
GO

来源:http://msdn.microsoft.com/en-us/library/bb510625.aspx