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

SQL using while loop to calculate values for multiple elements

我正在尝试使用 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]

目前为止一切正常,但我在尝试对多个项目执行相同操作时卡住了。 当我尝试用这样的 table 替换 @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 table 并说需要先声明它。在这一点上,我不知道为什么会这样,我该如何解决。此外,我对该查询的性能表示怀疑,因为我将对大约 30,000 件商品执行库存计算。

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

亲切的问候。

你要的是累加和。即使在 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 服务器之外)是执行一个 while 循环,每天保持一个 增量 值.但是,这可能具有挑战性,因为您需要为每个项目处理一个单独的变量。

对于所有项目,试试这个:

    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)

创建一个"Numbers"(或"Tally"table)。它只是一个 single-column table 比包含顺序整数。您可以阅读有关如何创建一个 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