卡了一晚上的一个问题,基础不牢,地动山摇!

题目

给定一个表 tree,id 是树节点的编号, p_id 是它父节点的 id 。

+----+------+| id | p\_id |+----+------+| 1 | NULL || 2 | 1 || 3 | 1 || 4 | 2 || 5 | 2 |+----+------+

树中每个节点属于以下三种类型之一:

叶子:如果这个节点没有任何孩子节点。

根:如果这个节点是整棵树的根,即没有父节点。

内部节点:如果这个节点既不是叶子节点也不是根节点。

写一个查询语句,输出所有节点的编号和节点的类型,并将结果按照节点编号排序。上面样例的结果为:

+----+------+| id | TYPE |+----+------+| 1 | Root || 2 | INNER|| 3 | Leaf || 4 | Leaf || 5 | Leaf |+----+------+

解释

节点 ‘1’ 是根节点,因为它的父节点是 NULL ,同时它有孩子节点 ‘2’ 和 ‘3’ 。

节点 ‘2’ 是内部节点,因为它有父节点 ‘1’ ,也有孩子节点 ‘4’ 和 ‘5’ 。

节点 ‘3’, ‘4’ 和 ‘5’ 都是叶子节点,因为它们都有父节点同时没有孩子节点。

样例中树的形态如下:

 1/ \\2 3/ \\4 5

首先先建表

1.建表
CREATE TABLE tree(
id INT ,
p_id INT
)

下面是我的做法:

SELECT id,(
CASE WHEN tree.p_id IS NULL THEN 'Root'WHEN tree.id NOT IN (  -- id不在父结点p_id列时,认为是叶子结点,逻辑上没有问题!SELECT p_idFROM treeGROUP BY p_id) THEN 'Leaf'ELSE 'Inner'
END
)TYPE
FROM tree

我觉得当id不在父结点p_id列时,认为是叶子结点,这在逻辑上完全没有任何问题,然而事情并没有这么简单,查询结果如下:从id=3开始没有查到我想要的结果!神奇吧!

于是又过了一晚上,终于解决了问题,我先给出正确的做法:

SELECT id,(
CASE WHEN tree.p_id IS NULL THEN 'Root'WHEN tree.id NOT IN (SELECT p_idFROM treeWHERE p_id IS NOT NULL  -- 添加了一句SQLGROUP BY p_id) THEN 'Leaf'ELSE 'Inner'
END
)TYPE
FROM tree


为什么会这样呢?
我们都知道

MySQL 中的 IN 运算符用来判断表达式的值是否位于给出的列表中;如果是,返回值为 1,否则返回值为 0。NOT IN 的作用和 IN 恰好相反,NOT IN 用来判断表达式的值是否不存在于给出的列表中;如果不是,返回值为 1,否则返回值为 0。

一般情况下我们都是这样用的,结果也是我们想要的。但是下面的特殊情况我们却经常遇到!

(1)in和not in左右两侧都没有NULL值的情况

【实例1】在 SQL 语句中使用 IN 和 NOT IN 运算符:

mysql> SELECT 2 IN (1,3,5,'thks'),'thks' IN (1,3,5, 'thks');
+---------------------+---------------------------+
| 2 IN (1,3,5,'thks') | 'thks' IN (1,3,5, 'thks') |
+---------------------+---------------------------+
|                   0 |                         1 |
+---------------------+---------------------------+
1 row in set, 2 warnings (0.00 sec)mysql> SELECT 2 NOT IN (1,3,5,'thks'),'thks' NOT IN (1,3,5, 'thks');
+-------------------------+-------------------------------+
| 2 NOT IN (1,3,5,'thks') | 'thks' NOT IN (1,3,5, 'thks') |
+-------------------------+-------------------------------+
|                       1 |                             0 |
+-------------------------+-------------------------------+
1 row in set, 2 warnings (0.00 sec)

由结果可以看到,IN 和 NOT IN 的返回值正好相反。

但是忽略了一个NULL值问题

