2011-04-28 78 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