MS SQL相当于ON DUPLICATE KEY UPDATE / UPSERT

时间:2017-01-26 20:33:33

标签: sql sql-server upsert on-duplicate-key

我是一位不熟悉MS SQL的postgres用户。我需要复制ON DUPLICATE KEY UPDATE功能(有时称为UPSERT)。我有一张年龄和性别的用户表(简称)。

使用此示例查询,但根据需要更改id,UPDATE功能有效,但INSERT不起作用。没有错误,只是说有0行受影响。

MERGE
    users AS target 
USING
    (SELECT id FROM users WHERE id=222) AS source
ON
    target.id = source.id

WHEN MATCHED THEN 
    UPDATE SET 
        target.id  = source.id,
        target.age = 33,
        target.sex = 'M'

WHEN NOT MATCHED THEN 
    INSERT (id, age, sex) VALUES (222, 33, 'M')
;

如果重要(可能有更简单的方法),我在linux中使用python3。

P.S。我在StackOverflow中查看了MSSQL中的其他 UPSERT 问题。这就是我如何得到这种语法。但是,我无法通过他们理解这里的问题。

3 个答案:

答案 0 :(得分:3)

我最终使用this question中的一些信息来解决它。它没有完全解决它,但它帮助我看到我的subselect(...)AS源的问题。基本上,(显然)USING隐式假设源表并通过FROM users WHERE ...显式指定它,我阻止了sql server检查它。无论如何,这是我最好的理解。

关键是,此查询有效:运行一次,然后插入一个(555, 55, 'M')的新用户。再次运行它,相同的记录更新为(555, 22, 'F')

另外,显然MERGE可能会出现高速并发问题,所以链接的问题建议使用HOLDLOCK,我在这里。

MERGE INTO users WITH (HOLDLOCK) AS target
    USING 
        (SELECT 555 AS id) AS source 
ON 
    (target.id = source.id)

WHEN MATCHED THEN 
        UPDATE SET 
            target.id  = source.id,
            target.age = 22,
            target.sex = 'F'
WHEN NOT MATCHED THEN 
        INSERT (id, age, sex) VALUES (555, 55, 'M')
;

答案 1 :(得分:1)

将表合并到自身时,您将无法插入表中不存在的行:

我建议做以下事项:

DECLARE @id INT = 222, @age int = 33, @sex VARCHAR(10) = 'M'


IF EXISTS (SELECT id FROM users WHERE id=@id)
BEGIN 
    UPDATE users SET age = @age, sex = @sex
END
ELSE 
BEGIN
    INSERT INTO users (id, age, sex) VALUES (@id, @age, @sex)
END

如果你从另一个应用程序调用它,你可能需要一个存储过程,所以你可能想创建一个存储过程来这样做:

CREATE PROCEDURE sp_UpdateInsertUsers @id  INT 
                             , @age INT 
                             , @sex VARCHAR(10) 
AS
    BEGIN
        SET NOCOUNT ON;
        IF EXISTS
               (SELECT id
                FROM   users
                WHERE  id = @id)
           BEGIN
              UPDATE users
                SET  age = @age, sex = @sex;
           END;
        ELSE
           BEGIN
              INSERT INTO      users(id
                               , age
                               , sex)
              VALUES
                    (@id
                   , @age
                   , @sex);
           END;
    END;
GO

调用程序如下:

EXECUTE sp_UpdateInsertUsers @id  = 222
                             , @age = 33
                             , @sex = 'M'

答案 2 :(得分:1)

在ASP.NET中具有绑定参数的示例,用于更新购物车中的产品:

MERGE 
INTO [shoppingcart] WITH (holdlock) AS target 
using        ( 
                    SELECT @ProductID AS ProductID) AS source 
ON ( 
                          target.productid = source.productid) 
WHEN matched THEN 
UPDATE 
SET              target.productid = source.productid, 
                 target.quantity = target.quantity + 1, 
                 target.date = @Date, 
                 target.clientid = @ClientID 
WHEN NOT matched THEN 
INSERT 
       ( 
              quantity, 
              date, 
              clientid, 
              productid 
       ) 
       VALUES 
       ( 
              @Quantity, 
              @Date, 
              @ClientID, 
              @ProductID 
       );