首页 > 解决方案 > Oracle查询:当只有一条记录时,WHERE NOT LIKE不排除记录

问题描述

我有以下查询

select cand_id 
from cand_kw
WHERE client_id='mamasandpapas' AND UPPER(kw) LIKE '%MARAH%' OR UPPER(kw) LIKE '%ANDREW%' AND UPPER(kw) NOT LIKE '%KOCH%' 

在数据库中有以下记录:

Andrew Postings
Andrew Postings
Andrew McDee
Marah Koch

因此,其中有 3 行和 Andrew,但只有一个记录有 Marah。

如果我将查询更改为以下内容,则排除两个 Andrew Postings

select cand_id
from cand_kw
 WHERE client_id='mamasandpapas' AND UPPER(kw) LIKE '%MARAH%' OR UPPER(kw) LIKE '%ANDREW%' AND UPPER(kw) NOT LIKE '%POSTINGS%' 

所以看起来如果只存在一条记录,那么即使应该排除它们,也会返回结果。

这是使用非常旧的 Oracle (9i) 版本,其搜索 (kw) 字段代表关键字,是包含一堆关键字的 CLOB。

这是一个非常古老的系统,不是我设计的。

任何人都可以在第一种情况下解释为什么 Marah Koch 没有被排除在外而 Andrew Postings 记录被排除在外吗?

标签: sqloracleoracle9i

解决方案


按照它的编写方式,NOT LIKE "%KOCH%" 只会在 LIKE "%ANDREW%" 评估为 True 时评估。这是关于与 Marah Koch 的记录的原始 WHERE 子句的流程。

第一个 SQL 查看 client_id 是否为“mamasandpapas”。太好了!接下来,它看到一个 AND,这意味着它后面的任何内容也必须为真,WHERE 子句才为真,幸运的是,Upper(kw) 确实是 LIKE '%MARAH%'。然后它会看到 OR next。SQL 决定它可以忽略其余部分,因为如果 OR 任一侧的任何表达式计算为真,那么它就完成了计算,因为 Upper(kw) LIKE '%MARAH%' 已经计算为真,所以它甚至没有到达 Upper (kw) 不喜欢 '%KOCH%'。

同样,在您的第二个 WHERE 子句示例中,它似乎仅起作用,因为在 Andrew Postings 的情况下,在 client_id 评估为 true 后,AND 说查看 Upper(kw) 是否为 LIKE'%MARAH%',哦不是,现在我们移动到 OR 的另一边,Upper(kw) is LIKE '%ANDREW%' 但是等等,现在我看到一个 AND,这意味着 Upper(kw) LIKE'%ANDREW%' 和上面的任何东西另一方必须为真,WHERE 为真。如果您在 Marah Postings 表中添加一条记录,它仍将在第二个示例中返回。

我为此学到的术语是“Naked ORs”。换句话说,为了可读性和大多数人理解 AND 和 OR 的逻辑,最好用括号“修饰”任何 OR 语句。


推荐阅读