SQL使用while循环来计算多个元素的值

时间:2017-02-03 13:47:24

标签: sql sql-server-2008 ssms

我正在尝试使用Ms SQL计算仓库中每件商品的平均每日库存量。 每个传入和传出的数量都记录在同一列中,我们将其命名为[数量]。由于这种结构,我今天告诉库存水平的唯一方法是简单地从开始时间开始计算所有数量。 即。

SELECT [item], SUM(quantity)
FROM item_table

如果我想查看昨天的库存水平,我需要遵循以下代码:

SELECT [item], SUM(quantity)
FROM item_table
WHERE [date] < DATEADD(day,-1,GETDATE())

等每一天。当然,为了获得全年的库存水平,我不会经历手动更改DATEADD数字360次的麻烦。因此我使用While循环如下:

DECLARE @intFlag INT
DECLARE @s DECIMAL = 0
DECLARE @i varchar(20) --replaced with table (see table part below)
SET @intFlag = 0
WHILE (@intFlag <= 360)
BEGIN
SET @intFlag = @intFlag + 1
SET @i = (SELECT TOP (1) [item] FROM item_table ) --replaced with table (see table part below)
SET @s = (
        SELECT
            SUM(quantity) + @s AS inventory
        FROM item_table
        WHERE 
        item IN (@i) --replaced with table (see table part below)
        AND [Date] < dateadd(day, - @intFlag, GETDATE())
        )
IF @intFlag = 360
    BREAK;
END

SELECT 
@i AS [item],
@s/360 AS [AVG_stock]

到目前为止这个工作正常,但是当我尝试对多个项目执行相同的操作时,我陷入了困境。 当我尝试用这样的表替换@i参数时:

DECLARE @items table (number varchar (20))
INSERT INTO @items 
SELECT DISTINCT [Item]
FROM items_table

并尝试在

中调用它
SET @s = (
        SELECT
            SUM(quantity) + @s AS inventory
        FROM item_table
        WHERE 
        item IN (@items) 
        AND [Date] < dateadd(day, - @intFlag, GETDATE())
        )

SQL无法找到@item表,并表示需要先声明它。在这一点上,我不知道为什么会发生这种情况,我该如何解决它。此外,我对该查询的性能有疑问,因为我将执行大约30,000个项目的库存计算。

也许有一个容易解决这个问题的方法,或者有人可能想出一种完全不同的计算那个该死的东西的方法。无论如何,我可以使用任何我能得到的帮助。

亲切的问候。

3 个答案:

答案 0 :(得分:1)

你想要的是累积总和。即使在SQL Server 2008中,您的while循环也不是最佳方法。您可以执行以下操作:

SELECT it.item, it2.quantity
FROM item_table it OUTER APPLY
     (SELECT SUM(it2.quantity) as quantity
      FROM it2
      WHERE it2.item = it.item AND
            it2.date < it.date
     ) it2;

在这种情况下,最快的方法(除了升级SQL Server之外)是执行while循环,保持每天的增量值。但是,这可能具有挑战性,因为您需要为每个项目处理单独的变量。

答案 1 :(得分:1)

对于所有项目,请尝试以下方法:

    With Ints(aInt) As
      (Select -365 Union All
       Select aInt + 1 From Ints
       Where aInt < 0)   
    Select item,
       DateAdd(day, i.aInt, getdate()) tdate 
       Sum(quantity) runningTotal
    from item_table it join Ints i
       on it.[Date] < DateAdd(day, i.aInt, getdate()) 
    group by item, DateAdd(day, i.aInt, getdate()) 
    Option (MaxRecursion 1000)

将其限制为一些小项目,只需添加一个where子句

    With Ints(aInt) As
      (Select -365 Union All
       Select aInt + 1 From Ints
       Where aInt < 0)   
    Select item,
       DateAdd(day, i.aInt, getdate()) tdate 
       Sum(quantity) runningTotal
    from item_table it join Ints i
       on it.[Date] < DateAdd(day, i.aInt, getdate()) 
    where item in ([set of comma-delimited item values here])
    group by item, DateAdd(day, i.aInt, getdate()) 
    Option (MaxRecursion 1000)

答案 2 :(得分:0)

创建&#34;数字&#34; (或&#34; Tally&#34;表)。它只是一个包含连续整数的单列表。您可以阅读有关如何创建一个here的信息。它们对于替换while循环很有用。

一旦你有了这个,你可以这样做:

select i.item, 
i.date, 
sum(i.quantity) over (partition by i.item order by i.date) quantity
from item_table i
join Numbers n on i.date = DATEADD(dd, -1*n.n, convert(date, getdate()))
where n.n <= 365

这应该会为您提供每天运行的总数量。

DEMO here