Skip to content

查询进阶

连接查询

连接是关系数据库模型的主要特点。
连接查询是关系数据库中最主要的查询,主要包括内连接、外连接等。通过连接运算符可以实现多个表查询。
在关系数据库管理修通中,表建立时各数据之间的关系不必确定,常把一个实体的所有信息存放在一个表中。
当查询数据时,通过连接操作查询出存放在多个表中的不同实体的信息。
当两个或多个表中存在相同意义的字段时,便可以通过这些字段对不同的表进行连接查询。

内连接查询

内连接(INNER JOIN)使用比较运算符进行表间某(些)列数据的比较操作,并列出这些表中与连接条件相匹配的数据行,组合成新的记录,
也就是说,在内连接查询中,只有满足条件的记录才能出现在结果关系中

首先创建表:

1
2
3
4
5
6
7
8
CREATE TABLE suppliers (
    s_id  INT NOT NULL AUTO_INCREMENT,
    s_name  CHAR(50) NOT NULL,
    s_city  CHAR(50) NULL,
    s_zip  CHAR(10) NULL,
    s_call  CHAR(50) NOT NULL,
    PRIMARY KEY (s_id)
);

插入数据:

1
2
3
4
5
6
7
8
9
INSERT INTO suppliers (s_id, s_name, s_city, s_zip, s_call)
VALUES
    (101, 'FastFruit Inc.','Tianjin','300000','48075'),
    (102,'LT Supplies', 'Chongqing','400000','44333'),
    (103,'ACME','Shanghai','200000','90046'),
    (104,'FNK Inc.', 'Zhongshan', '528437', '11111'),
    (105, 'Good Set', 'Taiyuan','030000','22222'),
    (106, 'Just Eat Ours','Beijing', '010', '45678'),
    (107, 'DK Inc.', 'Zhengzhou', '450000', '33332');

例: 在 fruits 表和 suppliers 表之间使用内连接查询:

查询之前,查看两个表的结构:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
mysql> DESC fruits;
+---------+--------------+------+-----+---------+-------+
| Field   | Type         | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| f_id    | char(10)     | NO   | PRI | NULL    |       |
| s_id    | int          | NO   |     | NULL    |       |
| f_name  | char(255)    | NO   |     | NULL    |       |
| f_price | decimal(8,2) | NO   |     | NULL    |       |
+---------+--------------+------+-----+---------+-------+
4 rows in set (0.08 sec)

mysql> DESC suppliers;
+--------+----------+------+-----+---------+----------------+
| Field  | Type     | Null | Key | Default | Extra          |
+--------+----------+------+-----+---------+----------------+
| s_id   | int      | NO   | PRI | NULL    | auto_increment |
| s_name | char(50) | NO   |     | NULL    |                |
| s_city | char(50) | YES  |     | NULL    |                |
| s_zip  | char(10) | YES  |     | NULL    |                |
| s_call | char(50) | NO   |     | NULL    |                |
+--------+----------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

由结果可以看到,fruits 表和 suppliers 表中都有相同类型的字段 s_id,两个表通过 s_id 字段建立联系。
接下来从 fruits 表中查询 f_name、f_price 字段,从 suppliers 表中查询 s_id、s_name

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
SELECT suppliers.s_id, s_name, f_name, f_price
FROM fruits, suppliers
WHERE fruits.s_id = suppliers.s_id;

+------+----------------+------------+---------+
| s_id | s_name         | f_name     | f_price |
+------+----------------+------------+---------+
|  101 | FastFruit Inc. | apple      |    5.20 |
|  103 | ACME           | apricot    |    2.20 |
|  101 | FastFruit Inc. | blackberry |   10.20 |
|  104 | FNK Inc.       | berry      |    7.60 |
|  107 | DK Inc.        | xxxx       |    3.60 |
|  102 | LT Supplies    | orange     |   11.20 |
|  105 | Good Set       | melon      |    8.20 |
|  101 | FastFruit Inc. | cherry     |    3.20 |
|  104 | FNK Inc.       | lemon      |    6.40 |
|  106 | Just Eat Ours  | mango      |   15.70 |
|  105 | Good Set       | xbaby      |    2.60 |
|  105 | Good Set       | xxtt       |   11.60 |
|  103 | ACME           | coconut    |    9.20 |
|  102 | LT Supplies    | banana     |   10.30 |
|  102 | LT Supplies    | grape      |    5.30 |
|  107 | DK Inc.        | xbababa    |    3.60 |
+------+----------------+------------+---------+
16 rows in set (0.01 sec)

