五种主流数据库:复合查询条件

如果只能使用单个过滤条件,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