TSQL运行总和

时间:2011-04-28 11:36:26

标签: sql sql-server tsql

我需要在视图中显示每天的库存水平。我有一个表列出当前项目和数量,另一个表列出了这些项目发生的所有事务。我需要创建一个查询,列出趋势报告中该日期的项目,日期和库存水平。以下是表格中的一些示例数据:

产品:

ItemNumber     QuantityOnHand
----------     --------------
B34233         25.0
B34234         10.0

ItemTransactions:

TransDate      ItemNumber     Quantity
-----------    ----------     --------
1/1/2011       B34233         10.0
1/2/2011       B34234         -15.0
1/2/2011       B34233         -5.0
1/4/2011       B34234         -10.0

以下是我想从查询中获得的结果:

Date          ItemNumber      Quantity
----          ----------      --------
12/31/2010    B34233          20.0
12/31/2010    B34234          35.0
1/1/2011      B34233          30.0
1/1/2011      B34234          35.0
1/2/2011      B34233          25.0
1/2/2011      B34234          20.0
1/3/2011      B34233          25.0
1/3/2011      B34234          20.0
1/4/2011      B34233          25.0
1/4/2011      B34234          10.0

我该如何撰写此查询?我对TSQL非常了解,但无法想出一种编写此查询的方法。

3 个答案:

答案 0 :(得分:1)

SQL Server 2005及以上:

WITH    dates (itemNumber, quantity, currentDate, minDate) AS
        (
        SELECT  itemNumber, CAST(quantityOnHand AS DECIMAL(20, 2)), it.*
        FROM    items i
        CROSS APPLY
                (
                SELECT  MAX(transDate) AS currentDate,
                        MIN(transDate) AS minDate
                FROM    itemTransactions it
                ) it
        UNION ALL
        SELECT  d.itemNumber,
                CAST
                (
                d.quantity -
                COALESCE(
                (
                SELECT  it.quantity
                FROM    itemTransactions it
                WHERE   it.transDate = d.currentDate
                        AND it.itemNumber = d.itemNumber
                ), 0) AS DECIMAL(20, 2)),
                DATEADD(d, -1, currentDate),
                minDate
        FROM    dates d
        WHERE   currentDate >= minDate
        )
SELECT  currentDate, itemNumber, quantity
FROM    dates
ORDER BY
        currentDate, itemNumber

