英文:
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;
阅读这篇文章,并注意以下内容:
- 您需要一个事务来确保一致性。
- 您需要添加
UPDLOCK
和HOLDLOCK/SERIALIZABLE
提示来确保正确的锁定。 - 您不需要使用
SELECT
进行首次检查,这是浪费的。只需进行UPDATE
,如果@@ROWCOUNT
为0,则执行INSERT
。 - 如果后者更有可能,可以交换
UPDATE
和INSERT
。 - 如果有选择的话,在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
andHOLDLOCK/SERIALIZABLE
hints to ensure correct locking. -
You don't need to check first using a
SELECT
, it's wasteful. Just do theUPDATE
, and if the@@ROWCOUNT
is 0 then do theINSERT
. -
You can swap around the
UPDATE
andINSERT
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论