在这里,SELECT 语句与前面所介绍的一个最大的差别是: SELECT 后面指定的列分别属于两个不同的表,(f_name, f_price) 在表 fruits 中,而另外两个字段在表 suppliers 中;
同时 FROM 子句列出了两个表 fruits 和 suppliers。
WHERE 子句在这里作为过滤条件,指明只有两个表中的 s_id 字段值相等的时候才符合连接查询的条件。
从返回的结果可以看到,显示的记录是由两个表中的不同列值组成的新纪录。

提示:

因为 fuits 表和 suppliers 表中有相同的字段 s_id,因此在比较的时候需要完全限定表名(格式为 "表名.列名"),如果只给出 s_id,MySQL 将不知道指的是哪一个,并返回错误信息。

下面的内连接查询语句返回与前面完全相同的结果:

例: 在 fruits 表和 suppliers 表之间,使用 INNER JOIN 语法进行内连接查询:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
SELECT suppliers.s_id, s_name, f_name, f_price
FROM fruits INNER JOIN suppliers
ON fruits.s_id = suppliers.s_id;

+------+----------------+------------+---------+
| s_id | s_name         | f_name     | f_price |
+------+----------------+------------+---------+
|  101 | FastFruit Inc. | apple      |    5.20 |
|  103 | ACME           | apricot    |    2.20 |
|  101 | FastFruit Inc. | blackberry |   10.20 |
|  104 | FNK Inc.       | berry      |    7.60 |
|  107 | DK Inc.        | xxxx       |    3.60 |
|  102 | LT Supplies    | orange     |   11.20 |
|  105 | Good Set       | melon      |    8.20 |
|  101 | FastFruit Inc. | cherry     |    3.20 |
|  104 | FNK Inc.       | lemon      |    6.40 |
|  106 | Just Eat Ours  | mango      |   15.70 |
|  105 | Good Set       | xbaby      |    2.60 |
|  105 | Good Set       | xxtt       |   11.60 |
|  103 | ACME           | coconut    |    9.20 |
|  102 | LT Supplies    | banana     |   10.30 |
|  102 | LT Supplies    | grape      |    5.30 |
|  107 | DK Inc.        | xbababa    |    3.60 |
+------+----------------+------------+---------+
16 rows in set (0.00 sec)

在这里的查询语句中,两个表之间的关系通过 INNER JOIN 指定。
使用这种语法的时候,连接的条件使用 ON 子句而不是 WHERE,ON 和 WHERE 后面指定的条件相同。

提示:
使用 WHERE 子句定义连接条件比较简单明了,而 INNER JOIN 语法是 ANSI SQL 的标准规范,使用 INNER JOIN 连接语法能够确保不会忘记连接条件,而且 WHERE 子句在某些时候会影响查询的性能。

自连接

如果一个连接查询中,涉及的两个表都是同一个表,这种查询称为自连接查询。
自连接是一种特殊的内连接,它是指相互连接的表在物理上为同一张表,但可以在逻辑上分为两张表。

例: 查询 f_id = 'a1' 的水果供应商提供的水果种类:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
SELECT f1.f_id, f1.f_name
FROM fruits AS f1, fruits AS f2
WHERE f1.s_id = f2.s_id AND f2.f_id = 'a1';

+------+------------+
| f_id | f_name     |
+------+------------+
| a1   | apple      |
| b1   | blackberry |
| c0   | cherry     |
+------+------------+
3 rows in set (0.00 sec)

