基于列值筛选表数据:获取Bsp到Esp之间记录的SQL查询需求
筛选'Bsp'之后到'Esp'为止的SQL查询方案
假设你的数据表名为your_table,且ID字段代表记录的先后顺序(用于确定'Bsp'和'Esp'的区间范围),以下提供两种实现方案:
方案一:支持窗口函数的数据库(MySQL 8+、PostgreSQL、SQL Server等)
使用窗口函数标记每个行所属的区间,逻辑清晰且性能较好:
WITH marked_rows AS ( SELECT ID, col1, col2, -- 累计统计到当前行为止的'Bsp'出现次数 SUM(CASE WHEN col2 = 'Bsp' THEN 1 ELSE 0 END) OVER (ORDER BY ID) AS bsp_count, -- 累计统计到当前行前一行为止的'Esp'出现次数 SUM(CASE WHEN col2 = 'Esp' THEN 1 ELSE 0 END) OVER (ORDER BY ID ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS esp_count FROM your_table ) SELECT ID, col1, col2 FROM marked_rows -- 只保留处于"Bsp已出现但对应Esp未出现"的区间内的行 WHERE bsp_count > esp_count -- 排除'Bsp'本身的行(根据你的期望结果) AND col2 != 'Bsp';
逻辑说明
bsp_count记录从表开头到当前行,一共出现了多少次'Bsp',用于标记当前处于第几个"Bsp-Esp"区间。esp_count记录从表开头到当前行的前一行,一共出现了多少次'Esp',用于标记当前区间是否已经结束。- 当
bsp_count > esp_count时,说明当前行处于某个未结束的"Bsp-Esp"区间内,再排除掉'Bsp'本身的行,就得到目标结果。
方案二:不支持窗口函数的老版本数据库(如MySQL 5.x)
使用用户变量跟踪区间状态,实现相同逻辑:
SELECT ID, col1, col2 FROM ( SELECT ID, col1, col2, -- 用变量跟踪当前是否处于"Bsp之后、Esp之前"的区间 @in_range := CASE WHEN col2 = 'Bsp' THEN 1 -- 遇到Bsp,开启区间 WHEN col2 = 'Esp' THEN 0 -- 遇到Esp,关闭区间 ELSE @in_range -- 非边界行,保持区间状态 END AS in_range FROM your_table -- 初始化变量,初始状态为未进入区间 CROSS JOIN (SELECT @in_range := 0) AS init_vars -- 必须按ID排序,保证区间判断的顺序正确 ORDER BY ID ) AS temp_rows -- 保留区间内的行,以及Esp本身(区间结束行),同时排除Bsp本身 WHERE (in_range = 1 OR col2 = 'Esp') AND col2 != 'Bsp';
逻辑说明
- 初始化变量
@in_range为0,表示初始未进入任何区间。 - 按ID顺序遍历每行:
- 遇到'Bsp'时,将
@in_range设为1,标记进入区间。 - 遇到'Esp'时,将
@in_range设为0,标记区间结束,但Esp本身需要保留。 - 其他行保持当前
@in_range的状态。
- 遇到'Bsp'时,将
- 最后筛选出区间内的行(
in_range=1)或者'Esp'行,同时排除'Bsp'行,得到目标结果。
内容的提问来源于stack exchange,提问作者Merlin
相关产品推荐
相关产品推荐

