如何在SQL中对两列执行Pivot操作?求技术帮助
同时处理计划日期和实际日期的SQL透视方案
核心思路是先把**计划日期(plan_date)和实际日期(actual_date)**这两列转成行数据(逆透视),统一成「日期类型+日期值」的结构,再一次性完成透视操作,避免单独处理两列的麻烦。
示例场景说明
假设你的原始数据表project_data结构如下(贴合报表常见场景):
| project_id | task_name | plan_date | actual_date | completion_rate |
|---|---|---|---|---|
| 1 | 需求分析 | 2024-01-10 | 2024-01-12 | 100% |
| 1 | 开发 | 2024-01-15 | 2024-01-18 | 90% |
| 2 | 测试 | 2024-01-20 | 2024-01-21 | 100% |
方案1:适用于支持UNPIVOT的数据库(如SQL Server)
第一步:逆透视(UNPIVOT)
先把plan_date和actual_date拆成两行,标记日期类型:
SELECT project_id, task_name, date_type, date_value, completion_rate FROM project_data UNPIVOT ( date_value FOR date_type IN (plan_date, actual_date) ) AS unpvt;
执行后会得到结构统一的行数据,每条原始记录拆分为「计划日期」「实际日期」两行。
第二步:透视生成报表
根据报表需求选择不同的聚合逻辑:
需求A:按日期统计计划/实际任务数量
SELECT date_value AS 日期, ISNULL([plan_date], 0) AS 计划任务数, ISNULL([actual_date], 0) AS 实际完成任务数 FROM ( SELECT date_value, date_type FROM project_data UNPIVOT ( date_value FOR date_type IN (plan_date, actual_date) ) AS unpvt ) AS src PIVOT ( COUNT(date_type) FOR date_type IN ([plan_date], [actual_date]) ) AS pvt ORDER BY date_value;
需求B:按任务展示计划/实际日期及完成率
SELECT task_name AS 任务名称, [plan_date] AS 计划日期, [actual_date] AS 实际日期, completion_rate AS 完成率 FROM ( SELECT task_name, date_type, date_value, completion_rate FROM project_data UNPIVOT ( date_value FOR date_type IN (plan_date, actual_date) ) AS unpvt ) AS src PIVOT ( MAX(date_value) FOR date_type IN ([plan_date], [actual_date]) ) AS pvt;
方案2:适用于不支持UNPIVOT的数据库(如MySQL)
用UNION ALL替代逆透视,再用CASE WHEN实现透视:
需求A:按日期统计计划/实际任务数量
SELECT date_value AS 日期, SUM(CASE WHEN date_type = 'plan_date' THEN 1 ELSE 0 END) AS 计划任务数, SUM(CASE WHEN date_type = 'actual_date' THEN 1 ELSE 0 END) AS 实际完成任务数 FROM ( SELECT plan_date AS date_value, 'plan_date' AS date_type FROM project_data UNION ALL SELECT actual_date AS date_value, 'actual_date' AS date_type FROM project_data ) AS src WHERE date_value IS NOT NULL GROUP BY date_value ORDER BY date_value;
需求B:按任务展示计划/实际日期及完成率
SELECT task_name AS 任务名称, MAX(CASE WHEN date_type = 'plan_date' THEN date_value END) AS 计划日期, MAX(CASE WHEN date_type = 'actual_date' THEN date_value END) AS 实际日期, MAX(completion_rate) AS 完成率 FROM ( SELECT task_name, 'plan_date' AS date_type, plan_date AS date_value, completion_rate FROM project_data UNION ALL SELECT task_name, 'actual_date' AS date_type, actual_date AS date_value, completion_rate FROM project_data ) AS src GROUP BY task_name;
注意事项
- 聚合函数选择:取日期值用
MAX/MIN,计数用COUNT,数值求和/求平均用SUM/AVG - 空值处理:用
ISNULL(SQL Server)或COALESCE(通用)替换NULL,保证报表美观 - 字段适配:如果你的表结构和示例不同,只需替换对应的表名、字段名即可
内容的提问来源于stack exchange,提问作者Tuan La
相关产品推荐
相关产品推荐

