OR子句返回错误结果:含LOCKED的用户记录为何仍被查询返回?
问题原因与解决方案
你猜的一点没错!这条记录被返回的核心问题就是逻辑运算符用错了,再加上逻辑组合的思路和你预期的完全相反。
先拆解你的原查询逻辑
先把你原查询里的语法小错误修正下(括号和参数位置),得到实际执行的语句:
select username from table where (instr(username,'LOCKED') = 0 or instr(username,'CLOSED') = 0 or instr(username,'DEACTIVATED') = 0) and userid = '1234'
对那条ID=1234、用户名带LOCKED的记录来说:
instr(username,'LOCKED') = 0→ 结果是假(因为确实找到了LOCKED)instr(username,'CLOSED') = 0→ 结果是真(压根没CLOSED这个词)instr(username,'DEACTIVATED') = 0→ 结果是真(也没DEACTIVATED)
因为你用的是OR连接这三个条件——OR的规则是只要其中一个条件为真,整个组合条件就为真。再加上userid='1234'也是真,所以整个WHERE条件就成立了,这条记录自然被返回,完全违背了你想排除它的初衷。
正确的查询写法
你的需求是排除包含LOCKED、DEACTIVATED、CLOSED任一关键词的记录,换句话说,就是要求用户名同时不包含这三个词。所以必须用AND来连接三个“不包含”的条件:
select username from table where instr(username,'LOCKED') = 0 and instr(username,'CLOSED') = 0 and instr(username,'DEACTIVATED') = 0 and userid = '1234'
如果你用的数据库支持通配符(比如MySQL、PostgreSQL、SQL Server这些主流库),用NOT LIKE会更直观:
select username from table where username NOT LIKE '%LOCKED%' and username NOT LIKE '%CLOSED%' and username NOT LIKE '%DEACTIVATED%' and userid = '1234'
这样一来,只要用户名沾了三个关键词里的任意一个,对应的条件就会变成假,整个WHERE条件不成立,这条记录就会被排除,正好符合你的预期。
额外提一句:括号的作用
你原查询里的括号其实是对的——它把三个关键词检查的条件归为一组,再和userid的条件做AND,这个优先级处理没问题。但核心还是逻辑运算符选错了,换成AND就解决问题了。
内容的提问来源于stack exchange,提问作者OllieBr
相关产品推荐
相关产品推荐

