问题描述
在工单某报表开发过程中,需新增工单占比字段wkord_percentage
,该字段要求计算某类工单数量占总工单数的百分比。核心需求如下:
- 百分比计算需动态适配时间范围参数
sTime
/eTime
- 结果保留两位小数并添加百分号
- 兼容部门ID过滤条件
dId
Failed to parse SQL: Syntax error near 'AND'
错误分析
1. 动态条件拼接缺陷
生成的SQL片段存在语法错误:
SELECT ...
WHERE event_id IS NOT NULL
AND event_id <> ''
AND date >= '2024-05-01'AND date <= '2024-05-31' /* 缺失空格 */
2. 类型转换不兼容
使用非标准函数toString()
导致数据库兼容性问题:
CONCAT(toString(...), '%') /* MySQL不支持toString */
3. 除零风险未处理
当总工单数为零时触发除零异常:
a.wkord_cnt / (SELECT COUNT(...))
解决方案
1. 动态条件安全拼接
let subQuery = "SELECT COUNT(event_id) FROM crm.payroll " +
"WHERE event_id IS NOT NULL " + "AND event_id <> ''";
if (sTime) subQuery += " AND date >= '" + sTime + "'"; // 前缀空格保障
if (eTime) subQuery += " AND date <= '" + eTime + "'";
2. 类型转换标准化
CONCAT(
CAST(ROUND(
COALESCE(
a.wkord_cnt * 100.0 / NULLIF((${subQuery}), 0),
0
), 2 )
AS CHAR),
'%' ) AS wkord_percentage
3. 数学运算安全防护
- NULLIF处理零分母:
NULLIF(subquery, 0)
- COALESCE默认值:
COALESCE(..., 0)
- 浮点精度保障:使用
100.0
代替100
完整实现代码
unction buildPercentageField(params) {
const { sTime, eTime } = params;
// 构建子查询
let subQuery = SELECT COUNT(event_id)
FROM crm.payroll
WHERE event_id IS NOT NULL AND event_id <> '';
// 动态时间条件(安全拼接)
const conditions = [];
if (sTime) conditions.push(date >= '${sTime}');
if (eTime) conditions.push(date <= '${eTime}');
if (conditions.length) {
subQuery += ' AND ' + conditions.join(' AND '); }
// 构建百分比字段
return CONCAT( CAST(ROUND( COALESCE( a.wkord_cnt * 100.0 / NULLIF((${subQuery}), 0), 0.0 ), 2 ) AS CHAR), '%' ) AS wkord_percentage;
}
经验总结
- 动态SQL开发规范
- 所有动态条件前必须包含空格
- 使用参数化查询代替字符串拼接
- 显式处理NULL和除零情况