详解MySQL---DDL语句、DML语句与DCL语句

背景:近几年,开源数据库逐渐流行起来。由于具有免费使用、配置简单、稳定性好、性能优良等优点,开源数据库在中低端应用上占据了很大的市场份额,而 MySQL 正是开源数据库中的杰出代表。MySQL 数据库目前分为社区版(Community Server)和企业版(Enterprise),它们最重要的区别在于:社区版是自由下载而且完全免费的,但是官方不提供任何技术支持,适用于大多数普通用户;而企业版则是收费的,不能在线下载,相应地,它提供了更多的功能和更完备的技术支持,更适合于对数据库的功能和可靠性要求较高的企业客户。本篇博客将通过丰富的实例对 SQL 语言的基础进行详细介绍,MySQL,使得读者不但能够学习到标准 SQL【Structure Query Language(结构化查询语言)】 的使用,又能够学习到 MySQL 中一些扩展 SQL 的使用方法。

PS:本片博客的内容都是借鉴了深入浅出MySQL这本书,真是一本SQL入门好书,推荐。

SQL 分类:

SQL 语句主要可以划分为以下 3 个类别。

DDL(Data Definition Languages)语句:数据定义语言,这些语句定义了不同的数据段、数据库、表、列、索引等数据库对象的定义。常用的语句关键字主要包括 create、drop、alter等。

DML(Data Manipulation Language)语句:数据操纵语句,用于添加、删除、更新和查询数据库记录,并检查数据完整性,常用的语句关键字主要包括 insert、delete、udpate 和select 等。(增添改查)

DCL(Data Control Language)语句:数据控制语句,用于控制不同数据段直接的许可和访问级别的语句。这些语句定义了数据库、表、字段、用户的访问权限和安全级别。主要的语句关键字包括 grant、revoke 等。

DDL 语句:

DDL 是数据定义语言的缩写,简单来说,就是对数据库内部的对象进行创建、删除、修改的操作语言。它和 DML 语言的最大区别是 DML 只是对表内部数据的操作,而不涉及到表的定义、结构的修改,更不会涉及到其他对象。DDL 语句更多的被数据库管理员(DBA)所使用,一般的开发人员很少使用。

下面通过一些例子来介绍 MySQL 中常用 DDL 语句的使用方法。

1.创建数据库

启动 MySQL 服务之后,输入以下命令连接到 MySQL 服务器:

[mysql@db3 ~]$ mysql -uroot -p

Enter password:

Welcome to the MySQL monitor. Commands end with ; or \g.

Your MySQL connection id is 7344941 to server version: 5.1.9-beta-log

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql>

在以上命令行中,mysql 代表客户端命令,-u 后面跟连接的数据库用户,-p 表示需要输入密码。如果数据库设置正常,并输入正确的密码,将看到上面一段欢迎界面和一个 mysql>提示符。在欢迎界面中介绍了以下几部分内容。

命令的结束符:用;或者\g 结束。

客户端的连接 ID:这个数字记录了 MySQL 服务到目前为止的连接次数,每个新连接都会自动加 1,本例中是 7344941。

MySQL 服务器的版本:本例中是“5.1.9-beta-log”,说明是 5.1.9 的测试版,如果是标准版,则会用 Standard 代替 Beta。

通过“help;”或者“\h”命令来显示帮助内容:通过“\c”命令来清除命令行 buffer。

在 mysql>提示符后面输入所要执行的的 SQL 语句,每个 SQL 语句以分号或者\g 结束,按回车键执行。

因为所有的数据都存储在数据库中,因此需要学习的第一个命令是创建数据库,语法如下所示:

CREATE DATABASE dbname

例如,创建数据库 test1,命令执行如下:

mysql> create database test1;

Query OK, 1 row affected (0.00 sec)

可以发现,执行完创建命令后,下面有一行提示“Query OK, 1 row affected (0.00 sec)”,这段提示可以分为 3 部分,“Query OK”表示上面的命令执行成功,读者可能奇怪,又不是执行查询操作,为什么显示查询成功?其实这是 MySQL 的一个特点,所有的 DDL 和 DML(不包括 SELECT)操作执行成功后都显示“Query OK”,这里理解为执行成功就可以了;“1 row

affected”表示操作只影响了数据库中一行的记录,“0.00 sec”则记录了操作执行的时间。这个时候,如果需要知道系统中都存在哪些数据库,可以用以下命令来查看:

mysql> show databases;

+--------------------+

| Database |

+--------------------+

| information_schema |

| cluster |

| mysql |

| test |

| test1 |

+--------------------+

5 rows in set (0.00 sec)

可以发现,在上面的列表中除了刚刚创建的 test1 外,还有另外 4 个数据库,它们都是安装MySQL 时系统自动创建的,其各自功能如下。

information_schema:主要存储了系统中的一些数据库对象信息。比如用户表信息、列信息、权限信息、字符集信息、分区信息等。

cluster:存储了系统的集群信息。

mysql:存储了系统的用户权限信息。

test:系统自动创建的测试数据库,任何用户都可以使用。

在查看了系统中已有的数据库后,可以用如下命令选择要操作的数据库:USE dbname

然后再用以下命令来查看 test1 数据库中创建的所有数据表:mysql> show tables;

2.删除数据库

删除数据库的语法很简单,如下所示:drop database dbname;

例如,要删除 test1 数据库可以使用以下语句:mysql> drop database test1;

