MyBatis中如何实现行内列全为NULL时total列返回NULL?
问题描述
当前在MyBatis中执行查询后得到如下结果(total列为每行的求和值):
| day_1 | day_2 | day_3 | total |
|---|---|---|---|
| [NULL] | 6 | [NULL] | 6 |
| [NULL] | [NULL] | [NULL] | 0 |
计算total列使用的MyBatis代码如下:
( <foreach item="item" collection="dayList" open="" separator=" + " close=""> COALESCE(day_${item}, 0) </foreach> ) AS total
期望的查询结果是:当某行所有列均为[NULL]时,total列返回[NULL],而非0:
| day_1 | day_2 | day_3 | total |
|---|---|---|---|
| [NULL] | 6 | [NULL] | 6 |
| [NULL] | [NULL] | [NULL] | [NULL] |
尝试过以下代码,但不确定是否可行:
( <foreach item="item" collection="dayList" open="" separator=" + " close=""> <if test="#{'hour_' + item} != null"> hour_${item} </if> </foreach> ) AS total
需要解决:如何在MyBatis中实现上述需求?
解决方案
方法一:用CASE WHEN判断所有列是否为空
核心逻辑是先判断当前行的所有day_*列是否都为NULL,再决定返回NULL还是求和值:
( CASE WHEN <foreach item="item" collection="dayList" open="" separator=" AND " close=""> day_${item} IS NULL </foreach> THEN NULL ELSE <foreach item="item" collection="dayList" open="" separator=" + " close=""> COALESCE(day_${item}, 0) </foreach> END ) AS total
这段代码执行时:
- 如果所有
day_*列都是NULL,total直接返回NULL; - 只要有一列非空,就把所有NULL转成0后求和,得到正确的非零结果。
方法二:利用NULLIF简化(适配支持该函数的数据库)
如果你的数据库(如MySQL、PostgreSQL)支持NULLIF函数,可以结合它简化代码:
( CASE WHEN <foreach item="item" collection="dayList" open="" separator=" OR " close=""> day_${item} IS NOT NULL </foreach> THEN <foreach item="item" collection="dayList" open="" separator=" + " close=""> COALESCE(day_${item}, 0) </foreach> ELSE NULL END ) AS total
逻辑和方法一一致,只是判断条件换成了“是否存在非空列”,写法更直观。
关于你尝试的代码的问题
你写的<if test="#{'hour_' + item} != null">逻辑不成立:MyBatis的test表达式是在SQL解析阶段执行的,无法直接判断数据库中列的值是否为NULL,所以这段代码不会过滤空列,反而可能因为生成空的求和表达式导致SQL语法错误。
内容的提问来源于stack exchange,提问作者mentha
相关产品推荐
相关产品推荐

