如果只能使用单个过滤条件,SQL 语句就无法满足复杂的查询需求,例如查找月薪超过10000 的女性员工。为此,SQL 借助于逻辑代数中的运算提供了三个逻辑运算符,可以基于多个运算符构建复杂的过滤条件。
本文比较五种主流数据库对于复合查询条件的实现和差异,包括 MySQL、Oracle、SQL Server、PostgreSQL 以及 SQLite。
复合查询条件 | MySQL | Oracle | SQL Server | PostgreSQL | SQLite |
---|---|---|---|---|---|
AND | ?? | ?? | ?? | ?? | ?? |
OR | ?? | ?? | ?? | ?? | ?? |
NOT | ?? | ?? | ?? | ?? | ?? |
XOR | ?? | ? | ? | ? | ? |
逻辑与(AND)
对于逻辑与运算符,只有当运算符两边的条件都为真时,才返回数据,否则查询不返回数据。例如,以下语句使用 AND 运算符查找月薪超过 10000 的女性员工:
SELECT emp_name, sex, salary FROM employee WHERE sex = '女' AND salary > 10000;
查询返回的结果如下:
emp_name|sex|salary --------|---|-------- 孙尚香 |女 |12000.00
女性员工中只有“孙尚香”的月薪超过了 10000。
AND 运算符的逻辑真值表如下:
x AND y | TRUE | FALSE | NULL |
---|---|---|---|
TRUE | TRUE | FALSE | NULL |
FALSE | FALSE | FALSE | FALSE |
NULL | NULL | FALSE | NULL |
逻辑或(OR)
对于逻辑或运算符,只要运算符两边的条件有一个为真,就返回数据,否则查询不返回数据。例如,我们可以使用 OR 运算符实现 2.2.1 节中的 IN 运算符示例:
SELECT emp_id, emp_name FROM employee WHERE emp_name = '刘备' OR emp_name = '关羽' OR emp_name = '张飞';
该查询同样返回了姓名为“刘备”、“关羽”或者“张飞”的员工。
OR 运算符的逻辑真值表如下:
x OR y | TRUE | FALSE | NULL |
---|---|---|---|
TRUE | TRUE | TRUE | TRUE |
FALSE | TRUE | FALSE | NULL |
NULL | TRUE | NULL | NULL |
对于逻辑运算符 AND 和 OR,SQL 使用短路运算(Short-Circuit Evaluation)。也就是说,只要左边的表达式能够决定最终的结果就不计算右边的表达式。例如,以下语句不会产生除零错误:
SELECT * FROM employee WHERE 1 = 0 AND 1/0 = 1; SELECT * FROM employee WHERE 1 = 1 OR 1/0 = 1;
第一个查询使用了 AND 运算符,由于 1=0 结果为假,查询肯定不会返回任何结果,也就不会计算右边的 1/0。第二个查询使用了 OR 运算符,由于 1=1 结果为真,查询返回全部员工,同样不会计算右边的 1/0。
提示:SQL 语句的短路运算方法可以减少某些情况下的表达式计算,提高运算的效率。
逻辑非(NOT)
逻辑非运算符与其他运算符一起使用时,表示将随后的运算结果取反:
- NOT >,查找不大于(小于或等于)指定值的数据。也可以使用 NOT=、NOT<等运算符。
- NOT BETWEEN,查找位于指定范围之外的数据。
- NOT IN,查找不在指定列表之中的数据。
- NOT LIKE,查找不匹配某个模式的文本。
- NOT expr IS NULL,查找 expr 不为空的数据,等价于 expr IS NOT NULL。
例如,以下语句查找奖金小于 2000 或者大于 10 000 的员工:
SELECT emp_name, bonus FROM employee WHERE NOT bonus BETWEEN 2000 AND 10000;
查询返回的结果如下:
emp_name|bonus --------|------- 蒋琬 |1500.00
虽然有很多员工没有奖金(bonus 字段为空),但是查询并没有返回这些员工的信息,因为未知结果取反之后仍然未知。
NOT 运算的逻辑真值表如下:
x | NOT x |
---|---|
TRUE | FALSE |
FALSE | TRUE |
NULL | NULL |
逻辑异或(XOR)
除了以上三个标准逻辑运算符之外,MySQL 还实现了一个逻辑异或(XOR )运算符,它在逻辑上等价于以下表达式:
(x AND (NOT y)) OR ((NOT x) AND y)
只要运算符两边的条件有一个为 NULL,结果为 NULL,查询不返回数据;如果有且只有一个条件为真,返回结果;否则,不返回结果。例如:
SELECT 1 XOR 1, 1 XOR 0, 1 XOR NULL; 1 XOR 1|1 XOR 0|1 XOR NULL| -------+-------+----------+ 0| 1| |
运算符优先级
我们还需要注意多个运算符之间的优先级问题。一般来说,比较运算符的优先级比逻辑运算符的优先级高,在逻辑运算符中 NOT 比 AND 优先级高,AND 比 OR 的优先级高。通常优先级高的运算符先执行,相同级别的运算符从左至右执行。
我们想要知道人力资源部(dept_id=2)或者财务部(dept_id=3)中有哪些员工有奖金,如果使用以下查询语句:
SELECT emp_name, dept_id, bonus FROM employee WHERE dept_id = 2 OR dept_id = 3 AND bonus IS NOT NULL;
返回的结果如下:
emp_name|dept_id|bonus --------|-------|------- 诸葛亮 | 2|8000.00 黄忠 | 2| 魏延 | 2| 孙尚香 | 3|5000.00
“黄忠”和“魏延”并没有奖金,不是我们期望的结果。那么问题出在哪里了呢?因为 AND 运算符比 OR 运算符的优先级高,以上查询实际返回了人力资源部(dept_id=2)的员工,以及财务部(dept_id=3)中有奖金的员工。
如果想要获得我们期望的结果,可以使用圆括号调整运算符的优先级,例如:
SELECT emp_name, dept_id, bonus FROM employee WHERE (dept_id = 2 OR dept_id = 3) AND bonus IS NOT NULL;
查询返回的结果如下:
emp_name|dept_id|bonus --------|-------|------- 诸葛亮 | 2|8000.00 孙尚香 | 3|5000.00