2011-04-28 77 views
2

我需要显示视图中每一天的库存水平。我有一个表列出当前项目和数量,另一个表包含发生在这些项目上的所有交易。我需要创建一个查询,为趋势报告列出该日期的项目,日期和库存水平。这里将是表中一些样本数据: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有很好的了解,但不能想出写这个查询的方法。

+1

你如何设置在从输入输出?输入中的“12/31/2010”在哪里? – Quassnoi 2011-04-28 11:39:55

+0

@Quassnoi:我猜目前'Items'表有“运行余额”。然后,他从过去的任意一天(开始日期)开始,从“01/01/2011”到现在(或另一个任意日期),都需要“历史”。 '12/31/2010'是“开始日期”的前一天。 – 2011-04-28 11:49:07

+0

ypercude是正确的。物料表在当前日期中具有库存量(现在仓库中的数量)。我需要按天清点当天的数量。 – awilinsk 2011-04-28 11:53:41

回答

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 

这里假设你有每天每个项目一个事务(这是递归CTESQL 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 
+0

我每天可以为一个项目创建多个记录。我应该在UNION ALL - > COALESCE - > SELECT语句中每天汇总交易吗? – awilinsk 2011-04-28 12:02:57

+0

@Wili:不,只需使用“GROUP BY”。查看帖子更新。 – Quassnoi 2011-04-28 12:03:33

+0

我在运行时出现错误:关键字'with'附近的语法错误。如果此语句是公用表表达式或xmlnamespaces子句,则前面的语句必须以分号结尾。 – awilinsk 2011-04-28 12:35:36

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 [email protected] order by ItemsTrasection.TransDate desc) 
         update #Transection set Transection_Date=(Select top 1 TransDate from ItemsTrasection where [email protected] order by TransDate desc), [email protected] 
          where [email protected] 
        End 
       Else 
        Begin 
         update #Transection set Transection_Date=(Select top 1 TransDate from Items where [email protected]), Quantity=(Select top 1 from Items where [email protected]) 
          where [email protected] 
        End 
     End 
Select * from #Transection 
+0

这是我用Cursor制作的,只要稍作修改,它肯定会适合你。 – Gaurav 2011-04-28 12:42:41

+0

将ItemNumber更改为您的原始列名称,将ItemTransection更改为您的Transection表名称,Quant对您的Quanity和Quantityonhand更改为Quantity_On_Hand列 – Gaurav 2011-04-28 12:43:46

+0

如有任何问题,您可以通过我的电子邮件与我联系[email protected] – Gaurav 2011-04-28 12:48:06

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