2017-02-23 69 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

我没有测试过这个查询。 –