本文介绍,在GBase 8a数据据集群中, not in 和 not exists的区别。
先看in 和 exists, 从本质上讲,都是判断等于,这个基本不会有任何问题,但对于判断不等于,出现了一个特例,那就是 null 不等于任何值。
目录导航
错误样例
查询没有使用中的颜色。
颜色表
gbase> select * from colors;
+----------+-------------+
| color_id | color_value |
+----------+-------------+
| c001 | Red |
| c002 | Yellow |
| c003 | Green |
| c004 | Black |
| c005 | White |
+----------+-------------+
5 rows in set (Elapsed: 00:00:00.00)
产品表
注意,其中1003的产品,颜色当前未知,为null。
gbase> select * from products;
+------------+-------------------+----------+
| product_id | product_name | color_id |
+------------+-------------------+----------+
| 1000 | smartwatch | c001 |
| 1001 | ballpoint pen | c003 |
| 1002 | wireless keyboard | c004 |
| 1003 | charging pad | NULL |
+------------+-------------------+----------+
4 rows in set (Elapsed: 00:00:00.01)
not in的查询结果
结果为空,不是预期的Yellow和White。
gbase> SELECT col.color_value FROM Colors AS col
WHERE col.color_id NOT IN
(SELECT prod.color_id FROM Products AS prod);
Empty set (Elapsed: 00:00:00.04)
gbase>
原因就是,在判断not in时,是将每个值做类似如下的判断
color_id NOT IN (c001, c003, c004, NULL)
等同于
NOT (color_id = c001 OR color_id = c003 OR color_id = c004 OR color_id = NULL).
而其中的 color_id = NULL 导致返回结果是【未知】,因为null不【等于】null, 也不【不等于】null。
最终导致返回值为false。
修正方法
使用not exists代替not in ,除非你确认你的数据里不包含null。
gbase> SELECT col.color_value
-> FROM Colors AS col
-> WHERE NOT EXISTS
-> (SELECT prod.color_id
-> FROM Products AS prod
-> WHERE col.color_id = prod.color_id);
+-------------+
| color_value |
+-------------+
| Yellow |
| White |
+-------------+
2 rows in set (Elapsed: 00:00:00.09)
总结
尽量避免使用not in这个用法,而是改用not exists。