SQL实现累计求和与累计计数 统计患者治疗疗程
治疗疗程划分逻辑的SQL实现方案
背景
我正在搭建患者治疗疗程划分规则,目前已经通过Python完成计算输出,需要将同等逻辑迁移到SQL环境实现。
样例数据
| PatientID | SessionDate | Next_date | diff | courses | Coursenum | course_Count | Total Session |
|---|---|---|---|---|---|---|---|
| 10000 | 12/13/2012 | NULL | 1.1 | start | 1 | 1 | 10 |
| 10000 | 12/14/2012 | 12/13/2012 | 1 | existing | 1 | 2 | 10 |
| 10000 | 12/14/2012 | 12/14/2012 | 0 | existing | 1 | 3 | 10 |
| 10000 | 12/17/2012 | 12/14/2012 | 3 | existing | 1 | 4 | 10 |
| 10000 | 12/18/2012 | 12/17/2012 | 1 | existing | 1 | 5 | 10 |
| 10000 | 12/19/2012 | 12/18/2012 | 1 | existing | 1 | 6 | 10 |
| 10000 | 12/21/2012 | 12/19/2012 | 2 | existing | 1 | 7 | 10 |
| 10000 | 12/21/2012 | 12/21/2012 | 0 | existing | 1 | 8 | 10 |
| 10000 | 12/22/2012 | 12/21/2012 | 1 | existing | 1 | 9 | 10 |
| 10000 | 12/24/2012 | 12/22/2012 | 2 | existing | 1 | 10 | 10 |
| 10000 | 9/17/2015 | 1/25/2013 | 965 | start | 2 | 1 | 20 |
| 10000 | 9/18/2015 | 9/17/2015 | 1 | existing | 2 | 2 | 20 |
| 10000 | 9/21/2015 | 9/18/2015 | 3 | existing | 2 | 3 | 20 |
| 10000 | 9/22/2015 | 9/21/2015 | 1 | existing | 2 | 4 | 20 |
| 10000 | 9/23/2015 | 9/22/2015 | 1 | existing | 2 | 5 | 20 |
| 10000 | 9/25/2015 | 9/23/2015 | 2 | existing | 2 | 6 | 20 |
| 10000 | 9/28/2015 | 9/25/2015 | 3 | existing | 2 | 7 | 20 |
| 10000 | 9/29/2015 | 9/28/2015 | 1 | existing | 2 | 8 | 20 |
| 10000 | 9/30/2015 | 9/29/2015 | 1 | existing | 2 | 9 | 20 |
| 10000 | 10/2/2015 | 9/30/2015 | 2 | existing | 2 | 10 | 20 |
| 10000 | 10/5/2015 | 10/2/2015 | 3 | existing | 2 | 11 | 20 |
| 10000 | 10/6/2015 | 10/5/2015 | 1 | existing | 2 | 12 | 20 |
| 10000 | 10/7/2015 | 10/6/2015 | 1 | existing | 2 | 13 | 20 |
| 10000 | 10/9/2015 | 10/7/2015 | 2 | existing | 2 | 14 | 20 |
| 10000 | 10/12/2015 | 10/9/2015 | 3 | existing | 2 | 15 | 20 |
| 10000 | 10/13/2015 | 10/12/2015 | 1 | existing | 2 | 16 | 20 |
| 10000 | 10/14/2015 | 10/13/2015 | 1 | existing | 2 | 17 | 20 |
| 10000 | 10/16/2015 | 10/14/2015 | 2 | existing | 2 | 18 | 20 |
| 10000 | 10/19/2015 | 10/16/2015 | 3 | existing | 2 | 19 | 20 |
| 10000 | 10/20/2015 | 10/19/2015 | 1 | existing | 2 | 20 | 20 |
*说明:diff列中的1.1是NULL值的占位符,无实际业务含义。
现有Python实现逻辑
实现代码如下:
sessions['Coursenum']=(sessions.courses.eq('start')).cumsum() sessions['course_count']=sessions.groupby(['Coursenum']).cumcount()+1 sessions['TotalSessions']=sessions.groupby('Coursenum')['course_count'].transform('max')
核心计算逻辑:
- 识别
courses列值为start的疗程起始记录,通过累计求和生成疗程编号Coursenum - 按
Coursenum分组,对组内记录按顺序累计计数,生成单疗程内的会话序号course_Count - 按
Coursenum分组取组内会话序号最大值,得到单疗程总会话数Total Session
SQL实现方案
基于标准ANSI窗口函数编写,兼容MySQL 8.0+、PostgreSQL、SQL Server、BigQuery等支持窗口函数的数据库引擎:
WITH step1 AS ( SELECT *, -- 对齐Python cumsum逻辑,累计start标记生成疗程编号 SUM(CASE WHEN courses = 'start' THEN 1 ELSE 0 END) OVER ( ORDER BY PatientID, SessionDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS Coursenum FROM sessions ), step2 AS ( SELECT *, -- 对齐分组cumcount+1逻辑,生成疗程内会话序号 ROW_NUMBER() OVER ( PARTITION BY PatientID, Coursenum ORDER BY SessionDate ) AS course_Count FROM step1 ) SELECT *, -- 对齐分组取max逻辑,计算单疗程总会话数 MAX(course_Count) OVER (PARTITION BY PatientID, Coursenum) AS `Total Session` FROM step2;
注意事项
- 涉及多患者数据时,所有窗口计算必须携带
PatientID作为分区字段,避免跨患者数据串算 - 若同一患者同一天存在多条就诊记录,建议在窗口的
ORDER BY子句中补充唯一排序字段(如就诊记录自增ID、精确到时分秒的就诊时间),保证记录排序和Python处理时的顺序完全一致,避免序号错位
内容的提问来源于stack exchange,提问作者PKN
相关产品推荐
相关产品推荐

