SQL 按交替行组进行分区

SQL Partition By alternating groups of rows

我有一个数据 table 看起来像这样。

|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

(为了这个例子的目的,我们假设数量在所有各方之间平均分配)

使用 sql RANK()DENSE_RANK()ROW_NUMBER() 窗口,我正在尝试制定一个查询,它将给我这个分组。一旦我能够获得此分组,我就应该能够将数据重新加入自身并最终确定我的每个目的地收到了多少。

这是在 SQL2008 上。

使用 common table expression, outer apply(), and dense_rank()

的组合

注意:我将 Key 列更改为 tKey,这样我就不必在其周围使用方括号。

;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       |
+------+-------+-----------------+----------+-------------+----------+