此处查询的两个表是相同的表,为了防止产生二义性,对表使用了别名,fruits 表第 1 此出现的别名为 f1,第 2 此出现的别名为 f2,使用 SELECT 语句返回列明确指出返回以 f1 为前缀的列的全名,WHERE 连接两个表,并按照第 2 个表的 f_id 对数据进行过滤,返回所需数据

外连接查询

外连接查询将查询多个表中相关联的行,内连接时,返回查询结果集合中仅是符合查询条件和连接条件的行。
有时候需要包含没有关联的行中数据,即返回查询结果集合中不仅包含符合连接条件的行,还包括左表(左外连接或左连接)、右表(右外连接或右连接)或两个边接表(全外连接)中的所有数据行。
外连接分为左外连接或左连接和右外连接或右连接:

  • LEFT JOIN(左连接): 返回包括左表中的所有记录和右表中连接字段相等的记录
  • RIGHT JOIN(右连接): 返回包括右表中的所有记录和左表中连接字段相等的记录

LEFT JOIN(左连接)

左连接的结果包括 LEFT OUTER 子句中指定的左表的所有行,而不仅仅是连接列所匹配的行。
如果左表的某行在右表中没有匹配行,则在相关联的结果行中,右表的所有选择列均为空值。

首先创建表 orders:

1
2
3
4
5
6
CREATE TABLE orders (
    o_num  INT NOT NULL AUTO_INCREMENT,
    o_date  DATETIME NOT NULL,
    c_id  INT NOT NULL,
    PRIMARY KEY (o_num)
);

插入数据:

1
2
3
4
5
6
7
INSERT INTO orders (o_num, o_date, c_id)
VALUES
    (30001, '2008-09-01', 10001),
    (30002, '2008-09-12', 10003),
    (30003, '2008-09-30', 10004),
    (30004, '2008-10-03', 10005),
    (30005, '2008-10-08', 10001);

例: 在 customers 表和 orders 表中,查询所有客户,包括没有订单的客户:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
SELECT customers.c_id, orders.o_num
FROM customers LEFT OUTER JOIN orders
ON customers.c_id = orders.c_id;

+-------+-------+
| c_id  | o_num |
+-------+-------+
| 10001 | 30005 |
| 10001 | 30001 |
| 10002 |  NULL |
| 10003 | 30002 |
| 10004 | 30003 |
+-------+-------+
5 rows in set (0.01 sec)

结果显示了 5 条记录,ID 等于 10002 的客户目前并没有下订单,所以对应的 orders 表中并没有该客户的订单信息,所以该条记录只取出了 customers 表中相应的值,而从 orders 表中取出的值为空值 NULL

RIGHT JOIN 右连接

右连接是左连接的反向连接,将返回右表的所有行。如果右表的某行在左表中没有匹配行,左表将返回空值

例: 在 customers 表和 orders 表中,查询所有订单,包括没有客户的订单:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
SELECT customers.c_id, orders.o_num
FROM customers RIGHT OUTER JOIN orders
ON customers.c_id = orders.c_id;

+-------+-------+
| c_id  | o_num |
+-------+-------+
| 10001 | 30001 |
| 10003 | 30002 |
| 10004 | 30003 |
|  NULL | 30004 |
| 10001 | 30005 |
+-------+-------+
5 rows in set (0.00 sec)

复合条件连接查询

复合条件连接查询是在连接查询的过程中,通过添加过滤条件限制查询的结果,使查询的结果更加准确。

例: 在 customers 表和 orders 表中,使用 INNER JOIN 语法查询 customers 表中 ID 为 10001 的客户的订单信息:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
SELECT customers.c_id, orders.o_num
FROM customers INNER JOIN orders
ON customers.c_id = orders.c_id AND customers.c_id = 10001;

+-------+-------+
| c_id  | o_num |
+-------+-------+
| 10001 | 30001 |
| 10001 | 30005 |
+-------+-------+
2 rows in set (0.00 sec)

