运算符
# 70.运算符
运算符就是对其两边的列或者值进行运算(计算或者比较大小等)的符号。
之前我们使用 where 指定条件查询的时候,就用了等号“=”这个运算符,在实际运用中,还有用到很多运算符
# 算术运算符
常见的运算符包括加减乘除:
含义 | 运算符 |
---|---|
加法运算 | + |
减法运算 | - |
乘法运算 | * |
除法运算 | / |
例如将商品单价 * 2:
mysql> SELECT product_name, sale_price,
-> sale_price * 2 AS "sale_price_x2"
-> FROM Product;
+--------------+------------+---------------+
| product_name | sale_price | sale_price_x2 |
+--------------+------------+---------------+
| T恤衫 | 1000 | 2000 |
| 打孔器 | 500 | 1000 |
| 运动T恤 | 4000 | 8000 |
| 菜刀 | 3000 | 6000 |
| 高压锅 | 6800 | 13600 |
| 叉子 | 500 | 1000 |
| 擦菜板 | 880 | 1760 |
| 圆珠笔 | 100 | 200 |
+--------------+------------+---------------+
8 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
以第一行结果为例,sale_price 列的值 1000 的 2 倍是 2000 ,它以 sale_price_x2 列的形式被查询出来。'打孔器' 记录行的值 500 的 2 倍 1000 ......运算就是这样以行为单位执行的 。
SQL 中也可以像平常的运算表达式那样使用括号“( )”。括号中运算表达式的优先级会得到提升,优先进行运算。例如在运算表达式(1 + 2) * 3 中,会先计算 1 + 2 的值,然后再对其结果进行 * 3 运算。
括号的使用并不仅仅局限于四则运算,还可以用在 SQL 语句的任何表达式当中。具体的使用方法今后会慢慢介绍给大家。
注意 null:请大家考虑一下在 SQL 语句中进行如下运算时,结果会是什么呢?
- 5 + NULL
- 10 - NULL
- 1 * NULL
- 4 / NULL
- NULL / 9
- NULL / 0
正确答案全部都是 NULL 。所有包含 NULL 的计算,结果肯定是 NULL,即使用 NULL 除以 0 也是。
# 比较运算符
之前我们用了等于号“=”来比较两边的值是否相等,实际上还有大于、不等于这样的比较运算符:
运算符 | 含义 |
---|---|
= | 相等 |
<> | 不相等 |
>= | 大于等于 |
> | 大于 |
<= | 小于等于 |
< | 小于 |
这些比较运算符可以对字符、数字和日期等几乎所有数据类型的列和值进行比较。
注意:在使用大于等于或者小于等于作为查询条件时,一定要注意不等号(< 、> )和等号(= )的位置不能颠倒。一定要让不等号在左,等号在右 。
# 对数字进行比较
例如,从 Product 表中选取出销售单价(sale_price ) 大于等于 1000 日元的记录:
mysql> SELECT product_name, product_type, sale_price
-> FROM Product
-> WHERE sale_price >= 1000;
+--------------+--------------+------------+
| product_name | product_type | sale_price |
+--------------+--------------+------------+
| T恤衫 | 衣服 | 1000 |
| 运动T恤 | 衣服 | 4000 |
| 菜刀 | 厨房用具 | 3000 |
| 高压锅 | 厨房用具 | 6800 |
+--------------+--------------+------------+
4 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
# 对日期进行比较
选取出登记日期在 2009 年 9 月 27 日之前的记录:
mysql> SELECT product_name, product_type, regist_date
-> FROM Product
-> WHERE regist_date < '2009-09-27';
+--------------+--------------+-------------+
| product_name | product_type | regist_date |
+--------------+--------------+-------------+
| T恤衫 | 衣服 | 2009-09-20 |
| 打孔器 | 办公用品 | 2009-09-11 |
| 菜刀 | 厨房用具 | 2009-09-20 |
| 高压锅 | 厨房用具 | 2009-01-15 |
| 叉子 | 厨房用具 | 2009-09-20 |
| 擦菜板 | 厨房用具 | 2008-04-28 |
+--------------+--------------+-------------+
6 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
小于某个日期就是在该日期之前的意思。想要实现在某个特定日期(包含该日期)之后的查询条件时,可以使用代表大于等于的 >= 运算符。
# 对运算结果进行比较
还可以使用比较运算符对计算结果进行比较。例如找出销售单价(sale_price )比进货单价(purchase_price )高出 500 日元以上的数据:
mysql> SELECT product_name, sale_price, purchase_price
-> FROM Product
-> WHERE sale_price - purchase_price >= 500;
+--------------+------------+----------------+
| product_name | sale_price | purchase_price |
+--------------+------------+----------------+
| T恤衫 | 1000 | 500 |
| 运动T恤 | 4000 | 2800 |
| 高压锅 | 6800 | 5000 |
+--------------+------------+----------------+
3 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
# 对字符进行比较
如何判断两个字符的大小呢?按字典顺序。在字典中,A 排第一位,B 排第二位,C 排第三位.......。因此,A 比 B 大,B 比 C 大...... 依次类推。
如果是字符串呢?就会让两个字符串逐个字母进行比较,直到找到比较出大小。
例如“AB”大于 "AC",因为第一个 A 是相等的,因此继续比较下一位,而 B 大于 C,因此 “AB”大于 "AC"
如果是数值类型的字符串,也是一样的,"12" 是小于 "2"的,因为比较的时候,先从第一位开始比,而"1"< "2",因此 "12" 小于 "2"。
就好比以书籍的章节为例也可以。1-1 节包含在第 1 章当中,所以肯定比第 2 章更靠前。
我们来测试下,先创建表和插入数据:
-- DDL :创建表
CREATE TABLE Chars
(chr CHAR(3) NOT NULL,
PRIMARY KEY (chr));
-- DML :插入数据
INSERT INTO Chars VALUES ('12');
INSERT INTO Chars VALUES ('2');
2
3
4
5
6
7
8
然后看看比 '2' 小的数据:
mysql> SELECT chr
-> FROM Chars
-> WHERE chr < '2';
+-----+
| chr |
+-----+
| 12 |
+-----+
1 row in set (0.00 sec)
2
3
4
5
6
7
8
9
# 不能对 NULL 使用比较运算符
关于比较运算符还有一点十分重要,那就是作为查询条件的列中含有 NULL 的情况。
例如,商品“叉子”和“圆珠笔”的进货单价是 NULL 。如果想选取进货单价为 NULL 的记录的话,条件表达式该怎么写呢?如果用比较运算符“=”,是查询不到的:
SELECT product_name, purchase_price
FROM Product
WHERE purchase_price = NULL;
--结果:
Empty set (0.00 sec)
2
3
4
5
6
7
即使使用 <> 运算符也还是无法选取出 NULL 的记录 。SQL 提供了专门用来判断是否为 NULL 的 IS NULL 运算符 。想要选取 NULL 的记录时,可以这样写:
SELECT product_name, purchase_price
FROM Product
WHERE purchase_price IS NULL;
--结果:
+--------------+----------------+
| product_name | purchase_price |
+--------------+----------------+
| 叉子 | NULL |
| 圆珠笔 | NULL |
+--------------+----------------+
2 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
13
反之,希望选取不是 NULL 的记录时,使用 IS NOT NULL 运算符 :
SELECT product_name, purchase_price
FROM Product
WHERE purchase_price IS NOT NULL;
--结果:
+--------------+----------------+
| product_name | purchase_price |
+--------------+----------------+
| T恤衫 | 500 |
| 打孔器 | 320 |
| 运动T恤 | 2800 |
| 菜刀 | 2800 |
| 高压锅 | 5000 |
| 擦菜板 | 790 |
+--------------+----------------+
6 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 逻辑运算符
在 SQL 中,同样涉及到逻辑运算,也就是与或非。
# and 运算符和 or 运算符
到目前为止,我们看到的每条 SQL 语句中都只有一个查询条件。但在实际使用当中,往往都是同时指定多个查询条件对数据进行查询的。
在 WHERE 子句中使用 AND 运算符 ,可以对多个查询条件进行组合。AND 运算符在其两侧的查询条件都成立时整个查询条件才成立 ,其意思相当于“并且”。
例如,想要查询“商品种类为厨房用具、销售单价大于等于 3000 日元:
mysql> SELECT product_name, purchase_price
-> FROM Product
-> WHERE product_type = '厨房用具'
-> AND sale_price >= 3000;
+--------------+----------------+
| product_name | purchase_price |
+--------------+----------------+
| 菜刀 | 2800 |
| 高压锅 | 5000 |
+--------------+----------------+
2 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
该查询条件的文氏图所示:
文氏图:将集合(事物的聚集)的关系通过更加容易理解的图形进行可视化展示。
左侧的圆圈代表符合查询条件“商品种类为厨房用具”的商品,右侧的圆圈代表符合查询条件“销售单价大于等于 3000 日元”的商品。两个圆重合的部分(同时满足两个查询条件的商品)就是通过 AND 运算符能够选取出的记录。
# or 运算符
or 运算符在其两侧的查询条件有一个成立时整个查询条件都成立 ,其意思相当于“或者” 。
选取出“商品种类为厨房用具(product_type = '厨房用具' ),或者 销售单价大于等于 3000 日元(sale_price >= 3000 )的商品”的数据:
SELECT product_name, purchase_price
FROM Product
WHERE product_type = '厨房用具'
OR sale_price >= 3000;
-- 执行结果:
+--------------+----------------+
| product_name | purchase_price |
+--------------+----------------+
| 运动T恤 | 2800 |
| 菜刀 | 2800 |
| 高压锅 | 5000 |
| 叉子 | NULL |
| 擦菜板 | 790 |
+--------------+----------------+
5 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
文氏图:
包含在左侧的圆圈(商品种类为厨房用具的商品)或者右侧的圆圈(销售单价大于等于 3000 日元的商品)中的部分就是通过 OR 运算符能够取出的记录。
# not 运算符
not 运算符表否定。NOT 不能单独使用,必须和其他查询条件组合起来使用。
比如,查询销售单价大于等于 1000 日元的记录:
mysql> SELECT product_name, product_type, sale_price
-> FROM Product
-> WHERE sale_price >= 1000;
+--------------+--------------+------------+
| product_name | product_type | sale_price |
+--------------+--------------+------------+
| T恤衫 | 衣服 | 1000 |
| 运动T恤 | 衣服 | 4000 |
| 菜刀 | 厨房用具 | 3000 |
| 高压锅 | 厨房用具 | 6800 |
+--------------+--------------+------------+
4 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
如果加了 not:
mysql> SELECT product_name, product_type, sale_price
-> FROM Product
-> WHERE NOT sale_price >= 1000;
+--------------+--------------+------------+
| product_name | product_type | sale_price |
+--------------+--------------+------------+
| 打孔器 | 办公用品 | 500 |
| 叉子 | 厨房用具 | 500 |
| 擦菜板 | 厨房用具 | 880 |
| 圆珠笔 | 办公用品 | 100 |
+--------------+--------------+------------+
4 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
通过否定销售单价大于等于 1000 日元(sale_price >= 1000 )这个查询条件,就可以选取出销售单价小于 1000 日元的商品。
但其实,选取出销售单价小于 1000 日元的商品,这样写更简单:
SELECT product_name, product_type
FROM Product
WHERE sale_price < 1000;
2
3
4
通过以上的例子大家可以发现,不使用 NOT 运算符也可以编写出效果相同的查询条件,并且更容易理解。
虽然如此,但是也不能完全否定 NOT 运算符的作用。在编写复杂的 SQL 语句时,经常会看到 NOT 的身影。这里只是希望大家了解 NOT 运算符的书写方法和工作原理,同时提醒大家不要滥用该运算符。
# 括号运算符
and 运算符的优先级是高于 or 运算符的。
假如我们想要查询这样的数据:“商品种类为办公用品”并且 “登记日期是 2009 年 9 月 11 日或者 2009 年 9 月 20 日”:
SELECT product_name, product_type, regist_date
FROM Product
WHERE product_type = '办公用品'
AND regist_date = '2009-09-11'
OR regist_date = '2009-09-20';
--结果:
+--------------+--------------+-------------+
| product_name | product_type | regist_date |
+--------------+--------------+-------------+
| T恤衫 | 衣服 | 2009-09-20 |
| 打孔器 | 办公用品 | 2009-09-11 |
| 菜刀 | 厨房用具 | 2009-09-20 |
| 叉子 | 厨房用具 | 2009-09-20 |
+--------------+--------------+-------------+
4 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
可以看到结果不太对,这样查询的结果是这样的商品:
- “商品种类为办公用品,并且登记日期是 2009 年 9 月 11 日”的商品
- “登记日期是 2009 年 9 月 20 日”的商品
这和想要指定的查询条件并不相符。
想要优先执行 OR 运算符时,可以使用括号运算符:
SELECT product_name, product_type, regist_date
FROM Product
WHERE product_type = '办公用品'
AND (regist_date = '2009-09-11'
OR regist_date = '2009-09-20');
--结果:
+--------------+--------------+-------------+
| product_name | product_type | regist_date |
+--------------+--------------+-------------+
| 打孔器 | 办公用品 | 2009-09-11 |
+--------------+--------------+-------------+
1 row in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
13
# 注意 null
在逻辑运算中,是对真值进行运算的,结果要么是真(true),要么是 false。
但是,null 的引入使得情况变的复杂了起来。为此,SQL 引入了第三种值-不确定(UNKNOWN)。一般的逻辑运算并不存在这第三种值。
包含“不确定”的逻辑运算,结果都是“不确定”。
由于引入 null 后,运算变的比较复杂,因此,数据库领域的有识之士们达成了“尽量不使用 NULL ”的共识。
# FROM 子句真的有必要吗?
实际上,FROM 子句在 SELECT 语句中并不是必不可少的,只使用 SELECT 子句进行计算也是可以的。例如:
SELECT (100 + 200) * 3 AS calculation;
--结果:
+-------------+
| calculation |
+-------------+
| 900 |
+-------------+
1 row in set (0.00 sec)
2
3
4
5
6
7
8
9
没有 from 子句的情况很少见。但是也存在像 Oracle 这样不允许省略 FROM 子句的 DBMS。