对空值 NULL 的处理
当 IN 运算符的两侧有一个为空值 NULL 时,如果找不到匹配项,则返回值为 NULL;如果找到了匹配项,则返回值为 1。

(2)NULL值在in左右两侧

请看下面的 SQL 语句如下:

mysql> SELECT NULL IN (1,3,5,'thks'),10 IN (1,3,NULL,'thks');
+------------------------+-------------------------+
| NULL IN (1,3,5,'thks') | 10 IN (1,3,NULL,'thks') |
+------------------------+-------------------------+
|                   NULL |                    NULL |
+------------------------+-------------------------+
1 row in set, 1 warning (0.00 sec)mysql>  SELECT NULL IN (1,3,5,'thks'),10 IN (1,10,NULL,'thks');
+------------------------+--------------------------+
| NULL IN (1,3,5,'thks') | 10 IN (1,10,NULL,'thks') |
+------------------------+--------------------------+
|                   NULL |                        1 |
+------------------------+--------------------------+
1 row in set (0.00 sec)

(3)NULL在NOT IN 的其中一侧

NOT IN 恰好相反,当 NOT IN 运算符的两侧有一个为空值 NULL 时,如果找不到匹配项,则返回值为 NULL;如果找到了匹配项,则返回值为 0。

请看下面的 SQL 语句如下:

mysql>  SELECT NULL NOT IN (1,3,5,'thks'),10 NOT IN (1,0,NULL,'thks');
+----------------------------+-----------------------------+
| NULL NOT IN (1,3,5,'thks') | 10 NOT IN (1,0,NULL,'thks') |
+----------------------------+-----------------------------+
|                       NULL |                        NULL |
+----------------------------+-----------------------------+
1 row in set, 1 warning (0.00 sec)mysql>  SELECT NULL NOT IN (1,3,5,'thks'),10 NOT IN (1,10,NULL,'thks');
+----------------------------+------------------------------+
| NULL NOT IN (1,3,5,'thks') | 10 NOT IN (1,10,NULL,'thks') |
+----------------------------+------------------------------+
|                       NULL |                            0 |
+----------------------------+------------------------------+
1 row in set (0.00 sec)

根据(3)NULL在NOT IN 的其中一侧的结果,这就可以看出问题
先来查询下面SQL语句,慢慢发现问题

SELECT p_id
FROM tree
GROUP BY p_id

上面查询结果包含了NULL值

所以查询下面SQL语句就查不到任何东西,这是因为NOT IN返回了NULL

SELECT id
FROM tree
WHERE id NOT IN (SELECT p_idFROM treeGROUP BY p_id)


所以要想查询出来结果就要先把NULL值给处理掉!好了,Bug搞定!
这题还有另外一种做法:

SELECT id,(
CASE WHEN tree.p_id IS NULL THEN 'Root'WHEN tree.id IN (SELECT p_idFROM treeGROUP BY p_id) THEN 'Inner'ELSE 'Leaf'
END
)TYPE
FROM tree


为什么是对的?留给大家想想

