MySQL使用入门--DML语句


DML操作是指对数据库中表记录的操作,主要包括表记录的插入(insert)、更新(update)、删除(delete)和查询(select),是开发人员日常使用最频繁的操作。

1、插入记录

INSERT INTO tablename(field1,field2,......fieldn) VALUES(value1,value2,......valuesn);
示例

插入格式1:

mysql> DESC emp;
+----------+---------------+------+-----+---------+-------+
| Field    | Type          | Null | Key | Default | Extra |
+----------+---------------+------+-----+---------+-------+
| ename    | varchar(20)   | YES  |     | NULL    |       |
| hiredate | date          | YES  |     | NULL    |       |
| sal      | decimal(10,2) | YES  |     | NULL    |       |
| deptno   | int(2)        | YES  |     | NULL    |       |
+----------+---------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

mysql> INSERT INTO emp(ename,hiredate,sal,deptno) VALUES('zzx1','2000-01-01','2000',1);
Query OK, 1 row affected (0.01 sec)

也可以不用指定字段名称,但是VALUES后面的顺序应该和字段的排列顺序一致:

mysql> INSERT INTO emp VALUES('lisa','2003-02-01','3000',2);
Query OK, 1 row affected (0.01 sec)

对于含可空字段、非空但是含有默认值的字段、自增字段,可以不用在INSERT后的字段列表里面出现,VALUES后面只写对应字段名称的VALUE:

mysql> INSERT INTO emp(ename,sal) VALUES('dony',1000);
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM emp;
+-------+------------+---------+--------+
| ename | hiredate   | sal     | deptno |
+-------+------------+---------+--------+
| zzx1  | 2000-01-01 | 2000.00 |      1 |
| lisa  | 2003-02-01 | 3000.00 |      2 |
| dony  | NULL       | 1000.00 |   NULL |
+-------+------------+---------+--------+
3 rows in set (0.00 sec)

在MySQL中,INSERT语句还可以一次性插入多条记录:

INSERT INTO tablename(field1,field2,......fieldn)
VALUES
(record1_value1,record1_value2,......record1_valuen),
(record2_value1,record2_value2,......record2_valuen),
......
(recordn_value1,recordn_value2,......recordn_valuen);

示例

mysql> CREATE TABLE dept(deptno INT(4),deptname VARCHAR(20));
Query OK, 0 rows affected (0.02 sec)

mysql> DESC dept;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| deptno   | int(4)      | YES  |     | NULL    |       |
| deptname | varchar(20) | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> INSERT INTO dept VALUES(1,'dept1'),(2,'dept2');
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM dept;
+--------+----------+
| deptno | deptname |
+--------+----------+
|      1 | dept1    |
|      2 | dept2    |
+--------+----------+
2 rows in set (0.00 sec)

 

2、更新记录

修改表内的值

UPDATE tablename SET field1=value1,field2=value2,......fieldn=valuen [WHERE CONDITION];

示例:

mysql> SELECT * FROM emp;
+-------+------------+---------+--------+
| ename | hiredate   | sal     | deptno |
+-------+------------+---------+--------+
| zzx1  | 2000-01-01 | 2000.00 |      1 |
| lisa  | 2003-02-01 | 3000.00 |      2 |
| dony  | NULL       | 1000.00 |   NULL |
+-------+------------+---------+--------+
3 rows in set (0.00 sec)

mysql> UPDATE emp SET sal=4000 WHERE ename='lisa';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT * FROM emp;
+-------+------------+---------+--------+
| ename | hiredate   | sal     | deptno |
+-------+------------+---------+--------+
| zzx1  | 2000-01-01 | 2000.00 |      1 |
| lisa  | 2003-02-01 | 4000.00 |      2 |
| dony  | NULL       | 1000.00 |   NULL |
+-------+------------+---------+--------+
3 rows in set (0.00 sec)

在MySQL中,UPDATE 命令可以同时更新多个表中数据:

UPDATE t1,t2,...tn SET 
t1.field1=expr1,
t2.field2=expr2,
...
tn.fieldn=exprn [WHERE CONDITION];

示例:

同时更新表emp中的字段sal和表dept中的字段deptname:

mysql> SHOW TABLES;
+----------------+
| Tables_in_test |
+----------------+
| dept           |
| emp            |
+----------------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM emp;
+-------+------------+---------+--------+
| ename | hiredate   | sal     | deptno |
+-------+------------+---------+--------+
| zzx1  | 2000-01-01 | 2000.00 |      1 |
| lisa  | 2003-02-01 | 4000.00 |      2 |
| dony  | NULL       | 1000.00 |   NULL |
+-------+------------+---------+--------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM dept;
+--------+----------+
| deptno | deptname |
+--------+----------+
|      1 | dept1    |
|      2 | dept2    |
+--------+----------+
2 rows in set (0.00 sec)

mysql> UPDATE emp a,dept b SET a.sal=a.sal*b.deptno,b.deptname=a.ename WHERE a.deptno=b.deptno;
Query OK, 3 rows affected (0.00 sec)
Rows matched: 4  Changed: 3  Warnings: 0

mysql> SELECT * FROM emp;
+-------+------------+---------+--------+
| ename | hiredate   | sal     | deptno |
+-------+------------+---------+--------+
| zzx1  | 2000-01-01 | 2000.00 |      1 |
| lisa  | 2003-02-01 | 8000.00 |      2 |
| dony  | NULL       | 1000.00 |   NULL |
+-------+------------+---------+--------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM dept;
+--------+----------+
| deptno | deptname |
+--------+----------+
|      1 | zzx1     |
|      2 | lisa     |
+--------+----------+
2 rows in set (0.00 sec)

注意:多表更新的语法更多地用在了根据一个表的字段,来动态的更新另一个表的字段。

 

3、删除记录

DELETE FROM tablename [WHERE CONDITION];

示例:

mysql> SELECT * FROM emp;
+-------+------------+---------+--------+
| ename | hiredate   | sal     | deptno |
+-------+------------+---------+--------+
| zzx1  | 2000-01-01 | 2000.00 |      1 |
| lisa  | 2003-02-01 | 8000.00 |      2 |
| dony  | NULL       | 1000.00 |   NULL |
+-------+------------+---------+--------+
3 rows in set (0.00 sec)

mysql> DELETE FROM emp WHERE ename='dony';
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM emp;
+-------+------------+---------+--------+
| ename | hiredate   | sal     | deptno |
+-------+------------+---------+--------+
| zzx1  | 2000-01-01 | 2000.00 |      1 |
| lisa  | 2003-02-01 | 8000.00 |      2 |
+-------+------------+---------+--------+
2 rows in set (0.00 sec)

 

在MySQL中可以一次删除多个表的数据:

DELETE t1,t2,...tn FROM t1,t2,...tn [WHERE CONDITION];

示例:

mysql> SELECT * FROM emp;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| zzx1   | 2000-01-01 | 2000.00 |      1 |
| lisa   | 2003-02-01 | 8000.00 |      2 |
| bjguan | 2004-04-02 |  100.00 |      1 |
| dony   | 2005-02-05 | 5000.00 |      4 |
| bzshen | 2005-09-01 | 4000.00 |      5 |
+--------+------------+---------+--------+
5 rows in set (0.00 sec)

mysql> SELECT * FROM dept;
+--------+----------+
| deptno | deptname |
+--------+----------+
|      1 | zzx1     |
|      2 | lisa     |
|      3 | hr       |
|      5 | fin      |
+--------+----------+
4 rows in set (0.00 sec)

mysql> DELETE a,b FROM emp a, dept b WHERE a.deptno=b.deptno AND a.deptno=1;
Query OK, 3 rows affected (0.01 sec)

mysql> SELECT * FROM emp;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| lisa   | 2003-02-01 | 8000.00 |      2 |
| dony   | 2005-02-05 | 5000.00 |      4 |
| bzshen | 2005-09-01 | 4000.00 |      5 |
+--------+------------+---------+--------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM dept;
+--------+----------+
| deptno | deptname |
+--------+----------+
|      2 | lisa     |
|      3 | hr       |
|      5 | fin      |
+--------+----------+
3 rows in set (0.00 sec)

注意:不管是单表还是多表,不加where条件将会把表的所有记录删除,所以操作时一定要小心。

 

4、查询记录

SELECT 基本语法:

SELECT * FROM tablename [WHERE CONDITION];

其中“*”表示要将所有的记录都选出来,也可以用逗号分割的所有字段来代替。

实际应用中,各种各样的查询要求:

(1)查询不重复的记录,可以用distinct关键字实现:

mysql> SELECT ename,hiredate,sal,deptno FROM emp;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| lisa   | 2003-02-01 | 8000.00 |      1 |
| dony   | 2005-02-05 | 5000.00 |      4 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
+--------+------------+---------+--------+
3 rows in set (0.00 sec)

mysql> SELECT DISTINCT deptno FROM emp;
+--------+
| deptno |
+--------+
|      1 |
|      4 |
+--------+
2 rows in set (0.00 sec)

 

(2)条件查询

需要查询所有 deptno为1的记录:

SELECT * FROM emp WHERE deptno=1;

其中,where 后面的条件除“=” 外,还可以使用 >、<、>=、<=、!=等比较运算符;

多个条件之间还可以使用or、and等逻辑运算符进行多条件联合查询:

mysql> SELECT * FROM emp;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| lisa   | 2003-02-01 | 8000.00 |      1 |
| dony   | 2005-02-05 | 5000.00 |      4 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
+--------+------------+---------+--------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM emp WHERE deptno=1 AND sal<5000;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| bzshen | 2005-09-01 | 4000.00 |      1 |
+--------+------------+---------+--------+
1 row in set (0.00 sec)

 

(3)排序和限制

SELECT * FROM tablename [WHERE CONDITION] [ORDER BY field1 [DESC|ASC], field2 [DESC|ASC],...fieldn [DESC|ASC]];

其中,DESC和ASC是排序关键字,

DESC表示按照字段进行降序排列(上大-下小),
ASC则表示升序排列(上小-下大),
如果不写此关键字默认是升序排列。
ORDER BY 后面可以跟多个不同的排列字段,并且每个排序字段可以有不同的排序顺序。
如果排序字段的值一样,则值相同的字段按照第二个排序字段进行排序,以此类推。如果只有一个排序字段,则这字段相同的记录将会无序排列。

把emp表中的记录按照工资高低进行显示:

mysql> SELECT * FROM emp;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| lisa   | 2003-02-01 | 8000.00 |      1 |
| dony   | 2005-02-05 | 5000.00 |      4 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
| zzx    | 2000-01-01 | 3000.00 |      3 |
| bjguan | 2004-04-02 | 3000.00 |      1 |
+--------+------------+---------+--------+
5 rows in set (0.00 sec)

mysql> SELECT * FROM emp ORDER BY sal;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| zzx    | 2000-01-01 | 3000.00 |      3 |
| bjguan | 2004-04-02 | 3000.00 |      1 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
| dony   | 2005-02-05 | 5000.00 |      4 |
| lisa   | 2003-02-01 | 8000.00 |      1 |
+--------+------------+---------+--------+
5 rows in set (0.00 sec)

按部门编号,工资排列显示:

mysql> SELECT * FROM emp ORDER BY deptno;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| lisa   | 2003-02-01 | 8000.00 |      1 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
| bjguan | 2004-04-02 | 3000.00 |      1 |
| zzx    | 2000-01-01 | 3000.00 |      3 |
| dony   | 2005-02-05 | 5000.00 |      4 |
+--------+------------+---------+--------+
5 rows in set (0.00 sec)

mysql> SELECT * FROM emp ORDER BY deptno ASC, sal DESC;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| lisa   | 2003-02-01 | 8000.00 |      1 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
| bjguan | 2004-04-02 | 3000.00 |      1 |
| zzx    | 2000-01-01 | 3000.00 |      3 |
| dony   | 2005-02-05 | 5000.00 |      4 |
+--------+------------+---------+--------+
5 rows in set (0.00 sec)

mysql> SELECT * FROM emp ORDER BY deptno DESC, sal ASC;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| dony   | 2005-02-05 | 5000.00 |      4 |
| zzx    | 2000-01-01 | 3000.00 |      3 |
| bjguan | 2004-04-02 | 3000.00 |      1 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
| lisa   | 2003-02-01 | 8000.00 |      1 |
+--------+------------+---------+--------+
5 rows in set (0.00 sec)

对于排序后的记录,如果希望只显示一部分,而不是全部,这时,就可以使用LIMIT关键字来实现,语法:

SELECT ......[LIMIT offset_start,row_count];

