【问题标题】:Check before Insert Command T-SQL [closed]在插入命令 T-SQL 之前检查 [关闭]
【发布时间】:2013-12-30 19:15:20
【问题描述】:

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

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

感谢您提供的任何帮助。

戴夫

【问题讨论】:

  • 是的。在某些情况下,在创建重复数据之前检查数据是否已经存在是有意义的。
  • 除了这是否有意义之外,还有更深层次的问题吗?你在担心什么吗?
  • 是的,如果您认为数据的完整性会受到损害,那么您应该检查
  • 在我看来,如果你能发布表格和源代码会更好。

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


【解决方案1】:

它被称为UPSERT(更新或插入)。

如果您使用的是 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

【讨论】:

  • +1:我认为称其为 UPSERT 令人困惑,因为这充其量只是技术术语(尽管我从未听说过使用它)。我认为MERGE 是正确和最好的答案。
  • 我没有想到UPSERT。这是 INSERT 或 UPDATE 操作的行业术语。甚至微软和其他软件供应商也这样称呼这种操作。 blogs.msdn.com/b/windowsazurestorage/archive/2011/09/15/…
  • 另外,MERGE isn't safe
  • 谢谢@BogdanSahlean 我更新了我的答案以警告 OP 后果。
  • 这还能回答问题吗?不清楚问了什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-10
  • 2016-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多