注意:数据库删除后,下面的所有表数据都会全部删除,所以删除前一定要仔细检查并做好相应备份。

3.创建表

在数据库中创建一张表的基本语法如下:

CREATE TABLE tablename (

column_name_1 column_type_1 constraints,

column_name_2 column_type_2 constraints ,

……

column_name_n column_type_n constraints)

因为 MySQL 的表名是以目录的形式存在于磁盘上,所以表名的字符可以用任何目录名允许的字符。column_name 是列的名字,column_type 是列的数据类型,contraints 是这个列的约束条件

例如,创建一个名称为 emp 的表。表中包括 3 个字段,ename(姓名),hiredate(雇用日期)、sal(薪水),字段类型分别为 varchar(10)、date、int(2):

mysql> create table emp(

ename varchar(10),

hiredate date,

sal decimal(10,2),deptno int(2));

Query OK, 0 rows affected (0.02 sec)

表创建完毕后,如果需要查看一下表的定义,可以使用如下命令:DESC tablename

虽然 desc 命令可以查看表定义,但是其输出的信息还是不够全面,为了查看更全面的表定义信息,有时就需要通过查看创建表的 SQL 语句来得到,可以使用如下命令实现:mysql> show create table emp \G;

*************************** 1. row ***************************

Table: emp

Create Table: CREATE TABLE 'emp' (

'ename' varchar(20) DEFAULT NULL,

'hiredate' date DEFAULT NULL,

'sal' decimal(10,2) DEFAULT NULL,

'deptno' int(2) DEFAULT NULL,

KEY idx_emp_ename' ('ename')

) ENGINE=InnoDB DEFAULT CHARSET=gbk

1 row in set (0.02 sec)

ERROR:

No query specified

mysql>

从上面表的创建 SQL 语句中,除了可以看到表定义以外,还可以看到表的 engine(存储引擎)charset(字符集)等信息。“\G”选项的含义是使得记录能够按照字段竖着排列,对于内容比较长的记录更易于显示。

4.删除表

表的删除命令如下:DROP TABLE tablename

例如,要删除数据库 emp 可以使用以下命令:mysql> drop table emp;

5.修改表(重要)

对于已经创建好的表,尤其是已经有大量数据的表,如果需要对表做一些结构上的改变,我们可以先将表删除(drop),然后再按照新的表定义重建表。这样做没有问题,但是必然要做一些额外的工作,比如数据的重新加载。而且,如果有服务在访问表,也会对服务产生影响。因此,在大多数情况下,表结构的更改一般都使用 alter table 语句,以下是一些常用的命令。

(1) 修改表类型,语法如下:

ALTER TABLE tablename MODIFY [COLUMN] column_definition [FIRST | AFTER col_name]

例如,修改表 emp 的 ename 字段定义,将 varchar(10)改为 varchar(20):mysql> alter table emp modify ename varchar(20);

(2) 增加表字段,语法如下:

ALTER TABLE tablename ADD [COLUMN] column_definition [FIRST | AFTER col_name]

例如,表 emp 上新增加字段 age,类型为 int(3):mysql> alter table emp add column age int(3);

(3)删除表字段,语法如下:

ALTER TABLE tablename DROP [COLUMN] col_name

例如,将字段 age 删除掉:mysql> alter table emp drop column age;

(4)字段改名,语法如下:

ALTER TABLE tablename CHANGE [COLUMN] old_col_name column_definition [FIRST|AFTER col_name]

例如,将 age 改名为 age1,同时修改字段类型为 int(4):mysql> alter table emp change age age1 int(4) ;

注意:change 和 modify 都可以修改表的定义,不同的是 change 后面需要写两次列名,不方便。但是 change 的优点是可以修改列名称,modify 则不能。

(5)修改字段排列顺序。

前面介绍的的字段增加和修改语法(ADD/CNAHGE/MODIFY)中,都有一个可选项 first|after column_name,这个选项可以用来修改字段在表中的位置,默认 ADD 增加的新字段是加在表的最后位置,而 CHANGE/MODIFY 默认都不会改变字段的位置。

例如,将新增的字段 birth date 加在 ename 之后:mysql> alter table emp add birth date after ename;

修改字段 age,将它放在最前面:mysql> alter table emp modify age int(3) first;

注意:CHANGE/FIRST|AFTER COLUMN 这些关键字都属于 MySQL 在标准 SQL 上的扩展,在其他数据库上不一定适用。

(6)表改名,语法如下:ALTER TABLE tablename RENAME [TO] new_tablename

例如,将表 emp 改名为 emp1,命令如下:mysql> alter table emp rename emp1;

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);

Query OK, 1 row affected (0.00 sec)

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

mysql> insert into emp values('lisa','2003-02-01','3000',2);

Query OK, 1 row affected (0.00 sec)

对于含可空字段、非空但是含有默认值的字段、自增字段,可以不用在 insert 后的字段列表

里面出现,values 后面只写对应字段名称的 value,这些没写的字段可以自动设置为 NULL、

默认值、自增的下一个数字,这样在某些情况下可以大大缩短 SQL 语句的复杂性。

例如,只对表中的 ename 和 sal 字段显式插入值:

mysql> insert into emp (ename,sal) values('dony',1000);

Query OK, 1 row affected (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 | NULL | 1000.00 | NULL |

+--------+------------+---------+--------+

果然,设置为可空的两个字段都显示为 NULL。

在 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)

;

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 中的帮助文档,以便快速查找各种语法定义。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值