在SQL中计算"之前"行的有效方法是什么?

Dan*_*lly 3 t-sql sql-server

很难说出这一个的标题.

我有一个数据表,每个发票包含一行.例如:

| Invoice ID | Customer Key |    Date    | Value | Something |
| ---------- | ------------ | ---------- | ------| --------- |
|     1      |     A        | 08/02/2019 |  100  |     1     |
|     2      |     B        | 07/02/2019 |  14   |     0     |
|     3      |     A        | 06/02/2019 |  234  |     1     |
|     4      |     A        | 05/02/2019 |  74   |     1     |
|     5      |     B        | 04/02/2019 |  11   |     1     |
|     6      |     A        | 03/02/2019 |  12   |     0     |
Run Code Online (Sandbox Code Playgroud)

我需要添加另一列来计算每个CustomerKey的前一行数,但仅当"Something"等于1时才会这样,以便它返回:

| Invoice ID | Customer Key |    Date    | Value | Something | Count |
| ---------- | ------------ | ---------- | ------| --------- | ----- |
|     1      |     A        | 08/02/2019 |  100  |     1     |   2   |
|     2      |     B        | 07/02/2019 |  14   |     0     |   1   |
|     3      |     A        | 06/02/2019 |  234  |     1     |   1   |
|     4      |     A        | 05/02/2019 |  74   |     1     |   0   |
|     5      |     B        | 04/02/2019 |  11   |     1     |   0   |
|     6      |     A        | 03/02/2019 |  12   |     0     |   0   |
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用这样的CTE来做到这一点......

(
select
    count(*)
from table
where
    [Customer Key] = t.[Customer Key]
    and [Date] < t.[Date]
    and Something = 1
)
Run Code Online (Sandbox Code Playgroud)

但是我有很多数据,这很慢.我知道我也可以使用交叉应用来实现同样的目的,但据我所知,这并不比仅仅使用CTE更好.

所以; 是否有更有效的方法来实现这一目标,还是我只是吮吸它?

编辑:我最初发布这个没有要求只Something = 1计算行数.Mea culpa - 我赶紧问它.不幸的是,我认为这意味着我无法使用row_number() over (partition by [Customer Key])

use*_*983 5

假设您使用的是 SQL Server 2012+,您可以使用窗口函数:

COUNT(CASE WHEN Something = 1 THEN CustomerKey END) OVER (PARTITION BY CustomerKey ORDER BY [Date]
                                                          ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) -1 AS [Count]
Run Code Online (Sandbox Code Playgroud)

新的所需逻辑之前的旧答案:

COUNT(CustomerKey) OVER (PARTITION BY CustomerKey ORDER BY [Date]
                         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) -1 AS [Count]
Run Code Online (Sandbox Code Playgroud)


Lui*_*res 5

如果您没有使用2012,则替代方法是使用ROW_NUMBER

ROW_NUMBER() OVER (PARTITION BY CustomerKey ORDER BY [Date]) - 1 AS Count
Run Code Online (Sandbox Code Playgroud)