Today I'm found a very sticky problem on SQL Server 2014.
Scenario: I want to pay awards to my customer (some pin code for cell phone operator)
In last cycle of loop T.Used = 0
condition is bypassed and is not working. I know in other conditions in that query (T.Cash < (@myAwards - @paid)
) is there a mistake and I must to use T.Cash <= (@myAwards - @paid)
instead of this but please focus on main question.
Why it's happened when I update Used
flag to 1 (True)
then in next loop it's selected while it doesn't have a valid condition (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
Please let me to understand this is a bug or I have misunderstanding
First screenshot:
Second screenshot (result of loop):
Third screenshot (final result):
As per my comments:
This isn't a problem with the condition, the problem is with the implemented logic. After i = 4
, there are no more rows where T.Used = 0 AND T.Cash < (@myAwards - @paid)
, that makes it so your reassigning variables gets zero rows, so they mantain the previous values.
You can test this behavior by doing:
DECLARE @A INT = 10;
SELECT @A = object_id
FROM sys.all_objects
WHERE name = 'an object that doesn''t exist'
SELECT @A;