SQL查询需求:获取每个ID对应Time3列中第二时间的完整行数据
问题描述
我刚接触SQL。
我有如下结构的数据:
| ID | Time 1 | Time 2 | Time 3 |
|---|---|---|---|
| 1 | 2023/01/01 00:23 | 2023/01/01 00:26 | 2023/01/01 00:29 |
| 1 | 2023/01/01 00:23 | 2023/01/01 00:27 | 2023/01/01 00:28 |
| 2 | 2023/01/01 04:51 | 2023/01/01 04:55 | 2023/01/01 05:10 |
| 2 | 2023/01/01 12:31 | 2023/01/01 12:33 | 2023/01/01 12:59 |
| 2 | 2023/01/01 12:31 | 2023/01/01 12:43 | 2023/01/01 12:51 |
| 3 | 2023/01/01 12:36 | 2023/01/01 12:37 | 2023/01/01 12:39 |
我想要获取每个ID对应的Time 3列中第二大时间所在的完整行数据,目标行已在下表高亮标注:
| ID | Time 1 | Time 2 | Time 3 |
|---|---|---|---|
| 1 | 2023/01/01 00:23 | 2023/01/01 00:26 | 2023/01/01 00:29 |
| 1 | 2023/01/01 00:23 | 2023/01/01 00:27 | 2023/01/01 00:28 |
| 2 | 2023/01/01 04:51 | 2023/01/01 04:55 | 2023/01/01 05:10 |
| 2 | 2023/01/01 12:31 | 2023/01/01 12:33 | 2023/01/01 12:59 |
| 2 | 2023/01/01 12:31 | 2023/01/01 12:43 | 2023/01/01 12:51 |
| 3 | 2023/01/01 12:36 | 2023/01/01 12:37 | 2023/01/01 12:39 |
我目前尝试提取每个时间戳的第二个值,但结果不符合预期:
| ID | TimeStamp 1 | TimeStamp 2 | TimeStamp 3 |
|---|---|---|---|
| 1 | 2023/01/01 00:23 | 2023/01/01 00:26 | 2023/01/01 00:29 |
| 1 | 2023/01/01 00:23 | 2023/01/01 00:27 | 2023/01/01 00:28 |
| 2 | 2023/01/01 04:51 | 2023/01/01 04:55 | 2023/01/01 05:10 |
| 2 | 2023/01/01 12:31 | 2023/01/01 12:33 | 2023/01/01 12:59 |
| 2 | 2023/01/01 12:33 | 2023/01/01 12:43 | 2023/01/01 12:51 |
| 3 | 2023/01/01 12:36 | 2023/01/01 12:37 | 2023/01/01 15:39 |
另外,ID下没有每个事件的唯一编号。
解决方案
用窗口函数ROW_NUMBER()就能解决这个问题,核心思路是按ID分组,给每个ID下的行按Time 3排序后编号,再筛选编号为2的行。
代码示例
-- 现代SQL通用的CTE写法 WITH ranked_rows AS ( SELECT *, -- 按ID分组,Time3降序排序并分配序号 ROW_NUMBER() OVER (PARTITION BY ID ORDER BY `Time 3` DESC) AS row_num FROM your_table ) SELECT ID, `Time 1`, `Time 2`, `Time 3` FROM ranked_rows WHERE row_num = 2;
如果你的数据库不支持CTE(比如MySQL 5.x版本),改用子查询:
SELECT ID, `Time 1`, `Time 2`, `Time 3` FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY `Time 3` DESC) AS row_num FROM your_table ) t WHERE row_num = 2;
关键细节
PARTITION BY ID:把数据按ID拆分成独立组,确保每个ID内单独排序ORDER BYTime 3DESC:按Time3从大到小排序,第二大的时间对应序号2;如果要第二小的时间,改成ASC即可- 字段名包含空格,需用反引号(MySQL)或方括号(SQL Server)包裹,避免语法错误
- 如果多个行的Time3值并列第二,
ROW_NUMBER()只会返回其中一行;若要保留所有并列行,替换为DENSE_RANK()函数
内容的提问来源于stack exchange,提问作者925475687465
相关产品推荐
相关产品推荐

