DML 语句:
DML 操作是指对数据库中表记录的操作,主要包括表记录的插入(insert)、更新(update)、删除(delete)和查(select),是开发人员日常使用最频繁的操作。下面将依次对它们进行介绍。
1.插入记录
表创建好后,就可以往里插入记录了,插入记录的基本语法如下:
INSERT INTO tablename (field1,field2,……fieldn) VALUES(value1,value2,……valuesn);
例如,向表 emp 中插入以下记录:ename 为 zzx1,hiredate 为 2000-01-01,sal 为 2000,deptno为 1,命令执行如下:
mysql> insert into emp (ename,hiredate,sal,deptno) values('zzx1','2000-01-01','2000',1);
也可以不用指定字段名称,但是 values 后面的顺序应该和字段的排列顺序一致(不推荐使用):
mysql> insert into emp values('lisa','2003-02-01','3000',2);
技巧:对于含可空字段、非空但是含有默认值的字段、自增字段,可以不用在 insert 后的字段列表里面出现,values 后面只写对应字段名称的 value,这些没写的字段可以自动设置为 NULL、默认值、自增的下一个数字,这样在某些情况下可以大大缩短 SQL 语句的复杂性。
例如,只对表中的 ename 和 sal 字段显式插入值:mysql> insert into emp (ename,sal) values('dony',1000);
在 MySQL 中,insert 语句还有一个很好的特性,可以一次性插入多条记录,语法如下:
INSERT INTO tablename (field1, field2,……fieldn)
VALUES
(record1_value1, record1_value2,……record1_valuesn),
(record2_value1, record2_value2,……record2_valuesn),
……
(recordn_value1, recordn_value2,……recordn_valuesn)
;
可以看出,每条记录之间都用逗号进行了分隔。
下面的例子中,对表 dept 一次插入两条记录:mysql> insert into dept values(5,'dept5'),(6,'dept6');
这个特性可以使得 MySQL 在插入大量记录时,节省很多的网络开销,大大提高插入效率。
2.更新记录
对于表里的记录值,可以通过 update 命令进行更改,语法如下:
UPDATE tablename SET field1=value1,field2.=value2,……fieldn=valuen [WHERE CONDITION]
例如,将表 emp 中 ename 为“lisa”的薪水(sal)从 3000 更改为 4000:mysql> update emp set sal=4000 where ename='lisa';
在 MySQL 中,update 命令可以同时更新多个表中数据,语法如下:
UPDATE t1,t2…tn set t1.field1=expr1,tn.fieldn=exprn [WHERE CONDITION]
在下例中,同时更新表 emp 中的字段 sal 和表 dept 中的字段 deptname:
mysql> update emp a,dept b set a.sal=a.sal*b.deptno,b.deptname=a.ename where a.deptno=b.deptno;
自此,两个表的数据同时进行了更新。
注意:多表更新的语法更多地用在了根据一个表的字段,来动态的更新另外一个表的字段
3.删除记录
如果记录不再需要,可以用 delete 命令进行删除,语法如下:DELETE FROM tablename [WHERE CONDITION]
例如,在 emp 中将 ename 为‘dony’的记录全部删除,命令如下:mysql> delete from emp where ename='dony';
在 MySQL 中可以一次删除多个表的数据,语法如下:DELETE t1,t2…tn FROM t1,t2…tn [WHERE CONDITION]
注意:如果 from 后面的表名用别名,则 delete 后面的也要用相应的别名,否则会提示语法错误。
在下例中,将表 emp 和 dept 中 deptno 为 3 的记录同时都删除:
mysql> delete a,b from emp a,dept b where a.deptno=b.deptno and a.deptno=3;
注意:不管是单表还是多表,不加 where 条件将会把表的所有记录删除,所以操作时一定要小心。
4.查询记录(重点)
数据插入到数据库中后,就可以用 SELECT 命令进行各种各样的查询,使得输出的结果符合我们的要求。由于 SELECT 的语法很复杂,所有这里只介绍最基本的语法:SELECT * FROM tablename [WHERE CONDITION]
查询最简单的方式是将记录全部选出,在下面的例子中,将表 emp 中的记录全部查询出来:mysql> select * from emp;
其中“*”表示要将所有的记录都选出来,也可以用逗号分割的所有字段来代替。“*”的好处是当需要查询所有字段信息时候,查询语句很简单,但是要只查询部分字段的时候,必须要将字段一个一个列出来。
上例中已经介绍了查询全部记录的语法,但是在实际应用中,用户还会遇到各种各样的查询
要求,下面将分别介绍。
(1)查询不重复的记录。
有时需要将表中的记录去掉重复后显示出来,可以用 distinct 关键字来实现:
mysql> select ename,hiredate,sal,deptno from emp;
+--------+------------+---------+--------+
| ename | hiredate | sal | deptno |
+--------+------------+---------+--------+
| zzx | 2000-01-01 | 2000.00 | 1 |
| lisa | 2003-02-01 | 4000.00 | 2 |
| bjguan | 2004-04-02 | 5000.00 | 1 |
+--------+------------+---------+--------+
3 rows in set (0.00 sec)
mysql> select distinct deptno from emp;
+--------+
| deptno |
+--------+
| 1 |
| 2 |
+--------+
2 rows in set (0.00 sec)
(2)条件查询。
在很多情况下,用户并不需要查询所有的记录,而只是需要根据限定条件来查询一部分数据,用 where 关键字可以来实现这样的操作。
例如,需要查询所有 deptno 为 1 的记录:mysql> select * from emp where deptno=1;
结果集中将符合条件的记录列出来。上面的例子中,where 后面的条件是一个字段的‘=’比较,除了‘=’外,还可以使用>、<、>=、<=、!=等比较运算符;多个条件之间还可以使用 or、and 等逻辑运算符进行多条件联合查询,运算符会在以后章节中详细讲解。
以下是一个使用多字段条件查询的例子:mysql> select * from emp where deptno=1 and sal<3000;
(3)排序和限制。
我们经常会有这样的需求,取出按照某个字段进行排序后的记录结果集,这就用到了数据库的排序操作,用关键字 ORDER BY 来实现,语法如下: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 order by sal;
如果排序字段的值一样,则值相同的字段按照第二个排序字段进行排序,以此类推。如果只有一个排序字段,则这些字段相同的记录将会无序排列。对于排序后的记录,如果希望只显示一部分,而不是全部,这时,就可以使用 LIMIT 关键字
来实现,LIMIT 的语法如下:SELECT ……[LIMIT offset_start,row_count]
其中 offset_start 表示记录的起始偏移量,row_count 表示显示的行数。
在默认情况下,起始偏移量为 0,只需要写记录行数就可以,这时候,显示的实际就是前 n条记录,看下面例子:
例如,显示 emp 表中按照 sal 排序后的前 3 条记录:mysql> select * from emp order by sal limit 3;
如果要显示 emp 表中按照 sal 排序后从第二条记录开始,显示 3 条记录:mysql> select * from emp order by sal limit 1,3;
注意:如果limit后面只有一个数字的时候指的是显示的行数。limit 经常和 order by 一起配合使用来进行记录的分页显示。
注意:limit 属于 MySQL 扩展 SQL92 后的语法,在其他数据库上并不能通用,与SQL中TOP关键字类似。
(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) |
+----------+
| 4 |
+----------+
1 row in set (0.00 sec)
在此基础上,要统计各个部门的人数:mysql> select deptno,count(1) from emp group by deptno;
+--------+----------+
| deptno | count(1) |
+--------+----------+
| 1 | 2 |
| 2 | 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 | 2 |
| 2 | 1 |
| 4 | 1 |
| NULL | 4 |
+--------+----------+
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 | 2 |
+--------+----------+
1 row in set (0.00 sec)
最后统计公司所有员工的薪水总额、最高和最低薪水:mysql> select * from emp;
+--------+------------+---------+--------+
| ename | hiredate | sal | deptno |
+--------+------------+---------+--------+
| zzx | 2000-01-01 | 100.00 | 1 |
| lisa | 2003-02-01 | 400.00 | 2 |
| bjguan | 2004-04-02 | 100.00 | 1 |
| dony | 2005-02-05 | 2000.00 | 4 |
+--------+------------+---------+--------+
4 rows in set (0.00 sec)
mysql> select sum(sal),max(sal),min(sal) from emp;
+----------+----------+----------+
| sum(sal) | max(sal) | min(sal) |
+----------+----------+----------+
| 2600.00 | 2000.00 | 100.00 |
+----------+----------+----------+
1 row in set (0.00 sec)
(5)表连接。
当需要同时显示多个表中的字段时,就可以用表连接来实现这样的功能。从大类上分,表连接分为内连接和外连接,它们之间的最主要区别是內连接仅选出两张表中互相匹配的记录,而外连接会选出其他不匹配的记录。我们最常用的是内连接。
例如,查询出所有雇员的名字和所在部门名称,因为雇员名称和部门分别存放在表 emp 和dept 中,因此,需要使用表连接来进行查询:mysql> select ename,deptname from emp,dept where emp.deptno=dept.deptno;
+--------+----------+
| ename | deptname |
+--------+----------+
| zzx | tech |
| lisa | sale |
| bjguan | tech |
| bzshen | hr |
+--------+----------+
4 rows in set (0.00 sec)
外连接有分为左连接和右连接,具体定义如下。
左连接:包含所有的左边表中的记录甚至是右边表中没有和它匹配的记录
右连接:包含所有的右边表中的记录甚至是左边表中没有和它匹配的记录
例如,查询 emp 中所有用户名和所在部门名称:
mysql> select ename,deptname from emp left join dept on emp.deptno=dept.deptno;
比较这个查询和上例中的查询,都是查询用户名和部门名,两者的区别在于本例中列出了所有的用户名,即使有的用户名(dony)并不存在合法的部门名称(部门号为 4,在 dept 中没有这个部门);而上例中仅仅列出了存在合法部门的用户名和部门名称。右连接和左连接类似,两者之间可以互相转化,例如,上面的例子可以改写为如下的右连接:
mysql> select ename,deptname from dept right join emp on dept.deptno=emp.deptno;
+--------+----------+
| ename | deptname |
+--------+----------+
| zzx | tech |
| lisa | sale |
| bjguan | tech |
| bzshen | hr |
| dony | |
+--------+----------+
5 rows in set (0.00 sec)
(6)子查询。
某些情况下,当我们查询的时候,需要的条件是另外一个 select 语句的结果,这个时候,就要用到子查询。用于子查询的关键字主要包括 in、not in、=、!=、exists、not exists 等。
例如,从 emp 表中查询出所有部门在 dept 表中的所有记录:
mysql> select * from emp where deptno in(select deptno from dept);
如果子查询记录数唯一,还可以用=代替 in:mysql> select * from emp where deptno = (select deptno from dept);
ERROR 1242 (21000): Subquery returns more than 1 row
mysql> select * from emp where deptno = (select deptno from dept limit 1);
+--------+------------+---------+--------+
| ename | hiredate | sal | deptno |
+--------+------------+---------+--------+
| zzx | 2000-01-01 | 2000.00 | 1 |
| bjguan | 2004-04-02 | 5000.00 | 1 |
+--------+------------+---------+--------+
2 rows in set (0.00 sec)
某些情况下,子查询可以转化为表连接,例如:mysql> select * from emp where deptno in(select deptno from dept);
+--------+------------+---------+--------+
| ename | hiredate | sal | deptno |
+--------+------------+---------+--------+
| zzx | 2000-01-01 | 2000.00 | 1 |
| lisa | 2003-02-01 | 4000.00 | 2 |
| bjguan | 2004-04-02 | 5000.00 | 1 |
| bzshen | 2005-04-01 | 4000.00 | 3 |
+--------+------------+---------+--------+
4 rows in set (0.00 sec)
转换为表连接后:mysql> select emp.* from emp ,dept where emp.deptno=dept.deptno;
+--------+------------+---------+--------+
| ename | hiredate | sal | deptno |
+--------+------------+---------+--------+
| zzx | 2000-01-01 | 2000.00 | 1 |
| lisa | 2003-02-01 | 4000.00 | 2 |
| bjguan | 2004-04-02 | 5000.00 | 1 |
| bzshen | 2005-04-01 | 4000.00 | 3 |
+--------+------------+---------+--------+
4 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 |
+--------+------------+---------+--------+
| zzx | 2000-01-01 | 100.00 | 1 |
| lisa | 2003-02-01 | 400.00 | 2 |
| bjguan | 2004-04-02 | 100.00 | 1 |
| dony | 2005-02-05 | 2000.00 | 4 |
+--------+------------+---------+--------+
4 rows in set (0.00 sec)
mysql> select * from dept;
+--------+----------+
| deptno | deptname |
+--------+----------+
| 1 | tech |
| 2 | sale |
| 5 | fin |
+-------+----------+
3 rows in set (0.00 sec)
mysql> select deptno from emp
-> union all
-> select deptno from dept;
+--------+
| deptno |
+--------+
| 1 |
| 2 |
| 1 |
| 4 |
| 1 |
| 2 |
| 5 |
+--------+
7 rows in set (0.00 sec)
如果希望将结果去掉重复记录后显示:
mysql> select deptno from emp
-> union
-> select deptno from dept;
+--------+
| deptno |
+--------+
| 1 |
| 2 |
| 4 |
| 5 |
+--------+
4 rows in set (0.00 sec)
2.2.4 DCL 语句
DCL 语句主要是 DBA 用来管理系统中的对象权限时所使用,一般的开发人员很少使用。下面
通过一个例子来简单说明一下。
创建一个数据库用户 z1,具有对 sakila 数据库中所有表的 SELECT/INSERT 权限:
mysql> grant select,insert on sakila.* to 'z1'@'localhost' identified by '123';
Query OK, 0 rows affected (0.00 sec)
52
mysql> exit
Bye
[mysql@db3 ~]$ mysql -uz1 -p123
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 21671 to server version: 5.1.9-beta-log
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> use sakila
Database changed
mysql> insert into emp values('bzshen','2005-04-01',3000,'3');
Query OK, 1 row affected (0.04 sec)
由于权限变更,需要将 z1 的权限变更,收回 INSERT,只能对数据进行 SELECT 操作:
[mysql@db3 ~]$ mysql -uroot
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 21757 to server version: 5.1.9-beta-log
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> revoke insert on sakila.* from 'z1'@'localhost';
Query OK, 0 rows affected (0.00 sec)
mysql> exit
Bye
用户 z1 重新登录后执行前面语句:
[mysql@db3 ~]$ mysql -uz1 -p123
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 21763 to server version: 5.1.9-beta-log
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> insert into emp values('bzshen','2005-04-01',3000,'3');
ERROR 1046 (3D000): No database selected
mysql> use sakila
Database changed
mysql> insert into emp values('bzshen','2005-04-01',3000,'3');
ERROR 1142 (42000): INSERT command denied to user 'z1'@'localhost' for table 'emp'
以上例子中的 grant 和 revoke 分别授出和收回了用户 z1 的部分权限,达到了我们的目的。
关于权限的更多内容,将会在第 4 篇中详细介绍。
53
2.3 帮助的使用
在 MySQL 使用过程中,可能经常会遇到以下问题:
某个操作语法忘记了,需要快速查找。
当前版本上,某个字段类型我们想快速知道它的取值范围?
当前版本上,都支持哪些函数?希望有例子能快速入门。
当前版本上,是否支持某个功能?
对于上面列出的各种问题,我们可能想到的办法是查找 MySQL 的文档。不错,这些问题在
MySQL 官方文档中都可以很清楚地查到,但是却要耗费大量的时间和精力。
所以对于以上问题,最好的解决办法是使用 MySQL 安装后自带的帮助文档,这样在遇到问
题时就可以方便快捷地进行查询。
2.3.1 按照层次看帮助
如果不知道帮助能够提供些什么,可以用“?contents”命令来显示所有可供查询的的分类,
如下例所示:
mysql> ? contents
You asked for help about help category: "Contents"
For more information, type 'help <item>', where <item> is one of the following
categories:
Account Management
Administration
Data Definition
Data Manipulation
Data Types
Functions
Functions and Modifiers for Use with GROUP BY
Geographic Features
Language Structure
Plugins
Storage Engines
Stored Routines
Table Maintenance
Transactions
Triggers
对于列出的分类,可以使用“? 类别名称”的方式针对用户感兴趣的内容做进一步的查看。
例如,想看看 MySQL 中都支持哪些数据类型,可以执行“? data types”命令:
mysql> ? data types
You asked for help about help category: "Data Types"
For more information, type 'help <item>', where <item> is one of the following
topics:
AUTO_INCREMENT
BIGINT
54
BINARY
BIT
BLOB
BLOB DATA TYPE
BOOLEAN
。。
。。。
。
上面列出了此版本支持的所有数据类型,如果想知道 int 类型的具体介绍,也可以利用上面
的方法,做进一步的查看:
mysql> ? int
Name: 'INT'
Description:
INT[(M)] [UNSIGNED] [ZEROFILL]
A normal-size integer. The signed range is -2147483648 to 2147483647.
The unsigned range is 0 to 4294967295.
帮助文档中显示了 int 类型的详细描述。通过这种“? 类别名称”的方式,就可以一层层
地往下查找用户所关心的主题内容。
2.3.2 快速查阅帮助
在实际应用当中,如果需要快速查阅某项语法时,可以使用关键字进行快速查询。例如,想
知道 show 命令都能看些什么东西,可以用如下命令:
mysql> ? show
Name: 'SHOW'
Description:
SHOW has many forms that provide information about databases, tables,
columns, or status information about the server. This section describes
those following:
SHOW AUTHORS
SHOW CHARACTER SET [LIKE 'pattern']
SHOW COLLATION [LIKE 'pattern']
SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [LIKE 'pattern']
SHOW CONTRIBUTORS
SHOW CREATE DATABASE db_name
SHOW CREATE EVENT event_name
SHOW CREATE FUNCTION funcname
。。。。。
。
例如,如果想参看 CREATE TABLE 的语法,可以使用以下命令:
mysql> ? create table
Name: 'CREATE TABLE'
Description:
Syntax:
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
(create_definition,...)
55
[table_option ...]
[partition_options]
Or:
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
[(create_definition,...)]
[table_option ...]
[partition_options]
select_statement
、 。
。。。。
。
2.3.3 常用的网络资源
http://dev.mysql.com/downloads/是 MySQL 的官方网站,可以下载到各个版本的 MySQL 以及
相关客户端开发工具等。
http://dev.mysql.com/doc/提供了目前最权威的 MySQL 数据库及工具的在线手册。
http://bugs.mysql.com/这里可以查看到 MySQL 已经发布的 bug 列表,或者向 MySQL 提交 bug
报告。
http://www.mysql.com/news-and-events/newsletter/通常会发布各种关于 MySQL 的最新消息。
2.4 小结
本章简单地介绍了 SQL 语句的基本分类 DML/DDL/DCL,并对每一种分类下的常用 SQL 的用
法进行了举例说明。MySQL 在标准 SQL 的基础上进行了很多扩展,本章对常用的一些语法
做了简单介绍,更详细的说明,读者可以参考 MySQL 的帮助或者官方文档。在本章的最后,
还介绍了用户应如何使用 MySQL 中的帮助文档,以便快速查找各种语法定义。