今天我在SQL Server 2014上发现了一个非常棘手的问题。
情景:我想向我的客户支付奖励(手机运营商的一些密码)
在循环T.Used = 0
的最后一个循环中,条件被绕过并且不起作用。我知道在该查询的其他条件(T.Cash < (@myAwards - @paid)
)中存在错误,我必须使用T.Cash <= (@myAwards - @paid)
代替此问题,但请关注主要问题。
为什么当我将Used
标志更新为1 (True)
然后在下一个循环中它被选中而它没有有效条件(T.Used = 0
)时发生了什么?
DECLARE @myAwards INT = 90000,
@paid INT = 0;
DECLARE @Temp TABLE
(
Id INT NOT NULL,
Pin VARCHAR(100) NOT NULL,
Cash INT NOT NULL,
[Weight] INT NULL,
Used BIT NOT NULL
)
INSERT INTO @Temp
SELECT
UPFI.Id, UPFI.PinCode,
PT.Cash, NULL, 0
FROM
dbo.UploadedPinFactorItem UPFI WITH (NOLOCK)
INNER JOIN
dbo.PinType PT WITH (NOLOCK) ON PT.ID = UPFI.PinTypeID
WHERE
PT.Cash <= @myAwards
UPDATE T
SET [Weight] = ISNULL((SELECT COUNT(TT.Id)
FROM @Temp TT
WHERE TT.Cash = T.Cash), 0) * T.Cash
FROM @Temp T
--For debug (first picture)
SELECT * FROM @Temp
DECLARE @i int = 1
DECLARE @count int = 0
SELECT @count = COUNT([Id]) FROM @Temp C WHERE C.Used = 0
WHILE (@i <= @count AND @paid < @myAwards)
BEGIN
DECLARE @nextId INT,
@nextCash INT,
@nextFlag BIT;
-- 'T.Used = 0' condition is by passed
SELECT TOP (1)
@nextId = T.Id, @nextCash = T.Cash, @nextFlag = T.Used
FROM
@Temp T
WHERE
T.Used = 0
AND T.Cash < (@myAwards - @paid)
ORDER BY
T.[Weight] DESC, T.Cash DESC, T.Id DESC
UPDATE @Temp
SET Used = 1
WHERE Id = @nextId
SET @i = @i + 1
SET @paid = @paid + @nextCash
--Show result in second picture
SELECT
@i AS 'i', @paid AS 'paid', @nextFlag AS 'flag', @nextId AS 'marked Id',*
FROM
@temp T
ORDER BY
T.[Weight] DESC, T.Cash DESC, T.Id DESC
END
SELECT 'final', @paid, *
FROM @temp T
ORDER BY T.[Weight] DESC, T.Cash DESC, T.Id DESC
请让我明白这是一个错误或我有误解
第一个截图:
第二个截图(循环结果):
第三个截图(最终结果):
答案 0 :(得分:2)
根据我的评论:
这不是问题,问题在于实现的逻辑。在i = 4
之后,没有更多行T.Used = 0 AND T.Cash < (@myAwards - @paid)
,这使得重新分配的变量变为零行,因此它们保留了以前的值。
您可以通过执行以下操作来测试此行为:
DECLARE @A INT = 10;
SELECT @A = object_id
FROM sys.all_objects
WHERE name = 'an object that doesn''t exist'
SELECT @A;