其中offset_start表示记录的起始偏移量,row_count表示显示的行数。
在默认情况下,起始偏移量为0,只需要写记录行数就可以,此时,显示的实际就是前n条记录。
示例:显示emp表中按照sal排序后的前3条记录:

mysql> SELECT * FROM emp ORDER BY sal;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| zzx    | 2000-01-01 | 3000.00 |      3 |
| bjguan | 2004-04-02 | 3000.00 |      1 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
| dony   | 2005-02-05 | 5000.00 |      4 |
| lisa   | 2003-02-01 | 8000.00 |      1 |
+--------+------------+---------+--------+
5 rows in set (0.00 sec)

mysql> SELECT * FROM emp ORDER BY sal LIMIT 3;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| bjguan | 2004-04-02 | 3000.00 |      1 |
| zzx    | 2000-01-01 | 3000.00 |      3 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
+--------+------------+---------+--------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM emp ORDER BY sal LIMIT 2,3;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| bzshen | 2005-09-01 | 4000.00 |      1 |
| dony   | 2005-02-05 | 5000.00 |      4 |
| lisa   | 2003-02-01 | 8000.00 |      1 |
+--------+------------+---------+--------+
3 rows in set (0.00 sec)

LIMIT 经常和ORDER BY一起配合使用来进行记录的分页显示。

注意:limit属于MySQL扩展SQL92后的语法,在其他数据库上并不能通用。

 

(4)聚合

很多情况下,我们需要进行一些汇总操作,比如统计整个公司的人数或者统计每个部门的人数,这是就要用到SQL的集合操作。语法:

SELECT [field1,field2,......fieldn] fun_name
FROM tablename
[WHERE where_contition]
[GROUP BY field1,field2,......fieldn
[WITH ROLLUP]]
[HAVING where_contition];

对其参数进行以下说明:

  • fun_name 表示要做的集合操作,也就是聚合函数,常用的有sum(求和)、count(*)(记录数)、max(最大值)、min(最小值)。
  • GROUP BY 关键字表示要进行分类聚合的字段,比如要按照部门分类统计员工数量,部门就应该写在group by后面。
  • WITH ROLLUP 是可选语法,表明是否对分类聚合后的结果进行再汇总。
  • HAVING 关键字表示对分类后的结果再进行条件的过滤。

注意:having和where的区别在于having是对聚合后的结果进行条件的过滤,而where是在聚合前就对记录进行过滤,如果逻辑允许,我们尽可能用where先过滤记录,这样因为结果集减小,将对聚合的效率大大提高,最后再根据逻辑看是否用having进行再过滤。

 

聚合还是比较常用的,下面是一些常用示例:

要emp表中统计公司总人数:

mysql> SELECT COUNT(1) FROM emp;
+----------+
| COUNT(1) |
+----------+
|        5 |
+----------+
1 row in set (0.00 sec)

在此基础上,要统计各个部门的人数:

mysql> SELECT deptno,COUNT(1) FROM emp GROUP BY deptno;
+--------+----------+
| deptno | COUNT(1) |
+--------+----------+
|      1 |        3 |
|      3 |        1 |
|      4 |        1 |
+--------+----------+
3 rows in set (0.00 sec)

更细些,既要统计各部门人数,又要统计总人数:

mysql> SELECT deptno,COUNT(1) FROM emp GROUP BY deptno WITH ROLLUP;
+--------+----------+
| deptno | COUNT(1) |
+--------+----------+
|      1 |        3 |
|      3 |        1 |
|      4 |        1 |
|   NULL |        5 |
+--------+----------+
4 rows in set (0.00 sec)

统计人数大于 1 人的部门:

mysql> SELECT deptno,COUNT(1) FROM emp GROUP BY deptno HAVING COUNT(1)>1;
+--------+----------+
| deptno | COUNT(1) |
+--------+----------+
|      1 |        3 |
+--------+----------+
1 row in set (0.00 sec)

最后统计公司所有员工的薪水总额、最高和最低薪水:

mysql> SELECT SUM(sal),MAX(sal),MIN(sal) FROM emp;
+----------+----------+----------+
| SUM(sal) | MAX(sal) | MIN(sal) |
+----------+----------+----------+
| 23000.00 |  8000.00 |  3000.00 |
+----------+----------+----------+
1 row in set (0.00 sec)

 

(5) 表连接

