【问题标题】:SQL if not exists insert else update [duplicate]SQL如果不存在则插入否则更新[重复]
【发布时间】:2014-05-30 12:45:03
【问题描述】:

我有一个在下面工作的存储过程:

--Stored procedure to update data in Data_Archive.dbo.company
CREATE PROC dbo.TransferCompanyInfo
as
BEGIN TRAN
INSERT INTO Data_Archive.dbo.Company
Select 
CompanyID,
CompanyName,
Address1,
Address2,
Address3,
Address4,
ZipCode,
FROM OLD.dbo.company 
where not exists (select Data_Archive.dbo.Company.CompanyID from                   Data_Archive.dbo.Company
WHERE CompanyID = OLD.dbo.Company.CompanyID)

Update Data_Archive.dbo.Company
Set 
Data_Archive.dbo.Company.CompanyID = b.CompanyID,
Data_Archive.dbo.Company.CompanyName = b.CompanyName,
Data_Archive.dbo.Company.Address1 = b.Address1,
Data_Archive.dbo.Company.Address2 = b.Address2,
Data_Archive.dbo.Company.Address3 = b.Address3,
Data_Archive.dbo.Company.Address4 = b.Address4,
Data_Archive.dbo.Company.ZipCode = b.ZipCode,
From Data_Archive.dbo.Company a, OLD.dbo.Company b
Where a.CompanyID = b.CompanyID


IF @@ERROR <> 0
            BEGIN
                ROLLBACK TRAN
                RAISERROR ('Error occured while copying data to TachographData_Archive.dbo.company', 16, 1)
                RETURN -1
           END

 IF @@TRANCOUNT > 0
     BEGIN
           COMMIT TRAN
           RETURN 0
     END

但是我想知道如何使它更快,因为目前它必须扫描表以查看是否不存在,然后插入,然后再次扫描并更新。我在想如果我这样做 if exists update else insert 它会使它更快,但我不知道如何重新格式化它。目前我尝试了下面的代码但不起作用:

--更新Data_Archive.dbo.company中数据的存储过程

 CREATE PROC dbo.TransferCompanyInfo
    as
    BEGIN TRAN
    Update Data_Archive.dbo.Company
    Set 
    Data_Archive.dbo.Company.CompanyID = b.CompanyID,
    Data_Archive.dbo.Company.CompanyName = b.CompanyName,
    Data_Archive.dbo.Company.Address1 = b.Address1,
    Data_Archive.dbo.Company.Address2 = b.Address2,
    Data_Archive.dbo.Company.Address3 = b.Address3,
    Data_Archive.dbo.Company.Address4 = b.Address4,
    Data_Archive.dbo.Company.ZipCode = b.ZipCode,
    From Data_Archive.dbo.Company a, OLD.dbo.Company b
    Where a.CompanyID = b.CompanyID

    ELSE
    INSERT INTO Data_Archive.dbo.Company
    Select 
    CompanyID,
    CompanyName,
    Address1,
    Address2,
    Address3,
    Address4,
    ZipCode,
    FROM OLD.dbo.company 
    where not exists (select Data_Archive.dbo.Company.CompanyID from                   Data_Archive.dbo.Company
    WHERE CompanyID = OLD.dbo.Company.CompanyID)



    IF @@ERROR <> 0
                BEGIN
                    ROLLBACK TRAN
                    RAISERROR ('Error occured while copying data to TachographData_Archive.dbo.company', 16, 1)
                    RETURN -1
               END

     IF @@TRANCOUNT > 0
         BEGIN
               COMMIT TRAN
               RETURN 0
         END

【问题讨论】:

  • 你应该看看Merge。
  • 你的桌子上有什么索引?
  • 没有索引 atm,我只想让它先发送数据
  • 您使用的是什么版本的 SQL Server?

标签: sql sql-server sql-server-2008


【解决方案1】:

您可以为此使用MERGE:

MERGE Data_Archive.dbo.Company WITH (HOLDLOCK) AS a
USING OLD.dbo.Company AS o
    ON a.CompanyID = b.CompanyID
WHEN MATCHED THEN UPDATE    
    SET CompanyName = o.CompanyName,
        Address1 = o.Address1,
        Address2 = o.Address2,
        Address3 = o.Address3,
        Address4 = o.Address4,
        ZipCode = o.ZipCode
WHEN NOT MATCHED BY TARGET THEN 
    INSERT (CompanyName, Address1, Address2, Address3, Address4, ZipCode)
    VALUES (o.CompanyName, o.Address1, o.Address2, o.Address3, o.Address4, o.ZipCode)
WHEN NOT MATCHED BY SOURCE THEN DELETE;

这将更新所有存在的记录,插入任何新记录,并从存档中删除已从OLD 数据库中删除的所有记录。如果不需要最后一位,则只需删除WHEN NOT MATCHED BY SOURCE THEN DELETE。

使用HOLDLOCK 将确保您不会遇到race condition,尽管MERGE 仍然有some quirks,但我认为它们不会成为问题。

