在SQL中计算“上一个”行的有效方法是什么?

时间:2019-02-08 16:00:07

标签: sql-server tsql

很难用短语表达这个标题。

我有一个数据表,其中每个发票都包含一行。例如:

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

我需要添加另一列,该列计算每个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   |

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

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

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

所以;有没有更有效的方法来实现这一目标,或者我只是把它吸了呢?

编辑:我最初发布此内容时不需要所有Something = 1所在的行。 Mea culpa-我急着问。不幸的是,我认为这意味着我不能使用row_number() over (partition by [Customer Key])

2 个答案:

答案 0 :(得分:5)

如果您不使用2012,则可以使用ROW_NUMBER

ROW_NUMBER() OVER (PARTITION BY CustomerKey ORDER BY [Date]) - 1 AS Count

答案 1 :(得分:4)

假设,您正在使用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]

在需要新逻辑之前的旧答案:

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