当需要同时显示多个表中的字段时,就可以用表连接来实现,这样的功能。
从大类上分,表连接分为内连接和外连接,它们之间的最主要区别是:
内连接仅选出两张表中互相匹配的记录,
而外连接会选出其他不匹配的记录。我们常用的是内连接。
例如:查询出所有雇员的名字和所在部门名称,因为雇员名称和部门分别存放在表emp和dept中,因此,需要使用表连接来进行查询:

mysql> SELECT * FROM emp;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| lisa   | 2003-02-01 | 8000.00 |      1 |
| dony   | 2005-02-05 | 5000.00 |      2 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
| zzx    | 2000-01-01 | 3000.00 |      3 |
| bjguan | 2004-04-02 | 3000.00 |      1 |
+--------+------------+---------+--------+
5 rows in set (0.00 sec)

mysql> SELECT * FROM dept;
+--------+----------+
| deptno | deptname |
+--------+----------+
|      1 | tech     |
|      3 | hr       |
|      2 | sale     |
+--------+----------+
3 rows in set (0.00 sec)

mysql> SELECT ename,deptname FROM emp,dept WHERE emp.deptno=dept.deptno;
+--------+----------+
| ename  | deptname |
+--------+----------+
| lisa   | tech     |
| dony   | sale     |
| bzshen | tech     |
| zzx    | hr       |
| bjguan | tech     |
+--------+----------+
5 rows in set (0.00 sec)

外连接有分为左连接和右连接,具体定义如下:

  • 左连接:包含所有的左边表中的记录甚至是右边表中没有和它匹配的记录
  • 右连接:包含所有的右边表中的记录甚至是左边表中没有和它匹配的记录

例如,查询emp中所有用户和所在部门名称:

mysql> SELECT * FROM emp;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| lisa   | 2003-02-01 | 8000.00 |      1 |
| dony   | 2005-02-05 | 5000.00 |      2 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
| zzx    | 2000-01-01 | 3000.00 |      3 |
| bjguan | 2004-04-02 | 3000.00 |      1 |
| atai   | 1999-01-01 | 8000.00 |      4 |
+--------+------------+---------+--------+
6 rows in set (0.00 sec)

mysql> SELECT * FROM dept;
+--------+----------+
| deptno | deptname |
+--------+----------+
|      1 | tech     |
|      3 | hr       |
|      2 | sale     |
+--------+----------+
3 rows in set (0.00 sec)
mysql
> SELECT ename,deptname FROM emp LEFT JOIN dept ON emp.deptno=dept.deptno; +--------+----------+ | ename | deptname | +--------+----------+ | lisa | tech | | bzshen | tech | | bjguan | tech | | zzx | hr | | dony | sale | | atai | NULL | +--------+----------+ 6 rows in set (0.00 sec)

员工atai 部门号为 4,在dept中没有这个部门。

右连接和左连接类似:

mysql> SELECT ename,deptname FROM dept RIGHT JOIN emp ON dept.deptno=emp.deptno;
+--------+----------+
| ename  | deptname |
+--------+----------+
| lisa   | tech     |
| bzshen | tech     |
| bjguan | tech     |
| zzx    | hr       |
| dony   | sale     |
| atai   | NULL     |
+--------+----------+
6 rows in set (0.01 sec)

 

(6)子查询

某些情况,当我们查询的时候,需要的条件是另一个SELECT语句的结果,这个时候,就要用到子查询。

用于子查询的关键字主要包括in、not in、=、!=、exists、not exists等。

例如,从emp表中查询出所有部门在dept表中的所有记录:

mysql> SELECT * FROM emp;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| lisa   | 2003-02-01 | 8000.00 |      1 |
| dony   | 2005-02-05 | 5000.00 |      2 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
| zzx    | 2000-01-01 | 3000.00 |      3 |
| bjguan | 2004-04-02 | 3000.00 |      1 |
| atai   | 1999-01-01 | 8000.00 |      4 |
+--------+------------+---------+--------+
6 rows in set (0.00 sec)

