SQL Server:这是一个错误还是我有误解?

时间:2017-01-16 12:45:54

标签: sql sql-server tsql sql-server-2014

今天我在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

请让我明白这是一个错误或我有误解

第一个截图:

First picture

第二个截图(循环结果):

Second picture

第三个截图(最终结果):

Third picture

1 个答案:

答案 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;