2017-02-23 63 views
3

我有一個類似於這樣的數據表。SQL分區通過交替組的行

|Key|LotId|TransactionType|Quantity|Destination 
|1 |A |Transform  |NULL |Foo 
|2 |A |Transform  |NULL |Bar 
|3 |A |Consume  |100  |NULL 
|4 |B |Transform  |NULL |Bob 
|5 |B |Transform  |NULL |Fred 
|6 |B |Consume  |75  |NULL 
|7 |B |Consume  |50  |NULL 
|8 |B |Transform  |NULL |Sally 
|9 |B |Transform  |NULL |Fred 
|10 |B |Consume  |60  |NULL 
|11 |C |Transform  |NULL |Bar 
|12 |C |Transform  |NULL |Fred 
|13 |C |Consume  |25  |NULL 

轉換線告訴我我的數量在哪裏,消費線告訴我使用了多少數量。消費行適用於該LotId的所有先前變換行,直到先前的LotId或者與前一個變換&消耗分組相同的LotId。並且要添加一個扳手,組內變換和消耗線的數量是可變的。我爲我工作的一件事是,變形線先來,然後消耗,下次遇到變形我知道一個新的分組已經開始。

|Key|LotId|TransactionType|Quantity|Destination|Grouping 
|1 |A |Transform  |NULL |Foo  |A1 
|2 |A |Transform  |NULL |Bar  |A1 
|3 |A |Consume  |100  |NULL  |A1 
--------------------------------------------------------- 
|4 |B |Transform  |NULL |Bob  |B1 
|5 |B |Transform  |NULL |Fred  |B1 
|6 |B |Consume  |75  |NULL  |B1 
|7 |B |Consume  |50  |NULL  |B1 
--------------------------------------------------------- 
|8 |B |Transform  |NULL |Sally  |B2 
|9 |B |Transform  |NULL |Fred  |B2 
|10 |B |Consume  |60  |NULL  |B2 
--------------------------------------------------------- 
|11 |C |Transform  |NULL |Bar  |C1 
|12 |C |Transform  |NULL |Fred  |C1 
|13 |C |Consume  |25  |NULL  |C1 

(在這個例子的目的,我們只能假定量在所有各方平分)

  • A1組中的有富&之間100分吧
  • B1組Bob和Fred之間有125次拆分
  • B2組有60次拆分,Sally & Fred
  • C1組有25次拆分間欄和弗雷德

使用SQL RANK()DENSE_RANK(),& ROW_NUMBER()窗口,我試圖找出一個查詢,這將給我這個分組。一旦我能夠獲得這個分組,我就可以將數據加入自己,並最終確定每個目標收到的數量。

這是在SQL2008上。

+0

是關鍵,其可以用來申請的順序依次價值? – scsimon

+0

是的,他們的鑰匙是auto_ident。在這裏,我只是把它們全部順序放在一起,因爲它很容易但是我可以通過該鍵值來命令將記錄插入到表中的序列。 –

+0

數據中的內容表示從B1到B2的變化? –

回答

2

使用的common table expressionouter apply()組合,並dense_rank()

注:我改變了列KeytKey所以我也不會用它周圍的方括號。

;with cte as (
    select * 
    , PrevTransactionType=isnull(x.Prev_TransactionType,'Consume') 
    from t 
    outer apply (
     select top 1 
     Prev_TransactionType = TransactionType 
     from t as i 
     where i.tKey < t.tKey 
     order by i.tKey desc 
    ) as x 
) 
select t.tKey, t.LotId, t.TransactionType, t.Quantity, t.Destination 
, Grouping = LotId + convert(varchar(10),dense_rank() over (
    partition by LotId 
    order by GroupNumber 
    ) 
) 
from cte as t 
outer apply (
    select top 1 
    GroupNumber = i.tKey 
    from cte as i 
    where i.tKey <= t.tKey 
     and i.TransactionType = 'Transform' 
     and i.PrevTransactionType = 'Consume' 
    order by i.tKey desc 
    ) x 

測試設置:http://rextester.com/LWV40248

結果:

+------+-------+-----------------+----------+-------------+----------+ 
| tKey | LotId | TransactionType | Quantity | Destination | Grouping | 
+------+-------+-----------------+----------+-------------+----------+ 
| 1 | A  | Transform  | NULL  | Foo   | A1  | 
| 2 | A  | Transform  | NULL  | Bar   | A1  | 
| 3 | A  | Consume   | 100  | NULL  | A1  | 
| 4 | B  | Transform  | NULL  | Bob   | B1  | 
| 5 | B  | Transform  | NULL  | Fred  | B1  | 
| 6 | B  | Consume   | 75  | NULL  | B1  | 
| 7 | B  | Consume   | 50  | NULL  | B1  | 
| 8 | B  | Transform  | NULL  | Sally  | B2  | 
| 9 | B  | Transform  | NULL  | Fred  | B2  | 
| 10 | B  | Consume   | 60  | NULL  | B2  | 
| 11 | C  | Transform  | NULL  | Bar   | C1  | 
| 12 | C  | Transform  | NULL  | Fred  | C1  | 
| 13 | C  | Consume   | 25  | NULL  | C1  | 
+------+-------+-----------------+----------+-------------+----------+ 
+0

真棒的答案,我將需要驗證,但我不相信,在2008年可用的LAG。 –

+0

@NASlacker哎唷,你是對的。我會用'apply()'來代替它。 - 現在更新。 – SqlZim

+0

這個很好用!謝謝! –

1
CREATE TABLE #KeyWithRowNum (
    Key INT NOT NULL 
     UNIQUE, 
    LotId INT NOT NULL, 
    RowNum INT NOT NULL, 
     PRIMARY KEY (RowNum, LotId), 
    TransactionType VARCHAR(50) NOT NULL -- Replace current data type and max. length 
) 
SELECT j.Key, j.LotId, ROW_NUMBER() OVER(PARTITION BY j.LotId ORDER BY j.Key) AS RowNum, TransactionType 
FROM dbo.CocoJambo j; 

WITH CteRecursion 
AS (
SELECT crt.Key, crt.LotId, crt.RowNum, crt.TransactionType, 1 AS GroupId 
FROM #KeyWithRowNum crt 
WHERE RowNum = 1 
UNION ALL 
SELECT crt.Key, crt.LotId, crt.RowNum, crt.TransactionType, CASE WHEN crt.TransactionType = 'Transform' AND (prev.TransactionType = 'Consume' OR prev.TransactionType IS NULL) THEN prev.GroupId + 1 ELSE prev.GroupId END AS GroupId 
FROM #KeyWithRowNum crt 
INNER JOIN CteRecursion prev ON crt.LotId = prev.LotId AND crt.RowNum - 1 = prev.RowNum 
) 
SELECT *, LotId + LTRIM(x.GroupId) AS Grouping 
FROM CteRecursion x 
-- OPTION(MAXRECURSION 32767) -- Default is 100 
+0

我沒有測試過這個查詢。 –