mysql> SELECT * FROM dept;
+--------+----------+
| deptno | deptname |
+--------+----------+
|      1 | tech     |
|      3 | hr       |
|      2 | sale     |
|      5 | fin      |
+--------+----------+
4 rows in set (0.00 sec)
mysql
> SELECT * FROM emp WHERE deptno IN(SELECT deptno FROM dept); +--------+------------+---------+--------+ | ename | hiredate | sal | deptno | +--------+------------+---------+--------+ | lisa | 2003-02-01 | 8000.00 | 1 | | dony | 2005-02-05 | 5000.00 | 2 | | bzshen | 2005-09-01 | 4000.00 | 1 | | zzx | 2000-01-01 | 3000.00 | 3 | | bjguan | 2004-04-02 | 3000.00 | 1 | +--------+------------+---------+--------+ 5 rows in set (0.00 sec)

如果子查询记录数唯一,还可以用=代替in:

mysql> SELECT * FROM emp WHERE deptno=(SELECT deptno FROM dept LIMIT 1);
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| lisa   | 2003-02-01 | 8000.00 |      1 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
| bjguan | 2004-04-02 | 3000.00 |      1 |
+--------+------------+---------+--------+
3 rows in set (0.01 sec)

某些情况下,子查询可以转化为表连接,例如:

mysql> SELECT * FROM emp WHERE deptno IN(SELECT deptno FROM dept);
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| lisa   | 2003-02-01 | 8000.00 |      1 |
| dony   | 2005-02-05 | 5000.00 |      2 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
| zzx    | 2000-01-01 | 3000.00 |      3 |
| bjguan | 2004-04-02 | 3000.00 |      1 |
+--------+------------+---------+--------+
5 rows in set (0.00 sec)

转换为表连接后:

mysql> SELECT emp.* FROM emp,dept WHERE emp.deptno=dept.deptno;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| lisa   | 2003-02-01 | 8000.00 |      1 |
| dony   | 2005-02-05 | 5000.00 |      2 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
| zzx    | 2000-01-01 | 3000.00 |      3 |
| bjguan | 2004-04-02 | 3000.00 |      1 |
+--------+------------+---------+--------+
5 rows in set (0.00 sec)

注意:子查询和表连接之间的转换主要应用在两个方面:

  • MySQL 4.1 以前的版本不支持子查询,需要用表连接来实现子查询的功能
  • 表连接在很多情况下用于优化子查询

(7)记录联合

我们经常会碰到这样的应用,将两个表的数据按照一定的查询条件查询出来后,将结果合并到一起显示出来,这个时候,就需要用到union和union all关键字来实现这样的功能,具体语法如下:

SELECT * FROM t1
UNION|UNION ALL
SELECT * FROM t2
......
UNION|UNION ALL
SELECT * FROM tn;

UNION 和 UNION ALL的主要区别是 UNION ALL 是把结果集直接合并在一起,而UNION是将UNION ALL后的结果进行一次DISTINCT,去除重复记录后的结果。

例如,将emp和dept表中的部门编号的集合显示出来:

mysql> SELECT * FROM emp;
+--------+------------+---------+--------+
| ename  | hiredate   | sal     | deptno |
+--------+------------+---------+--------+
| lisa   | 2003-02-01 | 8000.00 |      1 |
| dony   | 2005-02-05 | 5000.00 |      2 |
| bzshen | 2005-09-01 | 4000.00 |      1 |
| zzx    | 2000-01-01 | 3000.00 |      3 |
| bjguan | 2004-04-02 | 3000.00 |      1 |
| atai   | 1999-01-01 | 8000.00 |      4 |
+--------+------------+---------+--------+
6 rows in set (0.01 sec)

mysql> SELECT * FROM dept;
+--------+----------+
| deptno | deptname |
+--------+----------+
|      1 | tech     |
|      3 | hr       |
|      2 | sale     |
|      5 | fin      |
+--------+----------+
4 rows in set (0.00 sec)

mysql> SELECT deptno FROM emp
    -> UNION ALL
    -> SELECT deptno FROM dept;
+--------+
| deptno |
+--------+
|      1 |
|      2 |
|      1 |
|      3 |
|      1 |
|      4 |
|      1 |
|      3 |
|      2 |
|      5 |
+--------+
10 rows in set (0.00 sec)

如果希望将结果去掉重复记录后显示:

mysql> SELECT deptno FROM emp
    -> UNION
    -> SELECT deptno FROM dept;
+--------+
| deptno |
+--------+
|      1 |
|      2 |
|      3 |
|      4 |
|      5 |
+--------+
5 rows in set (0.00 sec)

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM