基于CTE统计各ID工作日与非工作日天数的技术咨询
问题解答
你的实现思路没问题,但有个小语法错误,而且可以更高效。
你的实现修正与可行性
你把宽表转成单行长表再统计的逻辑是成立的,但代码里第一个GROUP BY shop_id应该改成GROUP BY id(原CTE里根本没shop_id字段),修正后就能正常跑。不过手动写VALUES把宽表拆成长表的方式太死板——数据变多或者星期列调整时,手动改很容易错,也麻烦。
更优的实现方式(直接基于原CTE处理)
不用手动拆表,直接通过列转行的方式处理原宽表,灵活又好维护:
方式1:用UNNEST(PostgreSQL等支持数组的数据库)
WITH a(id, MON, TUE, WED, THUR, FRI, SAT, SUN) AS ( VALUES (1,0,0,1,1,1,0,0),(2,1,1,1,1,0,0,0) ) SELECT id, CASE WHEN day_name IN ('MON','TUE','WED','THUR','FRI') THEN 'Working' ELSE 'Non-working' END AS day_type, SUM(day_value) AS "COUNT" FROM a CROSS JOIN UNNEST( ARRAY['MON','TUE','WED','THUR','FRI','SAT','SUN'], ARRAY[MON,TUE,WED,THUR,FRI,SAT,SUN] ) AS days(day_name, day_value) GROUP BY id, day_type ORDER BY id, day_type;
方式2:通用SQL(兼容所有主流数据库)
如果你的数据库不支持UNNEST,用UNION ALL拆列就行:
WITH a(id, MON, TUE, WED, THUR, FRI, SAT, SUN) AS ( VALUES (1,0,0,1,1,1,0,0),(2,1,1,1,1,0,0,0) ) -- 统计工作日 SELECT id, 'Working' AS day_type, SUM(day_value) AS "COUNT" FROM ( SELECT id, MON AS day_value FROM a UNION ALL SELECT id, TUE FROM a UNION ALL SELECT id, WED FROM a UNION ALL SELECT id, THUR FROM a UNION ALL SELECT id, FRI FROM a ) working_days GROUP BY id UNION ALL -- 统计非工作日 SELECT id, 'Non-working' AS day_type, SUM(day_value) AS "COUNT" FROM ( SELECT id, SAT AS day_value FROM a UNION ALL SELECT id, SUN FROM a ) non_working_days GROUP BY id ORDER BY id, day_type;
两种方案对比
- 你的修正后实现:逻辑简单,但扩展性差,只适合小数据量临时用。
- 推荐方案:自动列转行,不用手动维护数据,修改或扩展星期列时只需调整对应部分,更适合长期使用。
内容的提问来源于stack exchange,提问作者Ms.kitty
相关产品推荐
相关产品推荐