这假设您每天每件商品有一笔交易(这是CTE中递归SQL Server的限制。

如果您不这样做,则应添加另一个CTE,它会按天和项汇总交易,并使用它代替items

WITH    itGrouped (transDate, itemNumber, quantity) AS
        (
        SELECT  transDate, itemNumber, SUM(quantity)
        FROM    itemTransactions
        GROUP BY
                transDate, itemNumber
        ),
        dates (itemNumber, quantity, currentDate, minDate) AS
        (
        SELECT  itemNumber, CAST(quantityOnHand AS DECIMAL(20, 2)), it.*
        FROM    items i
        CROSS APPLY
                (
                SELECT  MAX(transDate) AS currentDate,
                        MIN(transDate) AS minDate
                FROM    itGrouped it
                ) it
        UNION ALL
        SELECT  d.itemNumber,
                CAST
                (
                d.quantity -
                COALESCE(
                (
                SELECT  it.quantity
                FROM    itGrouped it
                WHERE   it.transDate = d.currentDate
                        AND it.itemNumber = d.itemNumber
                ), 0) AS DECIMAL(20, 2)),
                DATEADD(d, -1, currentDate),
                minDate
        FROM    dates d
        WHERE   currentDate >= minDate
        )
SELECT  currentDate, itemNumber, quantity
FROM    dates
ORDER BY
        currentDate, itemNumber

答案 1 :(得分:0)

请参阅,查询很简单,但您对日期的要求是什么。我给出了一个简单的查询,它会给你一个想法,我正在使用一个临时表:

Create Table #Transection
(
    ID int Identity(1,1) not null,Item_Number varchar(20),Transection_Date datetime,Quantity_Available decimal(10,2)
)

insert into #Transection (Item_Number)  (Select ItemNumber from Items)

Declare @Product varchar(20),@Next_Product Cursor, @Item varchar(20),@Quantity decimal(10,2)
set  @Next_Product= CURSOR FOR Select Item_Number from #Transection open @Next_Product Fetch Next from @Next_Product into @Product

    While @@Fetch_Status=0
        Begin
            set @Item=(Select ItemNumber from  ItemTransection where ItemNumber= @Product)
                if is not null
                    Begin
                        Set @Quantity=(Select top 1 Items.Quantityonhand -ItemsTrasection.Quant as Quantity from Items Join
                                       ItemsTrasection on ItemsTrasection.ItemNumber=Items.ItemNumber where ItemsTrasection.ItemNumber=@Item order by ItemsTrasection.TransDate desc)
                        update #Transection set Transection_Date=(Select top 1 TransDate from ItemsTrasection where ItemNumber=@Item order by TransDate desc), Quantity=@Quantity
                            where Item_Number=@Item
                    End
                Else
                    Begin
                        update #Transection set Transection_Date=(Select top 1 TransDate from Items where ItemNumber=@Item ), Quantity=(Select top 1 from Items where ItemNumber=@Item )
                            where Item_Number=@Item
                    End
        End
Select * from #Transection

答案 2 :(得分:0)

一个简单的版本,使用子选择来获取每天的数量。

如果你没有100k的交易和/或一个不错的sql框,这是一个好的/快速的解决方案。

请原谅凌乱的SQL(午餐时间编码:P)

CREATE TABLE #transactions (ID INT, DTE DATETIME, PROD VARCHAR(25), QTY INT )
CREATE TABLE #products (ID VARCHAR(25))
CREATE TABLE #dates (DTE DATETIME)

-- create some dates - you would do this dynamically
INSERT INTO #dates values (convert(datetime, '01/01/2011', 103))
INSERT INTO #dates values (convert(datetime, '02/01/2011', 103))
INSERT INTO #dates values (convert(datetime, '03/01/2011', 103))

-- create some products - you would get these from where-ever they live
INSERT INTO #products values ('A')
INSERT INTO #products values ('B')

-- create some transactions - you would get these from where-ever they live
INSERT INTO #transactions values (1, convert(datetime, '01/01/2011', 103), 'A', 25)
INSERT INTO #transactions values (2, convert(datetime, '01/01/2011', 103), 'A', -5)
INSERT INTO #transactions values (3, convert(datetime, '02/01/2011', 103), 'A', 60)
INSERT INTO #transactions values (4, convert(datetime, '02/01/2011', 103), 'A', -15)
INSERT INTO #transactions values (5, convert(datetime, '03/01/2011', 103), 'A', 100)
INSERT INTO #transactions values (6, convert(datetime, '03/01/2011', 103), 'A', -20)

INSERT INTO #transactions values (7, convert(datetime, '01/01/2011', 103), 'B', 10)
INSERT INTO #transactions values (8, convert(datetime, '01/01/2011', 103), 'B', 5)
INSERT INTO #transactions values (9, convert(datetime, '02/01/2011', 103), 'B', -30)
INSERT INTO #transactions values (1, convert(datetime, '02/01/2011', 103), 'B', 50)
INSERT INTO #transactions values (11, convert(datetime, '03/01/2011', 103), 'B', 10)
INSERT INTO #transactions values (12, convert(datetime, '03/01/2011', 103), 'B', 200)

-- Join dates and transactions - Do a sub select from 'begining of time' to get qty on hand per day
SELECT CONVERT(VARCHAR(25), a.DTE, 103),  b.id, (SELECT sum(qty) from #transactions c where b.id = c.prod and c.DTE <= a.DTE)
FROM #dates a, #products b

-- One benefit to this approach means you can genereate qty_on_hand per days were no transactions have occured (if you needed this)

DROP TABLE #transactions
DROP TABLE #products
DROP TABLE #dates