Oracle RIGHT JOIN中WHERE子句对varchar2列的异常行为问询
这是个很典型的RIGHT JOIN和NULL值交互导致的问题,我来给你拆解每个查询的行为,你马上就能明白:
1. 为啥WHERE a.app_cluster = 'ASLDKJASKDJFASKDJF'返回0行?
先回忆RIGHT JOIN的核心规则:它会完整保留右表(也就是这里的cluster_farm)的所有行,左表(xtern_app_info)里找不到匹配的那些行,对应的左表字段(比如a.app_cluster)会被填充成NULL。
而SQL里有个容易被忽略的规则:NULL和任何值做比较(=、<>、>、<等)结果都是UNKNOWN,不会被WHERE条件筛选出来。
回到你的查询:
- 如果某个集群只在
cluster_farm里存在,没有对应的xtern_app_info记录,那a.app_cluster就是NULL,自然不满足= 'xxx' - 如果集群有对应的
xtern_app_info记录,但a.app_cluster不等于目标字符串,也不会被选中 - 更关键的是:目标字符串
'ASLDKJASKDJFASKDJF'根本不在a.app_cluster列里,所以完全没有符合条件的行,返回0行就不奇怪了。
2. 为啥WHERE a.app_cluster <> 'ASLDKJASKDJFASKDJF'返回224行?
同样的逻辑,NULL <> 'xxx'的结果也是UNKNOWN,所以那些左表没有匹配的行(a.app_cluster为NULL)会被WHERE条件排除。
去掉WHERE时返回226行(也就是cluster_farm去重后的总集群数),减去2行(这两行是cluster_farm里没有对应xtern_app_info记录的集群),刚好就是224行。
3. 为啥去掉WHERE子句返回226行?
这就是RIGHT JOIN的原生行为:不管左表有没有匹配,右表的所有行都会被保留。加上DISTINCT后,返回的就是cluster_farm表中所有去重后的集群名称,总数226。
4. 为啥替换任意字符串结果都一致?
因为目标字符串'ASLDKJASKDJFASKDJF'压根不在a.app_cluster里:
- 用
=时,不管你换什么字符串(只要不在a.app_cluster里),永远找不到匹配的行,所以都是0行 - 用
<>时,相当于筛选a.app_cluster IS NOT NULL的行(因为字符串不存在,所有非NULL的a.app_cluster都不等于它),也就是224行,和你换的字符串没关系。
你可以跑这几个SQL来确认我的分析:
-- 查看cluster_farm总共有多少去重的集群(应该是226) SELECT COUNT(DISTINCT name) FROM cluster_farm; -- 查看有多少集群在xtern_app_info中有对应记录(应该是224) SELECT COUNT(DISTINCT b.name) FROM xtern_app_info a JOIN cluster_farm b ON a.app_cluster = b.name; -- 查看有多少集群在xtern_app_info中没有对应记录(应该是2) SELECT COUNT(DISTINCT name) FROM cluster_farm WHERE name NOT IN (SELECT DISTINCT app_cluster FROM xtern_app_info WHERE app_cluster IS NOT NULL);
如果你的需求是找出cluster_farm中名称为'ASLDKJASKDJFASKDJF'的集群(不管左表有没有匹配),那应该把条件放到ON子句里,而不是WHERE:
SELECT DISTINCT b.name AS CLUSTER_NAME FROM xtern_app_info a RIGHT JOIN cluster_farm b ON a.app_cluster = b.name AND b.name = 'ASLDKJASKDJFASKDJF' ORDER BY cluster_name desc;
或者更简单,直接查右表就行:
SELECT name AS CLUSTER_NAME FROM cluster_farm WHERE name = 'ASLDKJASKDJFASKDJF';
内容的提问来源于stack exchange,提问作者aymanzone

