SQL - 如果满足使用多个先前列的条件,则滞后获取先前的值

标签 sql sql-server window-functions

我有一个由以下人员创建的表:

CREATE TABLE #test_table 
(
id INT
,EventName VARCHAR(50)
,HomeTeam VARCHAR(25)
,Metric INT
)

INSERT INTO #test_table VALUES
(1, 'Team A vs Team B', 'Team A', 5),
(2, 'Team A vs Team B', 'Team A', 7),
(3, 'Team C vs Team D', 'Team C', 6),
(4, 'Team Z vs Team A', 'Team Z', 8),
(5, 'Team A vs Team B', 'Team A', 9),
(6, 'Team C vs Team D', 'Team C', 3),
(7, 'Team C vs Team D', 'Team C', 1),
(8, 'Team E vs Team F', 'Team E', 2)

结果是:

id  EventName           HomeTeam    Metric
------------------------------------------
1   Team A vs Team B    Team A      5
2   Team A vs Team B    Team A      7
3   Team C vs Team D    Team C      6
4   Team Z vs Team A    Team Z      8
5   Team A vs Team B    Team A      9
6   Team C vs Team D    Team C      3
7   Team C vs Team D    Team C      1
8   Team E vs Team F    Team E      2

A 想要计算一个新列 PreviousMetricN,其中 N 可以是 1、2、3 ...,它显示 Metric 的先前值,但前提是HomeTeam 参与了之前的事件。例如:

id  EventName           HomeTeam    Metric  PreviousMetric1 PreviousMetric2
------------------------------------------------------------------------
1   Team A vs Team B    Team A      5       NULL            NULL
2   Team A vs Team B    Team A      7       5               NULL
3   Team C vs Team D    Team C      6       NULL            NULL
4   Team Z vs Team A    Team Z      8       NULL            NULL
5   Team A vs Team B    Team A      9       8               7
6   Team C vs Team D    Team C      3       6               NULL
7   Team C vs Team D    Team C      1       3               6
8   Team E vs Team F    Team E      2       NULL            NULL

我一直在尝试 LAG 的变体,在 PARTITION BY 子句中使用新的分组变量,例如

LAG(Metric) OVER(Partition by (CASE WHEN CHARINDEX(HomeTeam, EventName)>0 THEN 1 ELSE 0 END) ORDER BY id)

但没有成功。如何做到这一点?

编辑: 我也在这里问过 Pandas 这个问题: Pandas shift - get previous value if multiple conditions satisfied

最佳答案

我在这里看不到使用窗口函数和单次扫描表的答案。我们可以按以下方式在单次扫描中执行此查询:

让我们假设您在另一列中有 AwayTeam

If you don't have this yet and you wanted to parse it out of EventData:
We could use: SUBSTRING(EventData, CHARINDEX(' vs ', EventData) + 4)
I urge you to follow proper normalization and create this as a proper column in your table.

我们的算法是这样运行的:

  1. 使用 CROSS APPLY
  2. 将两个团队相乘(逆轴)作为单独的行
  3. 使用 LAG 计算之前的 Metric,按合并的 Team 列进行分区
  4. 过滤掉加倍的行,这样我们每个原始行只得到一行
SELECT id, HomeTeam, AwayTeam, Metric, Prev1, Prev2, Prev3
FROM (

  SELECT *
    ,Prev1 = LAG(Metric, 1) OVER (PARTITION BY v.Team ORDER BY id)
    ,Prev2 = LAG(Metric, 2) OVER (PARTITION BY v.Team ORDER BY id)
    ,Prev3 = LAG(Metric, 3) OVER (PARTITION BY v.Team ORDER BY id)
    -- more of these ......
  FROM test_table
  CROSS APPLY (VALUES (HomeTeam, 1),(AwayTeam, 0)) AS v(Team,IsHome)
) AS t

WHERE IsHome = 1
-- ORDER BY id  --if necessary

重要的是,我们可以在不使用多种不同的排序、分区或排序,并且不使用自连接的情况下做到这一点。只需一次扫描。

结果:

<表类="s-表"> <头> id 主队 客队 指标 上一篇 上一个 上一页 <正文> 1 A队 B队 5 (空) (空) (空) 2 A队 B队 7 5 (空) (空) 3 C队 D队 6 (空) (空) (空) 4 Z队 A队 8 (空) (空) (空) 5 A队 B队 9 8 7 5 6 C队 D队 3 6 (空) (空) 7 C队 D队 1 3 6 (空) 8 E队 F队 2 (空) (空) (空)

关于SQL - 如果满足使用多个先前列的条件,则滞后获取先前的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65905861/

相关文章:

mysql - 写一个基于三个表的sql连接

sql - 在 MS sql server 2005+ 中查找最大可能日期

sql-server - 无法在 Windows 8.1 上安装 LocalDB

json - Postgres 获取 json 计数

sql - 在聚合函数 SQL Server 中选择 N 行

php - 按时间顺序从不同表中获取帖子

mysql查询语法错误,mysql8.0之后UNION之前不能再用LIMIT了?

php - SQL - 将多个文本记录合并为一个

sql-server - 为什么即使在备份之后也无法缩小事务日志文件?

sql - 使用 over 子句运行总计