0

可能重复:
用 sql 处理负值

我有一个数据集,列出了未来产品库存的日期和数量。有时,我们的需求超过了我们未来的供应,我们最终会得到一个负的未来数量。我需要将未来的负数量计入之前的供应量,这样我们就不会因超卖供应而加剧问题。

在以下数据集中,我需要为 10 至 19 日的需求做准备,将负数沿链向上应用,直到我得到一个正数:

"ID","SKU","DATE","QUANTITY"
"1","001","2012-06-22","1656"
"2","001","2012-07-13","1986"
"3","001","2012-07-27","-283"
"4","001","2012-08-17","2718"
"5","001","2012-08-31","-4019"
"6","001","2012-09-14","7212"
"7","001","2012-09-21","782"
"8","001","2012-09-28","2073"
"9","001","2012-10-12","1842"
"10","001","2012-10-19","-12159"

我需要做到这一点:

"ID","SKU","DATE","QUANTITY"
"1","001","2012-06-22","1656"
"2","001","2012-07-13","152"

我已经研究过使用 while 循环和外部应用,但似乎还没有找到一种方法来做到这一点。任何帮助将非常感激。这需要适用于 sql server 2008 R2。

这是另一个例子:

"1","002","2012-07-13","1980"
"2","002","2012-08-10","-306"
"3","002","2012-09-07","826"

会成为:

"1","002","2012-07-13","1674"
"3","002","2012-09-07","826"

本质上,我需要做的是从最远的负值日期开始,然后回溯到我的第一个正值。然后到我的下一个最远的日期并继续工作,直到我再次获得积极的价值。因此,对于第一个示例,我从 -12,159 开始并返回到第 2 行,这最终给了我一个正值。Ex 2, -306 可以追溯到 1980 年,给我 1674。

4

2 回答 2

4

您需要使用 2 个外部应用程序。第一个获得数量为负数的最大日期(这也可以使用窗口函数完成,但它需要在子查询或公用表表达式中以供稍后引用)。然后下一个外部应用可以将当前行和最后一个负行之间的所有数量相加。

SELECT  ID, 
        SKU, 
        Date, 
        CASE WHEN Quantity2 < Quantity THEN Quantity2 ELSE Quantity END [Quantity]
FROM    T
        OUTER APPLY
        (   SELECT  MAX(Date) [LastNegativeDate]
            FROM    T T1
            WHERE   T1.SKU = T.SKU
            AND     Quantity < 0
        ) LastNegative
        OUTER APPLY
        (   SELECT  SUM(Quantity) [Quantity2]
            FROM    T T2
            WHERE   T2.SKU = T.SKU
            AND     T2.Date BETWEEN T.Date AND LastNegativeDate
        ) Quantity
WHERE   CASE WHEN Quantity2 < Quantity THEN Quantity2 ELSE Quantity END > 0
ORDER BY SKU, Date

这适用于您给出的两个示例:http ://sqlfiddle.com/#!3/ad650/2

ID  SKU     DATE                QUANTITY
1   001     June, 22 2012       1656
2   001     July, 13 2012       152
11  002     July, 13 2012       1674
13  002     September, 07 2012  826
于 2012-06-14T16:31:55.780 回答
1

如果你想要 SPROC 方法,这里有一个。到目前为止,这适用于您的所有场景。这是我使用的数据:

--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(1,'001',1656)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(2,'001',1986)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(3,'001',-283)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(4,'001',2718)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(5,'001',-4019)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(6,'001',7212)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(7,'001',782)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(8,'001',2073)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(9,'001',1842)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(10,'001',-12159)

--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(1,'002',1980)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(2,'002',-306)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(3,'002',826)

--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(1,'003',2592)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(2,'003',2592)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(3,'003',2448)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(4,'003',-4836)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(5,'003',1968)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(6,'003',1074)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(7,'003',324)
--INSERT INTO TestQuantity(ID, SKU, Quantity) Values(8,'003',1638)

这是SQL:

CREATE TABLE #Results(ID int, SKU varchar(50), Quantity int)

DECLARE @sku as VARCHAR(50)
DECLARE skuCursor CURSOR FOR
    SELECT DISTINCT SKU FROM TestQuantity WHERE Quantity < 0

OPEN skuCursor
FETCH NEXT FROM skuCursor INTO @sku

WHILE @@FETCH_STATUS = 0
BEGIN
    DECLARE @id AS INT
    DECLARE @quantity AS INT
    DECLARE quantityCursor CURSOR FOR
        SELECT ID, Quantity FROM TestQuantity WHERE SKU=@sku AND ID <= (SELECT MAX(ID) FROM TestQuantity WHERE SKU=@sku and Quantity < 0) ORDER BY ID DESC

    OPEN quantityCursor

    FETCH NEXT FROM quantityCursor
    INTO @id, @quantity

    DECLARE @firstID AS INT = @id
    DECLARE @sum AS INT = -1
    DECLARE @currentID AS INT
    DECLARE @currentQuantity AS INT
    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF @sum < 0
        BEGIN
            SELECT @currentID = ID, @currentQuantity = Quantity FROM TestQuantity WHERE SKU=@sku AND ID=@id - 1
            SET @sum = @currentQuantity + @quantity

            WHILE(@sum < 0)
            BEGIN
                SELECT @currentID = ID, @currentQuantity = Quantity FROM TestQuantity WHERE SKU=@sku AND ID=@currentID - 1
                SET @sum = @currentQuantity + @sum  
            END 
        END
        FETCH NEXT FROM quantityCursor
        INTO @id, @quantity 
    END

    INSERT INTO #results(ID, SKU, Quantity)
        SELECT ID, SKU, QUANTITY FROM TestQuantity WHERE ID > @firstID and SKU=@sku
    INSERT INTO #results(ID, SKU, Quantity)
        SELECT ID, SKU, QUANTITY FROM TestQuantity WHERE ID < @currentID and SKU=@sku
    INSERT INTO #results(ID, SKU, Quantity)
        SELECT @currentID, @sku, @sum

    CLOSE quantityCursor
    DEALLOCATE quantityCursor

    FETCH NEXT FROM skuCursor INTO @sku 
END 

CLOSE skuCursor
DEALLOCATE skuCursor

SELECT * FROM #results order by sku, id

DROP TABLE #results

我的结果:

1   001 1656
2   001 152
1   002 1674
3   002 826
1   003 2592
2   003 204
5   003 1968
6   003 1074
7   003 324
8   003 1638
于 2012-06-14T16:48:35.010 回答