SQL量消耗查询?

时间:2011-03-21 22:42:38

标签: sql sql-server

如何进行查询以计算消耗了多少物品(用完)?

我们可以在购买表中找到我们购买的每件商品的数量,包括列Id,ProductId,数量(十进制),日期

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表:列Id,ProductId,QtyUsed,Date),或者来自ConsumedSummaryView,其中包含ProductId,QtyUsed(这是ConsumedItems.QtyUsed的总和)

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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