SQL Server 2016,存储过程执行的意外结果



我绝不是SQL专家。我倾向于从我以这种方式找到和学习的其他样例代码中构建和测试查询。我编写了一个存储过程,用于更新两个表中的客户定价。应该发生的要点是,如果存在商品和价格级别,它应该更新该商品的价格。如果它不存在,我需要它用该数据插入一条新记录。当我执行这个过程时,它更新了DB中的每一条记录。我将非常感谢对正确表述这个条件语句的最佳实践的一些见解。提前谢谢。

USE [TEST]
GO
/****** Object:  StoredProcedure [dbo].[aUpdatePricingLevels]    Script Date: 5/2/2022 9:59:38 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE   PROCEDURE [dbo].[aUpdatePricingLevels]
@ItemNumber CHAR(31),
@PriceLevel CHAR(11),
@ToQuantity numeric(19, 5) = 999999999999,
@FromQuantity numeric(19, 5) = 1,
@UnitOfMeasure char(9) = 'EA',
@Price numeric(19, 5),
@Equivalency numeric(19, 5) = 1
AS
IF EXISTS(Select * FROM IV00108 WHERE ITEMNMBR like @ItemNumber and PRCLEVEL LIKE @PriceLevel)
UPDATE IV00108 SET UOMPRICE= @Price  --THERE IS AN ISSUE HERE.  IT SET ALL PRICES. NEEDS A 
CONDITIONAL
--PRINT'placeholder'
ELSE
INSERT INTO dbo.IV00108 (ITEMNMBR,PRCLEVEL,TOQTY,FROMQTY,UOFM,UOMPRICE,QTYBSUOM)
VALUES(@ItemNumber,@PriceLevel,@ToQuantity,@FromQuantity,@UnitOfMeasure,@Price,@Equivalency)

IF EXISTS(Select * FROM IV00107 WHERE ITEMNMBR like @ItemNumber and PRCLEVEL LIKE @PriceLevel)
PRINT 'Record Exists, No Action Needed'
ELSE
INSERT INTO dbo.IV00107 (ITEMNMBR,PRCLEVEL,UOFM,ROUNDHOW,ROUNDTO,UMSLSOPT,QTYBSUOM)
VALUES(@ItemNumber,@PriceLevel,@UnitOfMeasure,0,1,2,@Equivalency)
GO
<代码>

你在说:

UPDATE dbo.IV00108
SET UOMPRICE = @Price
WHERE ITEMNMBR like @ItemNumber 
and PRCLEVEL LIKE @PriceLevel;
IF @@ROWCOUNT = 0
BEGIN
INSERT ...
END
一个更好的模式,即使逻辑是正确的应该是:
IF (a row with these conditions exists) 
UPDATE the row with these conditions

我们为什么不说:

IF EXISTS(
Select * 
FROM IV00108 
WHERE ITEMNMBR like @ItemNumber and PRCLEVEL LIKE @PriceLevel
)
UPDATE IV00108 SET UOMPRICE= @Price  
WHERE ITEMNMBR like @ItemNumber and PRCLEVEL LIKE @PriceLevel)

?因为它的工作量是原来的两倍(为什么要两次定位行?),因为它创建了一个场景,在这个场景中,它们之间可能存在不一致(就像在这个例子中一样),而且——最重要的是——因为它引入了更多竞争条件的机会。看到:

  • 请停止使用此UPSERT反模式

你有一个where在你的存在,但没有在你的更新这里可能缩进有帮助…

PP_6

正如Arron在另一个答案中所说——最好使用@@rowcount

最新更新