SQL(Structure Query Language)结构化查询语言,是使用关系模型的数据库应用语言,由IBM在20世纪70年代开发,其作为IBM关系数据库原型System R的原型关系语言,实现了关系数据库的信息检索。后由ANSI(美国国家标准局)制定SQL标准并日趋完善。
DDL(Data Definition Languages)语句:数据定义语言,这些语句定义了不同的数据段、数据库、表、列、索引等数据库对象。常用的语句关键字包括create、drop、alter等。
DML(Data Manipulation Language)语句:数据操纵语句,用于添加、删除、更新和查询数据库记录,并检查数据完整性。常用的语句关键字主要包括insert、delete、update、select等。
DCL(Data Control Language)语句:数据控制语句,用于控制不同数据段直接的许可和访问级别的语句,这些语句定义了数据库、表、字段、用户的访问权限和安全级别,主要的语句关键字包括grant、revoke等。
DDL是对数据库内部的对象进行创建、删除、修改等操作的语言。其与DML最大的区别是,DML只针对表内部数据操作,而不涉及表的定义、结构的修改,更不会涉及其他对象。DDL语句更多地由数据库管理员(DBA)使用,开发人员较少使用。
1. 创建数据库
语法:CREATE DATABASE dbname
用例:创建数据库test1
命令:CREATE DATABASE test1;
结果反馈:Query OK,1 row affected(0.00 sec)
成功执行完创建命令后,一般会有一行提示"Query OK,1 row affected(0.00 sec)",这段提示分如下三部分。
Query OK:命令执行成功,这是MySQL一特点,所有地DDL和DML(不包括SELECT)操作执行成功后都显示Query OK。
1 row affected:表示操作只影响了数据库中一行地记录。
0.00 sec:记录了操作执行的时间。
2. 查看系统中存在哪些数据库
语法:SHOW DATABASE;
命令:SHOW DATABASE;
3. 选择要操作的数据库
语法:USE dbname
用例:使用test1数据库
命令:USE test1;
4. 删除数据库
语法:DROP DATABASE dbname;
用例:删除test1数据库
命令:DROP DATABASE test1;
结果反馈:Query OK,0 rows affected(0.00 sec)
注:数据库删除后,下面的所有表数据都会全部删除,所以删除前一定要仔细检查并做好相应备份。
5. 创建表
语法:
CREATE TABLE tablename (
column_name_1 column_type_1 constraints,
column_name_2 column_type_2 constraints,
……
column_name_n column_type_n constraints);
column_name:列名
column_type:列的数据类型
constraints:列的约束条件
用例:创建表emp,包含员工名字、雇佣日期、薪资、部门编号
命令:
CREATE TABLE emp (
ename varchar(10),
hiredate date,
sal decimal(10,2),
deptno int(2));
结果反馈:Query OK, 0 rows affected (0.02 sec)
注:因为MySQL的表名是以目录的形式存在于磁盘上,所以表名的字符可以用任何目录名允许的字符。
6. 查看表定义
7. 查看创建表的SQL语句
语法:SHOW CREATE TABLE tablename \G;
用例:查看emp表的创建语句
命令:SHOW CREATE TABLE emp \G;
结果反馈:
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=jbk
1 row in set (0.02 sec)
注:以上可以看出,除了可以看到表定义以外,还可以看到表的engine(存储引擎)和charset(字符集)等信息。"\G"选项的含义是使得记录能够按照字段竖向排列,以便更好地显示内容较长地记录。
4. 删除表
语法:DROP TABLE tablename
用例:删除表emp
命令:DROP TABLE emp
结果反馈:Query OK, 0 rows affected (0.00 sec)
5. 修改表
语法:ALTER TABLE tablename MODIFY [COLUMN] column_definition [FIRST|AFTER col_name]
用例:修改表emp的ename字段定义,将varchar(10)改为varchar(20)
命令:ALTER TABLE emp MODIFY ename varchar(20);
结果反馈:Query OK, 0 rows affected (0.03 sec)
Records:0 Duplicates:0 Warnings:0
语法:ALTER TABLE tablename ADD [COLUMN] column_definition [FIRST|AFTER col_name]
用例:在表emp中新增加字段age,类型为int(3)
命令:ALTER TABLE emp ADD column age int(3);
结果反馈:Query OK, 0 rows affected (0.03 sec)
Records:0 Duplicates:0 Warnings:0
语法:ALTER TABLE tablename DROP [COLUMN] col_name
用例:将字段age删除掉
命令:ALTER TABLE emp DROP column age;
结果反馈:Query OK, 0 rows affected (0.04 sec)
Records:0 Duplicates:0 Warnings:0
语法:ALTER TABLE tablename CHANGE [COLUMN] old_col_name column_definition [FIRST|AFTER col_name]
用例:将age改名为age1,同时修改字段类型为int(4)
命令:ALTER TABLE emp CHANGE age age1 int(4);
结果反馈:Query OK, 0 rows affected (0.02 sec)
Records:0 Duplicates:0 Warnings:0
注意:change和modify都可以修改表的定义,不同的是change后面需要写两次列名,不方便,但是change的优点是可以修改列名称,modify则不能。
前面介绍的字段增加和修改语法中,都有一个可选项FIRST|AFTER COLUMN_NAME,这个选项可以用来修改字段在表中的位置,ADD增加的新字段默认是加载表的最后位置,而CHANGE/MODIFY默认都不会改变字段的位置。
用例1:将新增的字段birth date加在ename之后
命令:ALTER TABLE emp ADD birth date after ename;
结果反馈:Query OK, 0 rows affected (0.03 sec)
Records:0 Duplicates:0 Warnings:0
用例2:修改字段age,将它放在最前面
命令:ALTER TABLE emp MODIFY age int(3) first;
结果反馈:Query OK, 0 rows affected (0.03 sec)
Records:0 Duplicates:0 Warnings:0
注意:CHANGE/FIRST|AFTER COLUMN这些关键字都属于MySQL在标准SQL上的扩展,在其他数据库上不一定使用。
语法:ALTER TABLE tablename RENAME [TO] new_tablename
用例:将表emp改名为emp1
命令:ALTER TABLE emp RENAME emp1;
结果反馈:Query OK,0 rows affected (0.00 sec)
1. 插入记录
语法:INSERT INTO tablename(field1,field2,……fieldn) VALUES(value1,value2,……valuen);
用例:向表emp中插入以下记录:enmae为zzx1,hiredate为2000-01-01,sal为2000,deptno为1
命令:INSERT INTO emp(ename,hiredate,sal,deptno) VALUES('zzx1','2000-01-01','2000',1);
结果反馈:Query OK,1 row affected (0.00 sec)
也可以不用指定字段名称,但是VALUES后面的顺序应该和字段的排列顺序一致:
命令: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字段显示插入值
命令:INSERT INTO emp (ename,sal) VALUES('dony',1000);
结果反馈:Query OK, 1 row affected (0.00 sec)
一次性插入多条记录:
语法:
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);
用例:对表dept一次性插入两条记录
命令:
INSERT INTO dept VALUES(5,'dept5'),(6,'dept6');
结果反馈:Query OK, 2 rows affected (0.04 sec)
Records:2 Duplicates:0 warnings:0
2. 更新记录
语法:UPDATE tablename SET field1=value1,field2=value2,……fieldn=valuen [WHERE CONDITION]
用例:将表emp中ename为'lisa'的薪水(sal)从3000更改为4000
命令:UPDATE emp SET sal=4000 WHERE ename='lisa';
结果反馈:Query OK,1 row affected (0.00 sec)
Rows matched:1 Changed:1 Warnings:0
语法:UPDATE t1,t2,……tn set t1.field1=expr1,tn.fieldn=exprn [WHERE CONDITION]
用例:同时更新多个表中数据,更新表emp中的字段sal和表dept中的字段deptname
命令: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.04 sec)
Rows matched:5 Changed:3 Warnings:0
注意:多表更新的语法更多地用在了根据一个表地字段来动态地更新另外一个表地字段。
3. 删除记录
语法:DELETE FROM tablename [WHERE CONDITION]
用例:在emp中将ename为'dony'的记录全部删除
命令:DELETE FROM emp WHERE ename='dony';
结果反馈:Query OK, 1 row affected (0.00 sec)
一次性删除多个表中的记录:
语法:DELETE t1,t2,……tn FROM t1,t2,……tn [WHERE CONDITION]
用例:同时删除表emp和dept中deptno为3的记录
命令:DELETE a,b FROM emp a, dept b WHERE a.deptno=b.deptno and a.deptno=3;
结果反馈:Query OK, 2 rows affected (0.04 sec)
4. 查询记录
语法:SELECT*FROM tablename [WHERE CONDITION]
用例:将表emp中的记录全部查询出来
命令:SELECT*FROM emp;
查询不重复的记录
语法:可以用distinct关键字来实现
用例:查询出各个deptno,不重复
命令:SELECT distinct deptno FROM emp;
语法:用WHERE关键字实现这样的操作
用例:查询所有deptno为1的记录
命令:SELECT * FROM emp WHERE deptno=1;
语法:SELECT * FROM tablename [WHERE CONDITION] [ORDER BY field1 [DESC|ASC], field2 [DESC|ASC],……fieldn [DESC|ASC]
用例:把emp表中的记录按照工资高低进行显示(升序)
命令:SELECT * FROM emp ORDER BY sal
注:DESC表示降序排列,ASC表示升序排列,如果不写关键字默认是升序排列。如果排序字段的值一样,则值相同的字段按照第二个排序字段进行排序,依此类推。如果只有一个排序字段,则这些字段相同的记录将会无序排列。
用例:把emp表中的记录按照部门编号deptno升序排序,如果deptno相同,则按照工资降序排序
命令:SELECT * FROM emp ORDER BY deptno, sal DESC;
语法:SELECT……[LIMIT offset_start,row_count]
offset_start:表示记录的起始偏移量,默认情况下为0
row_count:表示显示的行数
用例1:显示emp表中按照sal排序后的前3条记录
命令:SELECT * FROM emp ORDER BY sal LIMIT 3;
用例2:显示emp表中按照sal排序后从第二条记录开始的3条记录
命令:SELECT * FROM emp ORDER BY sal LIMIT 1,3;
注:LIMIT经常和ORDER BY一起配合使用来进行记录的分页显示。
语法:SELECT [field1,field2,……fieldn] fun_name FROM tablename [WHERE where_condition] [GROUP BY field1,field2,……fieldn [WITH ROLLUP]] [HAVING where_condition]
fun_name:表示要做的聚合操作,即聚合函数,常用的有sum(求和)、count(*)记录数、max(最大值)、min(最小值)。
GROUP BY:表示要进行分类聚合的字段,比如要按照部门分类统计员工数量,部门就应该写在GROUP BY后面。
WITH ROLLUP:是可选语法,表明是否对分类聚合后的结果进行再汇总。
HAVING:表示对分类后的结果再进行条件的过滤。
注:HAVING和WHERE的区别在于,HAVING是对聚合后的结果进行条件的过滤,而WHERE是在聚合前就对记录进行过滤。如果逻辑允许,我们尽可能用WHERE先过滤记录,这样因为结果集减小,将对聚合的效率大大提高,最后再根据逻辑看是否用HAVING进行再过滤。
用例1:在emp统计公司的总人数
命令:SELECT COUNT(1) FROM emp;
用例2:统计各部门的人数
命令:SELECT deptno, count(1) FROM emp GROUP BY deptno;
用例3:既要统计各部门人数,又要统计总人数
命令:SELECT deptno, count(1) FROM emp GROUP BY deptno WITH ROLLUP;
用例4:统计人数大于1人的部门
命令:SELECT deptno, count(1) FROM emp GROUP BY deptno HAVING count(1)>1;
用例5:统计公司所有员工的薪水总额、最高和最低薪水
命令:SELECT SUM(sal), MAX(sal), MIN(sal) FROM emp;
当需要同时显示多个表中的字段时,就可以用表连接来实现这样的功能。从大类上分,表连接分为内连接和外连接,它们最主要的区别是,内连接仅选出两张表中相互匹配的记录,而外连接会选出其他不匹配的记录,其中内连接较为常用。
用例:查询出所有雇员的名字和所在部门名称,其中雇员名称和部门名称分别存放在表emp和dept中,因此需要使用表连接进行查询。
命令:SELECT ename, deptname FROM emp, dept WHERE emp.deptno=dept.deptno;
外连接又分为左连接和右连接,具体定义如下:
左连接:包含所有的左边表中的记录甚至是右表中没有和它匹配的记录。
右连接:包含所有的右表中的记录甚至是左表中没有和它匹配的记录。
用例:查询emp中所有用户名和所在部门名称
命令:SELECT ename, deptname FROM emp LEFT JOIN dept ON emp.deptno=dept.deptno;
比较这个查询和上例中的查询,都是查询用户名和部门名,两者的区别在于本例中列出了所有的用户名,即使有的用户名(dony)并不存在合法的部门名称(部门号为4,在dept中没有这个部门);而上例中仅仅列出了存在合法部门的用户名和部门名称。右连接和左连接类似,两者之间可以相互转化。
当进行查询时,需要的条件时另外一个SELECT语句的结果,这便用到了子查询。用于子查询的关键字主要包括in、not in、=、!=、exists、not exists等。
用例1:从emp表中查询出所有部门在dept表中的所有记录
命令:SELECT * FROM emp WHERE deptno IN(SELECT deptno FROM dept);
注:如果子查询记录数唯一,还可以用=代替in。
用例2:从emp表中查询出部门编号为指定值的记录
命令:SELECT * FROM emp WHERE deptno = (SELECT deptno FROM dept LIMIT 1);
注:某些情况下,子查询可以转化为表连接,用例2便可以作为转换。
命令:SELECT emp.* FROM emp, dept WHERE emp.deptno = dept.deptno;
注:子查询和表连接之间的转换主要应用在两个方面。
a. MySQL4.1以前的版本不支持子查询,需要用表连接来实现子查询的功能。
b. 表连接在很多情况下用于优化子查询。
将两个表的数据按照一定的查询条件查询出来后,将结果合并到一起显示出来,这时候便用到UNION和UNION ALL关键字来实现这样的功能。
语法:SELECT * FROM t1 UNION|UNION ALL SELECT * FROM t2……UNION|UNION ALL SELECT * FROM tn;
用例1:将emp和dept表中的部门编号的集合显示出来
命令:SELECT deptno FROM emp UNION ALL SELECT deptno FROM dept;
用例2:将用例1的结果去重后显示出来
命令:SELECT deptno FROM emp UNION SELECT deptno FROM dept;
DCL语句主要是DBA用来管理系统中的对象权限时使用。
用例1:创建一个数据库用户z1,具有对sakila数据库中所有表的SELECT/INSERT权限。
命令:GRANT SELECT, INSERT ON sakila.* TO 'z1'@'localhost' identified by '123';
用例2:由于权限变更,需要将z1的权限变更,收回INSERT,只能对数据进行SELECT操作。
命令:REVOKE INSERT ON sakila.* FROM 'z1'@'localhost';
GRANT和REVOKE分别授出和收回用户z1的部分权限。