2011-03-21 98 views
1

你如何做一个查询来计算一个物品已经消耗了多少(用完)?SQL消耗量查询?

我们可以发现,我们在购买表列购买的每件商品的数量编号,产品编号,数量(十进制),日期

Id, ProductId, Qty, Date  
1, 1,   10, 1/1/11 
2, 1,   5, 2/2/11 
3, 1,   8, 3/3/11 

你如何再添加多少的计数购买表中的每一行都已被消耗 - 假设严格的FIFO?所以在上面的例子,如果我们知道,14已经被消耗的输出将是:

Id, ProductId, Qty, Date, Consumed  
1, 1,   10, 1/1/11, 10 
2, 1,   5, 2/2/11, 4 
3, 1,   8, 3/3/11, 0 

希望这说明我的意思的消耗量查询 - 我们知道14被消耗,并且在第一次进货是10 ,所有10个都被消耗掉了。接下来的购买是5,所以我们知道其中4个已被消费。

即使世界两个地方我可以从消费数据 - 的ConsumedItems表:列编号,产品编号,QtyUsed,日期),或者从列productId使用ConsumedSummaryView,QtyUsed(这是ConsumedItems.QtyUsed的总和)

回答

2

有点不同的方法比理查的,但我不知道这将有更好的表现:

SELECT 
    Purchases.Id, 
    Purchases.ProductId, 
    Purchases.Qty, 
    Purchases.Date, 
    CASE 
     WHEN COALESCE (PreviousPurchases.PreviousUsed, 0) + Qty < ConsumedSummaryView.QtyUsed THEN Qty 
     ELSE 
      CASE 
       WHEN ConsumedSummaryView.QtyUsed - COALESCE (PreviousPurchases.PreviousUsed, 0) < 0 THEN 0 
       ELSE ConsumedSummaryView.QtyUsed - COALESCE (PreviousPurchases.PreviousUsed, 0) 
      END 
    END AS Used 
FROM 
    Purchases 
    INNER JOIN ConsumedSummaryView ON Purchases.ProductId = ConsumedSummaryView.ProductId 
    LEFT OUTER JOIN (
     SELECT 
      SUM(Purchases_2.Qty) AS PreviousUsed, 
      Purchases_1.Id 
     FROM 
      Purchases AS Purchases_2 
      INNER JOIN Purchases AS Purchases_1 ON Purchases_2.Id < Purchases_1.Id 
               AND Purchases_2.ProductId = Purchases_1.ProductId 
     GROUP BY 
      Purchases_1.Id 
    ) AS PreviousPurchases ON Purchases.Id = PreviousPurchases.Id 
+0

似乎没有工作?对于3行,我得到Used = 10,NULL,0(使用上面的@Richard测试数据设置脚本+加上查询) – 2011-03-22 00:06:48

+1

对不起,在那里留下了一个变量。现在就试试。 – 2011-03-22 00:25:16

+0

您的解决方案目前看起来不错 – 2011-03-22 01:52:23

5

样品表和视图

create table purchases (Id int, ProductId int, Qty int, Date datetime) 
insert purchases select 1, 1,   10, '1/1/11' 
insert purchases select 2, 1,   5, '2/2/11' 
insert purchases select 3, 1,   8, '3/3/11' 
create view ConsumedSummaryView as select ProductID = 1, QtyUsed = 14 

查询

;with p as (
    select *, rn=ROW_NUMBER() over (partition by productid order by date, id) 
    from purchases) 
, tmp(Id, ProductId, Qty, Date, rn, ToGo, Consumed) as (
    select p.Id, p.ProductId, p.Qty, p.Date, cast(1 as bigint), 
      CAST(ISNULL(v.qtyused,0) - p.Qty as decimal(20,10)), 
     cast(case 
      when v.qtyused >= p.Qty Then p.Qty 
      when v.qtyused > 0 then v.qtyused 
      else 0 end as decimal(20,10)) 
    from p 
    left join ConsumedSummaryView v on p.ProductId = v.productId 
    where rn=1 
    union all 
    select p.Id, p.ProductId, p.Qty, p.Date, cast(p.rn as bigint), 
      cast(ISNULL(tmp.toGo,0) - p.Qty as decimal(20,10)), 
     cast(case 
      when tmp.toGo >= p.Qty Then p.Qty 
      when tmp.toGo > 0 then tmp.toGo 
      else 0 end as decimal(20,10)) 
    from tmp 
    --inner join p on p.rn=tmp.rn+1 
    inner join p on p.rn=tmp.rn+1 and p.productid = tmp.ProductId 
) 
select Id, ProductId, Qty, Date, Consumed 
from tmp 
order by rn 

输出

Id   ProductId Qty   Date     Consumed 
----------- ----------- ----------- ----------------------- ----------- 
1   1   10   2011-01-01 00:00:00.000 10 
2   1   5   2011-02-02 00:00:00.000 4 
3   1   8   2011-03-03 00:00:00.000 0 
+0

由于这是非常密切的。但我忘了说数量是小数。 “您的解决方案出现此错误”类型不匹配递归查询“tmp”的列“ToGo”中的锚点和递归部分“ – 2011-03-21 23:59:33

+0

如果更改上面的示例表以读取'create table purchases(Id int,ProductId int ,十进制数,日期datetime)'那么你可以看到发生错误 – 2011-03-22 00:08:38

+0

@JK当有疑问时,CAST的递归CTE的两个部分 - 答案更新。将小数点从20,10减少到更合理的点 – RichardTheKiwi 2011-03-22 00:11:11