关于MySql中使用IFNULL()函数失效的问题。

Java基础

浏览数:25

2019-9-11

    今天在学习时,碰到一个问题:在联表查询取得结果后,如果取得的结果是空值,则给一个默认值,如果不是空值,则返回这个值。

下面我们来看看业务场景:

       在menu表中:

存储的是前端页面的菜单配置,注意成员权限管理,报表权限管理和配置工具,这三个菜单是项目管理这个菜单的子菜单,他们通过parent_id这个字段进行关联。

在另外一张映射表project_menu中:

在将菜单归属到具体的项目下时,依然要把配置的父子菜单进行关联,但是在这里关联的id和上面关联的id是不一样的。

现在需求就是,在插入到project_menu表时,需要在插入时将子菜单的parent_id顺带插入其中。如果这个目录不是某个已存在目录的子菜单时,则parent_id默认是0,如果是某个菜单的子菜单,则需要关联表的查询,算出当前子目录的parent_id。

我们来看看一开始错误的写法:

1  SELECT IFNULL(id,0) from project_menu where code =
2  (SELECT code FROM menu where id =
3  (SELECT parent_id from menu where code = #{menuCode} and parent_id != 0)) 
4   AND project_id = #{projectId}

通过表的关联查询,得到当前目录的值,由于mybatis返回的值类型为int,所以如果查询到的值为null时,后台会报错,因此使用了IFNULL()函数,当id为null时,默认返回0。

但是这样做,在调试的时候,mybatis却一直报错该语句尝试返回null但定义的返回类型时int。说明这个函数并没有起作用。那为什么没有起作用呢?

那是因为这条语句的查询结果就是空的,也就是说,当传进来的参数是非子菜单时时,下面这条语句的返回值就是null

 1 (SELECT parent_id from menu where code = #{menuCode} and parent_id != 0) 

当这条语句返回null时,整条语句的返回值都是空的(where分支比select分支优先执行),这时,等价于下面这条语句:

 1 SELECT IFNULL(id,0) from project_menu where code = NULL 

这就不是这个当id为空时,用0替换id返回这个概念了,因为当语句本身就是null时,语句中的函数还会起作用吗?

所以,此方法行不通,附上解决方案:

 1 SELECT 
 2     CASE
 3     WHEN (SELECT parent_id from menu where code = #{code}) = 0  
 4      THEN  0
 5      ELSE 
 6      (SELECT id from project_menu where code =
 7      (SELECT code FROM menu where id =
 8      (SELECT parent_id from menu where code =#{code} ))
 9      AND project_id=#{projectId})
10      END

使用条件判断选择语句。亲测有效。

作者:jy的blog