如何根据SELECT的结果在一个语句中进行INSERT或UPDATE

huangapple go评论77阅读模式
英文:

How to INSERT or UPDATE depending on the result of SELECT in 1 statement

问题

我正在尝试创建一个基于SELECT语句的结果来决定是INSERT还是UPDATE语句的操作。

目前,我有这个不起作用的语句:

UPDATE Inventory 
SET CQuantity = CQuantity + 1 
WHERE CBarcode = '00029218' 
  AND COALESCE(COUNT(SELECT CQuantity 
                     FROM Inventory 
                     WHERE CBarcode = '00029218'), 0) > 1;

根据这个SQL语句,它应该在库存表中更新数量,如果条形码是指定的值,并且在库存表中找到了现有行。但它似乎不起作用。

如果在库存表中找到现有行,我想要UPDATE数量,否则,如果条形码不存在,就要INSERT一条新记录。

非常感谢。

英文:

I'm trying to create an INSERT or UPDATE statement depending on the result of a SELECT statement in one go.

Currently, I have this statement that doesn't work:

UPDATE Inventory 
SET CQuantity = CQuantity + 1 
WHERE CBarcode = '00029218' 
  AND COALESCE(COUNT(SELECT CQuantity 
                     FROM Inventory 
                     WHERE CBarcode = '00029218'), 0) > 1;

Based on the SQL statement, it's supposed to update the quantity in the inventory table if the barcode is the specified value and if it finds an existing row in the inventory table. It doesn't work though.

I would like to UPDATE quantity if it finds an existing row in the inventory table, otherwise, it would INSERT a new row if barcode doesn't exist.

Thank you so much.

答案1

得分: 3

这是一个标准的UpSert。您的逻辑应该如下所示。

DECLARE @barcode varchar(30) = '00029218';

SET XACT_ABORT, NOCOUNT ON;
BEGIN TRAN;

UPDATE Inventory WITH (UPDLOCK, HOLDLOCK)
SET CQuantity += 1
WHERE CBarcode = @barcode;

IF @@ROWCOUNT = 0
    INSERT Inventory (CBarcode, CQuantity)
    VALUES (@barcode, 1);

COMMIT;

阅读这篇文章,并注意以下内容:

  • 您需要一个事务来确保一致性。
  • 您需要添加UPDLOCKHOLDLOCK/SERIALIZABLE提示来确保正确的锁定。
  • 您不需要使用SELECT进行首次检查,这是浪费的。只需进行UPDATE,如果@@ROWCOUNT为0,则执行INSERT
  • 如果后者更有可能,可以交换UPDATEINSERT
  • 如果有选择的话,在SQL Server中不要使用MERGE,因为它充满了错误。
英文:

This is a standard UpSert. Your logic should look like this.

DECLARE @barcode varchar(30) = '00029218';

SET XACT_ABORT, NOCOUNT ON;
BEGIN TRAN;

UPDATE Inventory WITH (UPDLOCK, HOLDLOCK)
SET CQuantity += 1
WHERE CBarcode = @barcode;

IF @@ROWCOUNT = 0
    INSERT Inventory (CBarcode, CQuantity)
    VALUES (@barcode, 1);

COMMIT;

Take a read of this article, and note the following:

  • You need a transaction to ensure consistency.

  • You need to add UPDLOCK and HOLDLOCK/SERIALIZABLE hints to ensure correct locking.

  • You don't need to check first using a SELECT, it's wasteful. Just do the UPDATE, and if the @@ROWCOUNT is 0 then do the INSERT.

  • You can swap around the UPDATE and INSERT if the latter is more likely.

  • Don't use MERGE in SQL Server if you have a choice, it's full of bugs.

答案2

得分: 2

尽量编写可维护且易读的代码。因为他们能够理解它,所以没有人会抱怨!如果要使用稍微不那么易读但更优化的方法,请参考@Charlieface的答案。

SELECT @Exists = CQuantity FROM Inventory WHERE CBarcode = '00029218'

BEGIN
IF @Exists > 0 THEN
    UPDATE Inventory SET CQuantity = CQuantity + 1 WHERE CBarcode = '00029218'
ELSE
    INSERT INTO Inventory (CBarcode, CQuantity) VALUES ('00029218', 1)
END IF
英文:

Try to write maintainable and easily readable code. No one ever complained because they could understand it! For a slightly less readable but more optimized method see @Charlieface's answer.

SELECT @Exists = CQuantity FROM Inventory WHERE CBarcode = '00029218'

BEGIN
IF @Exists > 0 THEN
    UPDATE Inventory SET CQuantity = CQuantity + 1 WHERE CBarcode = '00029218'
ELSE
    INSERT INTO Inventory (CBarcode, CQuantity) VALUES ('00029218', 1)
END IF

huangapple
  • 本文由 发表于 2023年7月10日 10:58:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76650433.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定