基于多Status列布尔值生成统一状态字段的SQL实现
Oracle Status字段转换方案及ORA-00905错误解决
问题背景
现有表包含DCID、Status及14个字符类型的Status1至Status14字段(存储true/false),需导出仅含ID(对应DCID)和StatusNew的结果,规则如下:
- 若
Status1至Status14全为false,StatusNew显示None - 仅一个
Status列为true,显示对应列名 - 多个
Status列为true,显示Multiple
同时需解决SQL执行时出现的ORA-00905: missing keyword错误,并提供高效实现方案。
ORA-00905错误排查
该错误通常由SQL语法缺失关键字导致,常见场景:
CASE语句未正确闭合(缺少END)UNPIVOT/PIVOT语法错误(如IN子句格式错误)- 关键字拼写错误(如将
FROM写成FRM) - 子查询未加括号包裹
高效实现方案
方案一:行内计数+CASE判断
通过计算每行中true的数量,再分支判断结果,适合小数据量场景,执行效率高:
SELECT DCID AS ID, CASE WHEN true_count = 0 THEN 'None' WHEN true_count = 1 THEN CASE WHEN Status1 = 'true' THEN 'Status1' WHEN Status2 = 'true' THEN 'Status2' WHEN Status3 = 'true' THEN 'Status3' WHEN Status4 = 'true' THEN 'Status4' WHEN Status5 = 'true' THEN 'Status5' WHEN Status6 = 'true' THEN 'Status6' WHEN Status7 = 'true' THEN 'Status7' WHEN Status8 = 'true' THEN 'Status8' WHEN Status9 = 'true' THEN 'Status9' WHEN Status10 = 'true' THEN 'Status10' WHEN Status11 = 'true' THEN 'Status11' WHEN Status12 = 'true' THEN 'Status12' WHEN Status13 = 'true' THEN 'Status13' WHEN Status14 = 'true' THEN 'Status14' END ELSE 'Multiple' END AS StatusNew FROM ( SELECT DCID, (CASE WHEN Status1 = 'true' THEN 1 ELSE 0 END) + (CASE WHEN Status2 = 'true' THEN 1 ELSE 0 END) + (CASE WHEN Status3 = 'true' THEN 1 ELSE 0 END) + (CASE WHEN Status4 = 'true' THEN 1 ELSE 0 END) + (CASE WHEN Status5 = 'true' THEN 1 ELSE 0 END) + (CASE WHEN Status6 = 'true' THEN 1 ELSE 0 END) + (CASE WHEN Status7 = 'true' THEN 1 ELSE 0 END) + (CASE WHEN Status8 = 'true' THEN 1 ELSE 0 END) + (CASE WHEN Status9 = 'true' THEN 1 ELSE 0 END) + (CASE WHEN Status10 = 'true' THEN 1 ELSE 0 END) + (CASE WHEN Status11 = 'true' THEN 1 ELSE 0 END) + (CASE WHEN Status12 = 'true' THEN 1 ELSE 0 END) + (CASE WHEN Status13 = 'true' THEN 1 ELSE 0 END) + (CASE WHEN Status14 = 'true' THEN 1 ELSE 0 END) AS true_count, Status1, Status2, Status3, Status4, Status5, Status6, Status7, Status8, Status9, Status10, Status11, Status12, Status13, Status14 FROM your_table_name ) t;
方案二:UNPIVOT转置+分组统计
通过UNPIVOT将列转成行,再分组统计true的数量,代码更简洁易维护,适合列数较多的场景:
WITH unpivoted_status AS ( SELECT DCID AS ID, status_col FROM your_table_name UNPIVOT ( status_val FOR status_col IN ( Status1, Status2, Status3, Status4, Status5, Status6, Status7, Status8, Status9, Status10, Status11, Status12, Status13, Status14 ) ) WHERE status_val = 'true' ) SELECT t.DCID AS ID, CASE WHEN COUNT(u.status_col) = 0 THEN 'None' WHEN COUNT(u.status_col) = 1 THEN MAX(u.status_col) ELSE 'Multiple' END AS StatusNew FROM your_table_name t LEFT JOIN unpivoted_status u ON t.DCID = u.ID GROUP BY t.DCID;
验证示例
针对示例数据:
| DCID | Status | Status1 | Status2 | Status3 |
|---|---|---|---|---|
| 1 | 0 | false | false | false |
| 2 | 1 | false | true | false |
| 3 | 1 | true | true | false |
执行上述SQL后,将得到预期结果:
| ID | StatusNew |
|---|---|
| 1 | None |
| 2 | Status2 |
| 3 | Multiple |
内容的提问来源于stack exchange,提问作者d.sweigart
相关产品推荐
相关产品推荐