这样做的主要好处是 SQL 在单个事务中管理它,因此您无需检查一个部分是否失败然后回滚事务。

【讨论】:

  • 感谢 Gareth,这看起来更有效率
【解决方案2】:

使用MERGE 语句:

MERGE INTO Stg.Data_Archive.dbo.Company AS tbl
USING (
    SELECT old.CompanyID, old.CompanyName, old.Address1, old.Address2, old.Address3, old.Address4, old.ZipCode
    FROM OLD.dbo.Company AS old
    LEFT OUTER JOIN Data_Archive.dbo.Company AS new
    ON old.CompanyID = new.CompanyID 
    WHERE new.CompanyID IS NOT NULL) AS source
ON tbl.CompanyID=source.CompanyID
WHEN MATCHED THEN --if i find a row, update
    UPDATE SET
    tbl.CompanyID = source.CompanyID,
    tbl.CompanyName = source.CompanyName,
    tbl.Address1 = source.Address1,
    tbl.Address2 = source.Address2,
    tbl.Address3 = source.Address3,
    tbl.Address4 = source.Address4,
    tbl.ZipCode = source.ZipCode
WHEN NOT MATCHED THEN --if not, insert a new one
    INSERT (CompanyID, CompanyName, Address1, Address2, Address3, Address4, ZipCode)
    VALUES (source.CompanyID, source.CompanyName, source.Address1, source.Address2, source.Address3, source.Address4, source.ZipCode);

【讨论】:

    【解决方案3】:
    BEGIN TRY
          SET NOCOUNT ON
          DECLARE @l_numberOfRecordsInserted INT       
             BEGIN
                   RAISERROR ( N'Invalid Application User ID %d passed.'
                   ,17
                   ,1
                   ,-1 )
             END
          IF NOT EXISTS ( SELECT 
                              1
                          FROM
                              Data_Archive.dbo.Company
                          WHERE
                              ( CompanyID  = @i_CompanyID  )
                              AND CompanyName = @vc_CompanyName ) 
             BEGIN
                   INSERT INTO
                       Data_Archive.dbo.Company
                       (
                        CompanyID,
                        CompanyName,
                        Address1,
                        Address2,
                        Address3,
                        Address4,
                        ZipCode
                       )
                Select  CompanyID,
                        CompanyName,
                        Address1,
                        Address2,
                        Address3,
                        Address4,
                        ZipCode
                          FROM OLD.dbo.company 
        where not exists (select Data_Archive.dbo.Company.CompanyID from  Data_Archive.dbo.Company
                                        WHERE CompanyID = @i_CompanyID)
    
    
             END
          ELSE
             BEGIN
                  Update Data_Archive.dbo.Company
                                Set 
                                Data_Archive.dbo.Company.CompanyID = b.CompanyID,
                                Data_Archive.dbo.Company.CompanyName = b.CompanyName,
                                Data_Archive.dbo.Company.Address1 = b.Address1,
                                Data_Archive.dbo.Company.Address2 = b.Address2,
                                Data_Archive.dbo.Company.Address3 = b.Address3,
                                Data_Archive.dbo.Company.Address4 = b.Address4,
                                Data_Archive.dbo.Company.ZipCode = b.ZipCode,
                                From Data_Archive.dbo.Company a, OLD.dbo.Company b
                                Where a.CompanyID = @i_CompanyID
    
             END
    
          RETURN 0
    END TRY        
    --------------------------------------------------------         
    BEGIN CATCH        
        -- Handle exception        
          DECLARE @i_ReturnedErrorID INT
          EXECUTE @i_ReturnedErrorID = dbo.usp_HandleException @i_UserId = @i_AppUserId
    
          RETURN @i_ReturnedErrorID
    END CATCH
    

    【讨论】:

      【解决方案4】:

      您可以尝试改用Merge 语句。我相信这应该适合你:

      Merge Into Data_Archive.dbo.Company As Target
      Using
      (
          Select  CompanyID,
                  CompanyName,
                  Address1,
                  Address2,
                  Address3,
                  Address4,
                  ZipCode
          From    OLD.dbo.company 
      ) As Source On  Source.CompanyID = Target.CompanyID
      When Not Matched Then 
          Insert (CompanyID, CompanyName, Address1, Address2, Address3, Address4, ZipCode)
          Values (Source.CompanyID, Source.CompanyName, Source.Address1, Source.Address2, Source.Address3, Source.Address4, Source.ZipCode)
      When Matched Then
          Update
          Set     CompanyName = Source.CompanyName,
                  Address1    = Source.Address1,
                  Address2    = Source.Address2,
                  Address3    = Source.Address3,
                  Address4    = Source.Address4,
                  ZipCode     = Source.ZipCode
      ;
      

      【讨论】:

        猜你喜欢
        • 2011-04-30
        • 1970-01-01
        • 2015-07-04
        • 2014-11-29
        • 2014-10-23
        • 1970-01-01
        • 1970-01-01
        • 2019-10-17
        • 2012-12-13
        相关资源
        最近更新 更多