MySQL条件查询IN和NOT IN左右两侧包含NULL值的处理方式相关推荐

  1. MySQL 条件查询 limit、in、between and、like等等

    MySQL 条件查询 环境: CREATE TABLE `test_user` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户id',`userna ...

  2. MySQL学习-MySQL条件查询

    MySQL条件查询 操作的表 1.条件查询概述 2.条件查询between and] 3.条件查询is null和is not null 4.and和or的优先级的问题 5.条件查询in 6.模糊查询 ...

  3. Mysql 条件查询(like、between、and、in······)

    目录 Mysql 条件查询 示例 一.比较运算和逻辑运算符符 二.范围运算符 三.列表运算符 四.模糊匹配符 五.空值判断符 Mysql 条件查询 Mysql 条件查询即where子句后跟条件 运算符 ...

  4. mysql不等于条件不包含NULL值问题

    mysql不等于条件不包含NULL值问题 table表中,type为1(100条记录).2(50条记录).NULL(50条记录) 查询:select * form table where type & ...

  5. MySQL 条件查询

    MySQL SELECT,可以使用 WHERE 子句来指定查询条件,从 FROM 子句的中间结果中选取适当的数据行,达到数据过滤的效果. 语法格式如下: WHERE <查询条件> {< ...

  6. mysql 条件查询分页_百万数据下mysql条件查询及分页查询的注意事项

    接上一节<百万数据mysql分页问题>,我们加上查询条件:select id from news where cate = 1 order by id desc limit 500000 ...

  7. MySQL 条件查询

    一.带关系运算符的查询 在select语句中最常见的格式如下: select 字段名1 , 字段名2,,,, from 表名 where 条件表达式 举例,查询表student中id=4的学生姓名,过 ...

  8. MySQL条件查询语句(一)

    条件查询 注意:条件查诟需要用到 where 询句,where 必须放到 from 询句表的后面: 执行顺序:先from再where过滤后再检索出来. 1..支持如下运算 2.等号(=)操作符 (1) ...

  9. php mysql 条件查询语句_where 查询条件-Medoo - 高效的轻量级PHP数据库框架, 提高开发效率!...

    WHERE 语句 SQL中使用where可能会有一些不安全的动态参数传入或者一些复杂的SQL语句,但是Medoo提供非常简介和安全的方法来实现这些. 基础使用 在基础使用中. 你可以使用一些符号对参数 ...

  10. 有条件了!筛选,MySQL条件查询SELECT-WHERE

    1.基本语法 SELECT查询列表 FROM表名 WHERE筛选表达式; 2.按条件表达式筛选 条件运算符:>,<,=,!=,<>,>=,<= 条件运算符不能判断n ...

最新文章

  1. 传感器c语言开发,Android环境传感器开发教程
  2. WPF对象级资源的定义与查找
  3. aspnet中gridview文本只显示开始几个文本_软网推荐:三个小软件 轻松解决文本操作难题...
  4. mac 下终端 操作svn命令 以及出现证书错误的处理方法
  5. 【javascript】不刷新页面,实时显示当前时间
  6. XML Schema是什么
  7. 哥大计算机专业 世界排名,哥伦比亚大学计算机科学硕士排名第16(2020年TFE Times排名)...
  8. php 实现贪吃蛇游戏,HTML5 贪吃蛇游戏实现思路及源代码_html5教程技巧
  9. CentOS下调整VolGroup-lv_root分区大小
  10. FPGA UART总线协议简介
  11. 收费最低的云存储_营业收费系统|自来水管理系统|自来水公司收费管理系统|手机移动抄表|网上营业厅|短信服务平台...
  12. 纳米软件案例之陶瓷样品测试系统,原位观察力学测试纳米压痕仪-扫描电子显微镜SEM联用...
  13. 在ADF应用中,能够通过 oracle.adf.view.rich.security.FRAME_BUSTING 参数来使用framebusting功能。
  14. V831 MP4播放+船新版本
  15. 高级商务办公软件应用【9】
  16. [附源码]Python计算机毕业设计调查问卷及调查数据统计系统
  17. 程序员,停止你的焦虑
  18. alpha和color key
  19. UVA 12576 - Simply Loopy
  20. SpringSecurity启动器

热门文章

  1. 老男孩爬虫实战密训课第一季,2018.6,初识爬虫训练-实战2-自动登陆抽屉网
  2. 点击选择-图片添加对号(单选)
  3. uniapp快速入门开发
  4. 买火车票的过来看看,提供一个小工具,不一定能买到票,但是可以实现自动登录,自动刷票,自动重新提交订单!...
  5. excel最常用的快捷键大全:
  6. 优雅写代码的45个小技巧
  7. export default (imported as router) was not found_一篇文章搞定as四大用法
  8. UOJ #449. 【集训队作业2018】喂鸽子
  9. 常用密码技术-对称加密
  10. Transition过渡动画