Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/87.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MS SQL等效于重复密钥更新/更新插入_Sql_Sql Server_Upsert_On Duplicate Key - Fatal编程技术网

MS SQL等效于重复密钥更新/更新插入

MS SQL等效于重复密钥更新/更新插入,sql,sql-server,upsert,on-duplicate-key,Sql,Sql Server,Upsert,On Duplicate Key,我是一名postgres用户,对MS SQL来说是新手。我需要复制重复密钥更新功能(有时称为UPSERT)。我有一个用户表(这里简化了),包括年龄和性别 使用此示例查询,但根据需要更改id,更新功能可以工作,但插入功能不能。没有错误,它只是说0行受影响 MERGE users AS target USING (SELECT id FROM users WHERE id=222) AS source ON target.id = source.id WHEN MATCH

我是一名postgres用户,对MS SQL来说是新手。我需要复制重复密钥更新功能(有时称为UPSERT)。我有一个用户表(这里简化了),包括年龄和性别

使用此示例查询,但根据需要更改id,更新功能可以工作,但插入功能不能。没有错误,它只是说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


另外,我在StackOverflow中查看了MSSQL问题中的其他问题。这就是我得到这个语法的原因。但是,我无法通过它们理解这里的问题。

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

我建议做以下几点:

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'

我最终使用了来自的一些信息来解决它。它并没有确切地解决这个问题,但它帮助我看到了我的subselect(…)作为源的问题。基本上,(显然)USING隐式地假定了源表,并通过使用用户的
显式地指定源表,其中…
我阻止了sql server对其进行检查。这是我最好的理解

关键是,这个查询可以工作:运行它一次,它将插入一个新用户,并带有
(555,55,'M')
。再次运行它,相同的记录将更新为
(555,22,'F')

而且,很明显,合并可能会在高速率下出现并发问题,因此链接问题建议使用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')
;

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 
       );

如果id仅匹配,则将执行更新,而不是插入。遗憾的是,没有更改。不匹配时仍有(0行受影响)。是否要将表合并到自身?如果你有一个密钥存在,那么你会更新,但如果没有这样的记录存在,那么你想插入吗?如果后者是正确的,那么我认为您不需要合并。如果您有一个解决方案,我愿意接受另一个解决方案:)我只需要插入一条记录,或者如果该记录的id已经存在,则进行更新。谢谢您的帮助。我找到了一个稍微短一点的解决方案。我不完全确定它起作用的根本原因,但我能理解它的形式。你能分享一下这个解决方案吗。我很想知道它是什么