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)