例: 在 fruits 表和 suppliers 表之间,使用 INNER JOIN 语法进行内连接查询,并对查询结果排序

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
SELECT suppliers.s_id, s_name, f_name, f_price
FROM fruits INNER JOIN suppliers
ON fruits.s_id = suppliers.s_id
ORDER BY fruits.s_id;

+------+----------------+------------+---------+
| s_id | s_name         | f_name     | f_price |
+------+----------------+------------+---------+
|  101 | FastFruit Inc. | apple      |    5.20 |
|  101 | FastFruit Inc. | blackberry |   10.20 |
|  101 | FastFruit Inc. | cherry     |    3.20 |
|  102 | LT Supplies    | orange     |   11.20 |
|  102 | LT Supplies    | banana     |   10.30 |
|  102 | LT Supplies    | grape      |    5.30 |
|  103 | ACME           | apricot    |    2.20 |
|  103 | ACME           | coconut    |    9.20 |
|  104 | FNK Inc.       | berry      |    7.60 |
|  104 | FNK Inc.       | lemon      |    6.40 |
|  105 | Good Set       | melon      |    8.20 |
|  105 | Good Set       | xbaby      |    2.60 |
|  105 | Good Set       | xxtt       |   11.60 |
|  106 | Just Eat Ours  | mango      |   15.70 |
|  107 | DK Inc.        | xxxx       |    3.60 |
|  107 | DK Inc.        | xbababa    |    3.60 |
+------+----------------+------------+---------+
16 rows in set (0.01 sec)

子查询

子查询值一个查询语句嵌套在另一个查询语句内部的查询。
在 SELECT 子句中先计算子查询,子查询结果作为外层另一个查询的过滤条件,查询可以基于一个表或者多个表。
子查询中常用的操作符有 ANY(SOME)、ALL、IN、EXISTS。
子查询可以添加到 SELECT、UPDATE 和 DELETE 语句中,而且可以进行多层嵌套。
子查询中也可以使用比较运算符,如 <,<=,>、>= 和 != 等。

带 ANY、SOME 关键字的子查询

ANY 和 SOME 关键字是同义词,表示满足其中任一条件,它们允许创建一个表达式对子查询的返回值列表进行比较,只要满足内层子查询中的任何一个比较条件,就返回一个结果作为外层查询的条件。

下面定义两个表 tbl1 和 tbl2:

1
2
3
4
5
6
7
CREATE TABLE tbl1 (
    num1 INT NOT NULL
);

CREATE TABLE tbl2 (
    num2 INT NOT NULL
);

分别向两个表中插入数据:

1
2
3
4
5
6
7
INSERT INTO tbl1
VALUES
    (1), (5), (13), (27);

INSERT INTO tbl2
VALUES
    (6),(14),(11),(20);

ANY 关键字接在一个比较操作符的后面,表示若与子查询返回的任何值比较为 TRUE,则返回 TRUE

例: 返回 tbl2 表的所有 num2 列,然后将 tb1 中的 num1 的值与之进行比较,只要大于 num2 的任何一个值,即为符合查询条件的结果:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SELECT num1
FrOM tbl1
WHERE num1 > ANY(SELECT num2 FROM tbl2);

+------+
| num1 |
+------+
|   13 |
|   27 |
+------+
2 rows in set (0.12 sec)

SELECT num1
FrOM tbl1
WHERE num1 > SOME(SELECT num2 FROM tbl2);

+------+
| num1 |
+------+
|   13 |
|   27 |
+------+
2 rows in set (0.01 sec)

在子查询中,返回的是 tbl2 表的所有 num2 列结果 (6,14,11,20),然后将 tbl1 中的 num1 列的值与之进行比较,只要大于 num2 列的任意一个数即为符合条件的结果。

带 ALL 关键字的子查询

ALL 关键字与 ANY 和 SOME 不同,使用 ALL 时需要同时满足所有内层查询的条件。

例: 返回 tbl1 表中比 tbl2 表 num2 列所有值都大的值:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
SELECT num1
FROM tbl1
WHERE num1 > ALL(SELECT num2 FROM tbl2);

+------+
| num1 |
+------+
|   27 |
+------+
1 row in set (0.00 sec)

带 EXISTS 关键字的子查询

EXISTS 关键字后面的参数是一个任意的子查询,系统对子查询进行运算以判断它是否返回行,如果至少返回一行,你那么 EXISTS 的结果为 true,此时外层查询语句将进行查询;
如果子查询没有返回任何行,那么 EXISTS 返回的结果是 false,此时外层语句将不进行查询。

例: 查询 suppliers 表中是否存在 s_id = 107 的供应商,如果存在,则查询 fruits 表中的记录

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
SELECT *
FROM fruits
WHERE EXISTS (SELECT s_name FROM suppliers WHERE s_id = 107);

+------+------+------------+---------+
| f_id | s_id | f_name     | f_price |
+------+------+------------+---------+
| a1   |  101 | apple      |    5.20 |
| a2   |  103 | apricot    |    2.20 |
| b1   |  101 | blackberry |   10.20 |
| b2   |  104 | berry      |    7.60 |
| b5   |  107 | xxxx       |    3.60 |
| bs1  |  102 | orange     |   11.20 |
| bs2  |  105 | melon      |    8.20 |
| c0   |  101 | cherry     |    3.20 |
| l2   |  104 | lemon      |    6.40 |
| m1   |  106 | mango      |   15.70 |
| m2   |  105 | xbaby      |    2.60 |
| m3   |  105 | xxtt       |   11.60 |
| o2   |  103 | coconut    |    9.20 |
| t1   |  102 | banana     |   10.30 |
| t2   |  102 | grape      |    5.30 |
| t4   |  107 | xbababa    |    3.60 |
+------+------+------------+---------+
16 rows in set (0.05 sec)

EXISTS 关键字可以和条件表达式一起使用

例: 查询 suppliers 表中是否存在 s_id = 107 的供应商,如果存在,则查询 fruits 表中的 f_price 大于 10.20 的记录:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
SELECT *
FROM fruits
WHERE f_price > 10.20 AND EXISTS (SELECT s_name FROM suppliers WHERE s_id = 107);

+------+------+--------+---------+
| f_id | s_id | f_name | f_price |
+------+------+--------+---------+
| bs1  |  102 | orange |   11.20 |
| m1   |  106 | mango  |   15.70 |
| m3   |  105 | xxtt   |   11.60 |
| t1   |  102 | banana |   10.30 |
+------+------+--------+---------+
4 rows in set (0.00 sec)

NOT EXISTS 与 EXISTS 使用方法相同,返回结果相反

提示:
EXISTS 和 NOT EXISTS 的结果只会取决于是否会返回行,而不取决于这些行的内容,所以这个子查询输入列表通常是无关紧要的

带 IN 关键字的子查询

IN 关键字进行子查询时,内层查询语句仅仅返回一个数据列,这个数据列例的值将提供给外层查询语句进行比较操作

例: 在 orderitems 表中查询 f_id 为 c0 的订单号,并根据订单号查询具有订单号的客户 c_id

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
SELECT c_id
FROM orders
WHERE o_num IN (SELECT o_num FROM orderitems WHERE f_id = 'c0');

+-------+
| c_id  |
+-------+
| 10004 |
| 10001 |
+-------+
2 rows in set (0.05 sec)

SELECT 语句中可以使用 NOT IN 关键字,其作用与 IN 正好相反

提示
子查询的功能也可以通过连接查询完成,但是子查询使得 MySQL 代码更容易阅读和编写

带比较运算符的子查询

例: 在 suppliers 表中查询 s_city 等于 "Tianjin" 的供应商 s_id,然后在 fruits 表中查询所有该供应商提供的水果的种类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
SELECT s_id, f_name
FROM fruits
WHERE s_id = (SELECT s1.s_id FROM suppliers AS s1 WHERE s1.s_city = 'Tianjin');

+------+------------+
| s_id | f_name     |
+------+------------+
|  101 | apple      |
|  101 | blackberry |
|  101 | cherry     |
+------+------------+
3 rows in set (0.01 sec)

例: 在 suppliers 表中查询 s_city 等于 "Tianjin" 的供应商 s_id,然后在 fruits 表中查询所有非该供应商提供的水果的种类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
SELECT s_id, f_name
FROM fruits
WHERE s_id <> (SELECT s1.s_id FROM suppliers AS s1 WHERE s1.s_city = 'Tianjin');

+------+---------+
| s_id | f_name  |
+------+---------+
|  103 | apricot |
|  104 | berry   |
|  107 | xxxx    |
|  102 | orange  |
|  105 | melon   |
|  104 | lemon   |
|  106 | mango   |
|  105 | xbaby   |
|  105 | xxtt    |
|  103 | coconut |
|  102 | banana  |
|  102 | grape   |
|  107 | xbababa |
+------+---------+
13 rows in set (0.00 sec)

这里使用了不等于运算符,结果和前面相反。

合并查询结果

利用 UNION 关键字,可以给出多条 SELECT 语句,并将它们的结果组合成单个结果集。
合并时,两个表对应的列数和数据类型必须相同。
各个 SELECT 语句之间使用 UNION 或 UNION ALL 关键字分隔。
UNION 不使用关键字 ALL,执行的时候删除重复的记录,所有返回的行多是唯一的;
使用关键字 ALL 的作用是不删除重复行也不对结果进行自动排序。基本语法格式如下:

1
2
3
SELECT column,... FROM table1
UNION [ALL]
SELECT column,... FROM table2;

例: 查询所有价格小于 9 的水果的信息,查询 s_id 等于 101 和 103 所有的水果的信息,使用 UNION 连接查询结果,SQL 语句如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
SELECT s_id,f_name,f_price
FROM fruits
WHERE f_price < 9.0
UNION
SELECT s_id,f_name,f_price
FROM fruits
WHERE s_id IN (101,103);

+------+------------+---------+
| s_id | f_name     | f_price |
+------+------------+---------+
|  101 | apple      |    5.20 |
|  103 | apricot    |    2.20 |
|  104 | berry      |    7.60 |
|  107 | xxxx       |    3.60 |
|  105 | melon      |    8.20 |
|  101 | cherry     |    3.20 |
|  104 | lemon      |    6.40 |
|  105 | xbaby      |    2.60 |
|  102 | grape      |    5.30 |
|  107 | xbababa    |    3.60 |
|  101 | blackberry |   10.20 |
|  103 | coconut    |    9.20 |
+------+------------+---------+
12 rows in set (0.06 sec)

例: 使用 UNION ALL 连接查询:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
SELECT s_id,f_name,f_price
FROM fruits
WHERE f_price < 9.0
UNION ALL
SELECT s_id,f_name,f_price
FROM fruits
WHERE s_id IN (101,103);

+------+------------+---------+
| s_id | f_name     | f_price |
+------+------------+---------+
|  101 | apple      |    5.20 |
|  103 | apricot    |    2.20 |
|  104 | berry      |    7.60 |
|  107 | xxxx       |    3.60 |
|  105 | melon      |    8.20 |
|  101 | cherry     |    3.20 |
|  104 | lemon      |    6.40 |
|  105 | xbaby      |    2.60 |
|  102 | grape      |    5.30 |
|  107 | xbababa    |    3.60 |
|  101 | apple      |    5.20 |
|  103 | apricot    |    2.20 |
|  101 | blackberry |   10.20 |
|  101 | cherry     |    3.20 |
|  103 | coconut    |    9.20 |
+------+------------+---------+
15 rows in set (0.01 sec)

由结果可以看到,这里总的记录数等于两条 SELECT 语句返回的记录数之和,连接查询结果并没有去除重复的行

提示:
UNION 和 UNION ALL 的区别: 使用 UNION ALL 的功能是不删除重复行,加上 ALL 关键字语句执行时所需要的资源少,所以尽可能地使用它,
因此知道有重复行但是想保留这些行,确定查询结果中不会有重复数据或者不需要去掉重复数据的时候,应当使用 UNION ALL 以提高查询效率。

为表和字段取别名

为表取别名

当表名字很长或者执行一些特殊查询时,为了方便操作或者多次使用相同的表时,可以为表指定别名,用这个别名替代表原来的名称。
为表取别名的基本语法格式为:

表名 [AS] 表别名

例: 为 orders 表取别名 o,查询 30001 订单的下单日期:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
SELECT *
FROM orders AS o
WHERE o.o_num = 30001;

+-------+---------------------+-------+
| o_num | o_date              | c_id  |
+-------+---------------------+-------+
| 30001 | 2008-09-01 00:00:00 | 10001 |
+-------+---------------------+-------+
1 row in set (0.02 sec)

例: 为 customers 和 orders 表分别取别名,并进行连接查询:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
SELECT c.c_id, o.o_num
FROM customers AS c LEFT OUTER JOIN orders AS o
ON c.c_id = o.c_id;

+-------+-------+
| c_id  | o_num |
+-------+-------+
| 10001 | 30005 |
| 10001 | 30001 |
| 10002 |  NULL |
| 10003 | 30002 |
| 10004 | 30003 |
+-------+-------+
5 rows in set (0.03 sec)

为字段取别名

在使用 SELECT 语句显示查询结果时,MySQL 会显示每个 SELECT 后面指定的输出列,
在有些情况下,显示的列的名称会很长或者名称不够直观,MySQL 可以指定列别名,替换字段或表达式

1
列名 [AS] 列别名

"列名" 为表中字段定义的名称,"列别名" 为字段新的名称,AS 关键字为可选参数。

例: 查询 fruits 表,为 f_name 取别名 fruit_name,f_price 取别名 fruit_price,为 fruits 表取别名 f1,查询表中 f_price < 8 的水果的名称:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
SELECT f1.f_name AS fruit_name, f1.f_price AS fruit_price
FROM fruits AS f1
WHERE f1.f_price < 8;

+------------+-------------+
| fruit_name | fruit_price |
+------------+-------------+
| apple      |        5.20 |
| apricot    |        2.20 |
| berry      |        7.60 |
| xxxx       |        3.60 |
| cherry     |        3.20 |
| lemon      |        6.40 |
| xbaby      |        2.60 |
| grape      |        5.30 |
| xbababa    |        3.60 |
+------------+-------------+
9 rows in set (0.01 sec)

也可以为 SELECT 子句中的计算字段取别名。
例如,对使用 COUNT 聚合函数或者 CONCAT 等系统函数执行的结果字段取别名。

例: 查询 suppliers 表中字段 s_name 和 s_city,使用 CONCAT 函数连接这两个字段值,并取列别名为 suppliers_title.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
SELECT CONCAT(TRIM(s_name), '(', TRIM(s_city), ')')
AS suppliers_title
FROM suppliers
ORDER BY s_name;

+-------------------------+
| suppliers_title         |
+-------------------------+
| ACME(Shanghai)          |
| DK Inc.(Zhengzhou)      |
| FastFruit Inc.(Tianjin) |
| FNK Inc.(Zhongshan)     |
| Good Set(Taiyuan)       |
| Just Eat Ours(Beijing)  |
| LT Supplies(Chongqing)  |
+-------------------------+
7 rows in set (0.02 sec)

提示:
表别名只在执行查询的时候使用,并不在返回结果中显示,
而列别名定义之后,将返回给客户端显示,显示的结果字段为字段列的别名。

使用正则表达式查询

正则表达式通常用来检索或替换那些符合某个模式的文本内容,根据指定的匹配模式匹配文本中符合要求的特殊字符串

8.0新特性-GROUP BY不再隐式排序

8.0新特性-通用表表达式

专家解惑