Oracle查询:只有一条记录时WHERE NOT LIKE不排除记录

Oracle query: WHERE NOT LIKE is not excluding record when only one record exists

我有以下查询

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,但只有 1 条记录有 Marah。

如果我将查询更改为以下内容,则可以正确排除两个 Andrew 帖子

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 记录被排除在外?

据推测,您想要这样的 where 子句:

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

但我不确定,因为你没有解释你想要实现的实际逻辑。也就是说,如果您混合使用 ANDOR,请使用括号——至少在您真正理解运算符的优先级之前这样做。

按照它的写法,NOT LIKE "%KOCH%" 只会在 LIKE "%ANDREW%" 的计算结果为 True 时计算。这是关于 Marah Koch 记录的原始 WHERE 子句的流程。

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

同样,在您的第二个 WHERE 子句示例中,它似乎只起作用,因为在 Andrew Postings 的情况下,在 client_id 评估为真之后,AND 说看看 Upper(kw) 是否像' %MARAH%',哦,不是,现在我们转到 OR 的另一边,Upper(kw) 是 LIKE '%ANDREW%' 但是等等,现在我看到一个 AND,这意味着 Upper(kw) LIKE' %ANDREW%' AND 另一边的任何内容都必须为真,WHERE 才为真。如果您在 Marah Postings 的 table 中添加一条记录,它仍然会在第二个示例中返回。

我为此学到的术语是“裸手术室”。换句话说,最好用括号“装饰”任何 OR 语句以提高可读性,因为这是大多数人理解 AND 和 OR 逻辑的方式。