如何获取emp表中health字段首次记录后发生变更的emp_id?
现有SQL问题分析
你当前写的查询语句存在两个核心逻辑错误,无法满足需求:
count(e.health)统计时会自动忽略health为null的行,若员工健康状态从非空变更为null,该计数不会增长,会漏判符合条件的员工- 现有逻辑仅统计非空健康记录数大于1的员工,没有和首条记录做对比,若员工多次录入相同的健康值(比如多次记录都是
heart),会被误判为发生了变更
正确查询方案
核心逻辑为:先提取每个员工最早的健康状态作为基准,再判断该员工是否存在任意一条晚于首条的记录和基准值不同。
方案1:窗口函数实现(兼容性较好,大部分SQL引擎支持)
SELECT DISTINCT emp_id FROM ( SELECT emp_id, health, -- 取每个员工最早的health值作为对比基准 FIRST_VALUE(health) OVER (PARTITION BY emp_id ORDER BY modification_date ASC) AS first_health, -- 取每个员工的记录排序编号,用于排除只有1条记录的员工 ROW_NUMBER() OVER (PARTITION BY emp_id ORDER BY modification_date ASC) AS rn FROM emp ) t WHERE rn > 1 -- 排除仅1条记录、没有变更可能的员工 AND ( health <> first_health OR (health IS NULL AND first_health IS NOT NULL) OR (health IS NOT NULL AND first_health IS NULL) )
如果你使用的SQL引擎支持IS NOT DISTINCT FROM语法,可以简化条件判断:
WHERE rn > 1 AND health IS NOT DISTINCT FROM first_health = FALSE
方案2:子查询关联实现(适合不支持窗口函数的低版本SQL引擎)
SELECT DISTINCT e.emp_id FROM emp e INNER JOIN ( -- 先查询每个员工首条记录的健康状态 SELECT e1.emp_id, e1.health AS first_health, MIN(e1.modification_date) AS first_modify_date FROM emp e1 GROUP BY e1.emp_id, e1.health ) t ON e.emp_id = t.emp_id WHERE e.modification_date > t.first_modify_date AND ( e.health <> t.first_health OR (e.health IS NULL AND t.first_health IS NOT NULL) OR (e.health IS NOT NULL AND t.first_health IS NULL) )
内容的提问来源于stack exchange,提问作者rko
相关产品推荐
相关产品推荐

