文章目录
- 第二章、数据库表的相关操作
- 一、SQL语言
- 二、数据库表语句(DDL语句)
- 1、创建逻辑库
- 2、创建数据表
- 三、数据类型
- 1、数字类型
- 2、字符串类型
- 3、日期类型
- 四、修改表结构
- 1、添加字段
- 2、修改字段类型和约束
- 3、修改字段名称
- 4、删除字段
- 五、字段约束
- 1、数据库的范式
- 2、字段约束
- 六、索引
- 1、索引的使用原则
- 第三章、数据的相关操作
- 一、普通查询
- 1、记录查询
- 2、数据分页
- 3、排序
- 4、去除重复记录
- 5、条件查询
- 1)四类运算符
- 2)WHERE子句的注意事项
- 二、聚合函数
- 1、SUM函数
- 2、MAX函数
- 3、MIN函数
- 4、AVG函数
- 5、COUNT函数
- 三、分组查询
- 1、为什么要分组
- 2、逐级分组
- 3、对SELECT子句的要求
- 4、对分组结果集再次做汇总计算
- 5、GROUP_CONCAT函数
- 6、各种子句的执行顺序
- 四、HAVING子句
- 1、HAVING子句的特殊用法
- 五、表连接查询
- 1、从多张表中提取数据
- 2、表连接的分类
- 1)内连接
- 2)外连接
- 3)UNION
- 4)外连接案例
- 六、子查询
- 1、WHERE子查询
- 2、FROM子查询
- 3、SELECT子查询
- 4、单行子查询和多行子查询
- 5、子查询案例
- 七、INSERT语句
- 1、INSERT语句案例
- 2、INSERT语句方言
- 3、IGNORE关键字
- 八、UPDATE语句
- 1、UPDATE语句的表连接
- 2、UPDATE语句案例
- 九、DELETE语句
- 1、DELETE语句的表连接
- 2、快速删除数据表全部记录
- 3、DELETE语句案例
- 十、MySQL函数
- 1、数字函数
- 2、日期函数
- 3、字符函数
- 4、条件函数
- 第四章、数据导入与导出
- 一、数据导出
- 1、数据导出的分类
- 2、导出SQL文件
- 3、导入SQL文件
- 4、导出文本文档
- 二、数据导入
- 1、导入文本文档
第二章、数据库表的相关操作
一、SQL语言
SQL是用于访问和处理数据的标准的计算机语言。
SQL语言分类:
DML:添加、修改、删除、查询
DCL:用户、权限、事务
DDL:逻辑库、数据表、视图、索引
注:
SQL语句不区分大小写,但是字符串区分大小写。
SQL语句必须以分号结尾。
SQL语句中的空白和换行没有限制,但是不能破坏语法。
SQL语句的注释:
#这是一行注释文字
/*这是一段注释*/
二、数据库表语句(DDL语句)
1、创建逻辑库
CREATE DATABASE 逻辑库名称; # 创建逻辑库
SHOW DATABASES; #展示所有逻辑库
DROP DATABASE 逻辑库名称; #删除逻辑库
2、创建数据表
//创建数据表
CREATE TABLE 数据表(
列名1 数据类型 [约束] [COMMENT 注释],
列名2 数据类型 [约束] [COMMENT 注释],
......
)[COMMENT = 注释];
//展示当前逻辑库有哪些数据表
SHOW tables;
//查看student表的具体情况
DESC student;
//查询建表语句
SHOW CREATE TABLE student;
//删除数据表
DROP TABLE student;
三、数据类型
1、数字类型
注:十进制的浮点数无法在计算机中用二进制精确表达,所以浮点数会丢失精度。
如何用二进制小数表示十进制的0.2
1/8 + 1/16 + 1/128 + …
DECIMAL是按字符串的方式保存,所以不会丢失精度。
2、字符串类型
3、日期类型
四、修改表结构
1、添加字段
ALTER TABLE 表名称
ADD 列1 数据类型 [约束] [COMMENT 注释],
ADD 列2 数据类型 [约束] [COMMENT 注释],
......;
2、修改字段类型和约束
ALTER TABLE 表名称
MODIFY 列1 数据类型 [约束] [COMMENT 注释],
MODIFY 列2 数据类型 [约束] [COMMENT 注释],
......;
3、修改字段名称
ALTER TABLE 表名称
CHANGE 列1 新名称1 数据类型 [约束] [COMMENT 注释],
CHANGE 列2 新名称2 数据类型 [约束] [COMMENT 注释],
......;
4、删除字段
ALTER TABLE 表名称
DROP 列1,
DROP 列2,
......;
五、字段约束
1、数据库的范式
构造数据库必须遵循一定的规则,这种规则就是范式。
目前关系数据库有6种范式,一般情况下,只满足第三范式即可。
第一范式:原子性
第一范式是数据库的基本要求,不满足这一点就不是关系数据库。
数据表的每一列都是不可分割的基本数据项,同一列中不能有多个值,也不能存在重复的属性。
第二范式:唯一性
数据表中的每条记录必须是唯一的。为了实现区分,通常要为表加上一个列用来存储唯一标识,这个唯一属性列被称作主键列。
第三范式:关联性
每列都与主键有直接关系,不存在传递依赖。满足第三范式就意味着同时满足了第一范式和第二范式。
依照第三范式,数据可以拆分保存到不同的数据表,彼此保持关联。
2、字段约束
注:
建议主键一定要使用数字类型,因为数字的检索速度会非常快。
如果主键是数字类型,还可以设置自动增长。
NULL值以为没有值,而不是""空字符串。
CREATE TABLE t_user(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
tel CHAR(11) NOT NULL UNIQUE,
dept_id INT,
FOREING KEY (dept_id) REFERENCES t_dept(id)
);
注:运用外键约束容易形成外键闭环,我们将无法删除任何一张表的记录,所以不推荐使用外键约束。
六、索引
一旦数据排序之后,查找的速度就会翻倍,现实世界跟程序世界都是如此。
对某个字段添加索引后,数据库对此字段进行排序生成二叉树,将大大提高这个字段的查找速度。
//创建表时添加索引
CREATE TABLE 表名称(
......,
INDEX [索引名称](字段),
......
);
//对已存在的数据表添加索引
CREATE INDEX 索引名称 ON 表名(字段);
ALTER TABLE 表名称 ADD INDEX [索引名](字段);
//查询数据表的所有索引
SHOW INDEX FROM 表名;
//删除索引
DORP INDEX 索引名称 ON 表名;
1、索引的使用原则
数据量很大,而且经常被查询的数据表可以设置索引。
索引只添加在经常被用作检索条件的字段上面。
不要在大字段上创建索引。
第三章、数据的相关操作
一、普通查询
1、记录查询
SELECT * FROM 表名;
SELECT 列1,列2,列3 FROM 表名;
SELECT语句屏蔽了物理层的操作,用户不必关心数据的真实存储,交由数据库高效的查找数据。
使用列别名
SELECT id, sal*12 AS “income” FROM t_emp;
查询语句的子句执行顺序
2、数据分页
SELECT … FROM … LIMIT 起始位置,偏移量;
如果LIMIT子句只有一个参数,它表示的是偏移量,起始值默认为0。
执行顺序
FROM -> SELECT -> LIMIT
3、排序
SELECT … FROM … ORDER BY 列名 [ACS|DESC];
ASC代表升序(默认), DESC代表降序
如果排序列是数字类型,数据库就按照数字大小排序,如果是日期类型就按照日期大小排序,如果是字符串就按照字符集序号排序。
多个排序字段
我们可以使用ORDER BY规定首要排序条件和次要排序条件。数据库会先按照首要排序条件排序,如果遇到首要排序内容相同的记录,那么就会启动次要排序条件接着排序。
SELECT … FROM … ORDER BY 列名1 ACS,列2 DESC;
执行顺序
FROM -> SELECT -> ORDER BY -> LIMIT
4、去除重复记录
SELECT DISTINCT job FROM t_emp;
使用DISTINCT的SELECT子句中只能查询一列数据,如果查询多列,去除重复记录就会失效。
DISTINCT关键字只能在SELECT子句中使用一次。
5、条件查询
1)四类运算符
算术运算符:
注:
数字和null加减乘除运算结果还是null。
IFNULL(字段, 0) – mysql函数,字段为空时用0来代替。
DATEDIFF(time1, time2) – 计算两个日期相差的天数
NOW() – 获取当前日期比较运算符:
注:
在LIKE表达式里%表示多个字符,_表示单个字符。逻辑运算符:
按位运算符:
2)WHERE子句的注意事项
WHERE子句中,条件执行的顺序是从左到右的。所以我们应该把索引条件,或者筛选掉记录最多的条件写在最左侧。
执行顺序
FROM -> WHERE -> SELECT -> ORDER BY -> LIMIT
二、聚合函数
1、SUM函数
SUM函数用于求和,只能用于数字类型,字符类型的统计结果为0,日期类型统计结果是毫秒数相加。
SELECT SUM(sal) FROM t_emp;
2、MAX函数
MAX函数用于获得非空值的最大值。
SELECT MAX(comm) FROM t_emp;
3、MIN函数
MIN函数用于获得非空值的最小值。
SELECT MIN(comm) FROM t_emp;
4、AVG函数
AVG函数用于获得非空值的平均值,非数字数据统计结果为0。
SELECT AVG(comm) FROM t_emp;
5、COUNT函数
COUNT(*)用于获得包含空值的记录数,COUNT(列名)用于获得包含非空值的记录数。
SELECT COUNT(*) FROM t_emp;
注:
聚合函数不能出现在WHERE子句中。
三、分组查询
1、为什么要分组
默认情况下汇总函数是对全表范围内的数据做统计。
GROUP BY子句的作用是通过一定的规则将一个数据集划分成若干个小的区域,然后针对每个小区域分别进行数据汇总处理。
SELECT deptno, AVG(sal) FROM t_emp GROUP BY deptno;
2、逐级分组
数据库支持多列分组条件,执行的时候逐级分组。
//查询每个部门里,每种职位的人员数量和平均底薪
SELECT deptno, job, COUNT(*), AVG(sal) FROM t_emp GROUP BY deptno, job ORDER BY deptno;
3、对SELECT子句的要求
查询语句中如果含有GROUP BY子句,那么SELECT子句中的内容就必须要遵守规定:SELECT子句中可以包含聚合函数,或者GROUP BY子句的分组列,其余内容均不可以出现在SELECT子句中。
4、对分组结果集再次做汇总计算
SELECT deptno, COUNT(*), AVG(sal), MAX(sal), MIN(sal) FROM t_emp GROUP BY deptno WITH ROLLUP;
5、GROUP_CONCAT函数
GROUP_CONCAT函数可以把分组查询中的某个字段拼接成一个字符串。
//查询每个部门内底薪超过2000元的人数和员工姓名
SELECT deptno, GROUP_CONCAT(ename), COUNT(*) FROM t_emp WHERE sal>=2000 GROUP BY deptno;
6、各种子句的执行顺序
FROM -> WHERE -> GROUP BY -> SELECT -> ORDER BY -> LIMIT
四、HAVING子句
//查询部门平均底薪超过2000元的部门编号
SELECT deptno FROM t_emp GROUP BY deptno HAVING AVG(sal)>=2000;
注:having子句中聚合函数和普通数据可以比较,但是不能跟具体字段做判断。
1、HAVING子句的特殊用法
按照数字1分组,MySQL会依据SELECT子句中的列进行分组,HAVING子句也可以正常使用。
SELECT deptno, COUNT(*) FROM t_emp GROUP BY 1 HAVING deptno IN (10,20);
注:having子句中可以编写where子句中的条件,但是不建议这么写,因为where子句在分组之前执行筛选大量数据,会降低分组的速度。
五、表连接查询
1、从多张表中提取数据
从多张表中提取数据,必须指定关联的条件。如果不定义关联条件就会出现无条件连接,两张表的数据会交叉连接,产生笛卡尔积。
2、表连接的分类
表连接分为两种:内连接和外连接
内连接是结果集中只保留符合连接条件的记录。
外连接是不管符不符合连接条件,记录都要保留在结果集中。
1)内连接
SELECT ...... FROM 表1
[INNER] JOIN 表2 ON 条件
[INNER] JOIN 表3 ON 条件
......
内连接的多种语法形式
SELECT ...... FROM 表1 JOIN 表2 ON 连接条件;
SELECT ...... FROM 表1 JOIN 表2 WHERE 连接条件;
SELECT ...... FROM 表1, 表2 WHERE 连接条件;
内连接的数据表不一定必须有同名字段,只要字段之间符合逻辑关系就可以。
相同的数据表也可以做表连接。
子查询速度非常慢,因为子查询的SQL执行次数是由外层查询的表记录数决定的。所以换成连接查询速度会大大提高。
内连接案例
查询底薪超过公司平均底薪的员工信息
SELECT e.name, e.sal FROM t_emp e JOIN (
SELECT AVG(sal) avg FROM t_emp
) t ON e.sal>=t.avg;
查询每个底薪超过部门平均底薪的员工信息
SELECT e.name, e.sal FROM t_emp e JOIN (
SELECT deptno, AVG(sal) avg FROM t_emp GROUP BY deptno
) t ON e.deptno=t.deptno AND e.sal>=t.avg;
查询每种职业的最高工资、最低工资、平均工资、最高工资等级和最低工资等级
SELECT
e.job,
MAX(e.sal+IFNULL(e.comm, 0)),
MIN(e.sal+IFNULL(e.comm, 0)),
AVG(e.sal+IFNULL(e.comm, 0)),
MAX(s.grade),
MIN(s.grade)
FROM t_emp e
JOIN t salgrade s
ON (e.sal+IFNULL(e.comm, 0)) BETWEEN s.losal AND s.hisal
GROUP BY e.job;
2)外连接
外连接与内连接的区别在于,除了符合条件的记录之外,结果集中还会保留不符合条件的记录。
SELECT ...... FROM 表1
LEFT|RIGHT JOIN 表2 ON 条件
LEFT|RIGHT JOIN 表3 ON 条件
......
左连接和右连接
左外连接就是保留左表所有记录,与右表做连接。如果右表有符合条件的记录就与左表连接。如果右表没有符合条件的记录,就用NULL与左表连接。右外连接也是如此。
3)UNION
UNION关键字可以将多个查询语句的结果集进行合并
(查询语句) UNION (查询语句) UNION (查询语句) ......
4)外连接案例
查询每个部门的名称和部门的人数
SELECT d.dname, COUNT(e.deptno)
FROM t_dept d LEFT JOIN t_emp e
ON d.deptno = e.deptno
GROUP BY d.deptno;
查询每个部门的名称和部门的人数?如果没有部门的员工,部门名称用NULL代替。
(
SELECT d.dname, COUNT(e.deptno)
FROM t_dept d LEFT JOIN t_emp e
ON d.deptno = e.deptno
GROUP BY d.deptno
) UNION
(
SELECT d.dname, COUNT(*)
FROM t_dept d RIGHT JOIN t_emp e
ON d.deptno = e.deptno
GROUP BY d.deptno
)
六、子查询
子查询是一种查询中嵌套查询的语句。
子查询可以写在三个地方:WHERE子句、FROM子句、SELECT子句,但是只有FROM子句子查询是最可取的。
1、WHERE子查询
这种子查询最简单,最容易理解,但是却是效率很低的子查询。
2、FROM子查询
这种子查询只会执行一次,所以查询效率很高。
3、SELECT子查询
这种子查询每输出一条记录的时候都要执行一次,查询效率很低。
4、单行子查询和多行子查询
单行子查询的结果集只有一条记录,多行子查询结果集有多行记录。
多行子查询只能出现在WHERE子句和FROM子句中。
WHERE子句中,可以用IN、ALL、ANY、EXISTS关键字来处理多行表达式结果集的条件判断。
ALL
表示结果集之和。
ANY
表示比结果集任何一个。
EXISTS
关键字是把原来在子查询之外的条件判断,写到了子查询的里面。表示子查询是否存在,存在返回true,否则返回false。
5、子查询案例
如何用子查询查找FORD和MARTIN两个人的同事?
SELECT ename
FROM t_emp
WHERE
deptno IN(
SELECT deptno FROM t_emp WHERE ename IN ("FORD","MARTIN")
) AND ename NOT IN ("FORD","MARTIN");
查询工资等级是3级或者4级的员工信息
SELECT empno, ename, sal
FROM t_emp
WHERE EXISTS(
SELECT * FROM t_salgrade
WHERE sal BETWEEN losal AND hisal
AND grade IN (3, 4)
);
七、INSERT语句
INSERT语句可以向数据表写入记录,可以是一条记录,也可以是多条记录。
写入多条:
1、INSERT语句案例
向技术部添加一条员工记录
INSERT INTO t_emp
(empno, ename, job, mgr, hiredate, sal, comm, deptno)
VALUES(8001, "刘娜", "SALESMAN", 8000, "1988-12-20", 2000, NULL,
(SELECT deptno FROM t_dept WHERE dname= "技术部"));
2、INSERT语句方言
MySQL的INSERT语句还有一种方言语法:
3、IGNORE关键字
IGNORE关键字会让INSERT只插入数据库不存在的记录。
八、UPDATE语句
UPDATE语句用于修改表的记录
1、UPDATE语句的表连接
因为相关子查询效率非常低,所以我们可以利用表连接的方式来改造UPDATE语句。
UPDATE语句的表连接可以演变成下面的样子。
表连接的UPDATE语句可以修改多张表的记录。
UPDATE语句的表连接既可以是内连接,又可以是外连接
2、UPDATE语句案例
把每个员工的编号和上司的编号+1,用ORDER BY子句完成
UPDATE t_emp empno=empno+1, mgr=mgr+1
ORDER BY empno DESC;
把月收入前三名的员工底薪减100元,用LIMIT子句完成
UPDATE t_emp SET sal=sal-100
ORDER BY sal+IFNULL(comm, 0) DESC
LMIT 3;
把ALLEN调往RESEARCH部门,职务调整为ANALYST
UPDATE t_emp e JOIN t_dept d
SET e.deptno = d.deptno, e.job = "ANALYST"
WHERE e.ename="ALLEN" AND d.dname="RESEARCH"
把底薪低于公司平均底薪的员工,底薪增加150元
UPDATE t_emp e JOIN
(SELECT AVG(sal) AS avg FROM t_emp) t
ON e.sal<t.avg
SET e.sal=e.sal+150;
把没有部门的员工,或者SALES部门低于2000元底薪的员工,都调往20部门
UPDATE t_emp e LEFT JOIN t_dept d ON e.deptno=d.deptno
SET e.deptno=20
WHERE e.deptno IS NULL OR (d.dname="SALES" AND e.sal<2000);
九、DELETE语句
DELETE语句用于删除记录,语法如下:
1、DELETE语句的表连接
因为相关子查询效率非常低,所以我们可以利用表连接的方式来改造DELETE语句。
DELETE语句的表连接既可以是内连接,又可以是外连接
2、快速删除数据表全部记录
DELETE语句是在事务机制下删除记录,删除记录之前,先把将要删除的记录保存在日志文件里,然后再删除记录。
TRUNCATE语句在事物机制之外删除记录,速度远超过DELETE语句
3、DELETE语句案例
删除20部门中工资最高的员工记录
DELETE FROM t_emp
WHERE deptno= 20
ORDER BY sal+IFNULL(comm, 0) DESC
LIMIT 1;
删除SALES部门和该部门的全部员工记录
DELETE e, d
FROM t_emp e JOIN t_dept d ON e.deptno=d.deptno
WHERE d.dname="SALES";
删除每个低于部门平均底薪的员工记录
DELETE e
FROM t_emp e JOIN
(SELECT deptno, AVG(sal) AS sal FROM t_emp GROUP BY deptno) t
ON e.deptno=t.deptno AND e.sal<t.sal;
删除员工KING和他的直接下属的员工记录,用表连接实现
DELETE e
FROM t_emp e JOIN
(SELECT empno FROM t_emp WHERE ename="KING") t
ON e.mgr=t.deptno OR e.empno=t.empno;
删除SALES部门的员工,以及没有部门的员工
DELETE e
FROM t_emp e LEFT JOIN t_dept d ON e.deptno=d.deptno
WHERE d.dname= "SALES" OR e.deptno IS NULL;
十、MySQL函数
1、数字函数
2、日期函数
获取系统时间函数:
NOW()函数能获得系统日期和时间,格式yyyy-MM-dd hh:mm:ss
CURDATE()函数能获得当前系统日期,格式yyyy-MM-dd
CURTIME()函数能获得当前系统时间,格式hh:mm:ss
日期格式化函数:
DATE_FORMAT(日期, 表达式) 函数用于格式化日期,返回用户想要的日期格式。
其中,表达式有以下多种格式:
案例:
利用日期函数,查询1981年上半年入职的员工有多少人?
SELECT COUNT(*) FROM t_emp
WHERE DATE_FORMAT(hiredate, "%Y")=1981
AND DATE_FORMAT(hiredate, "%m")<=6;
日期计算的注意事项:
MySQL数据库里面,两个日期不能直接加减,日期也不能与数字加减。
日期偏移计算:
DATE_ADD()函数可以实现日期的偏移计算,而且时间单位很灵活。
案例:
SELECT DATE_ADD(NOW(), INTERVAL 15 DAY);
SELECT DATE_ADD(NOW(), INTERVAL -300 MINUTE);
SELECT DATE_ADD(DATE_ADD(NOW(), INTERVAL -6 MONTH), INTERVAL -3 DAY);
计算日期之间相隔的天数:
DATEDIFF()函数用来计算两个日期之间相差的天数
3、字符函数
4、条件函数
判断是否为null并替换null值:
if 函数,表达式为真时返回第一个值,否则返回第二个值:
条件语句:
案例:
SALES部门发放礼品A,其余部门发放礼品B,打印每名员工获得的礼品
SELECT
e.empno, e.ename, d.dname,
IF(d.dname="SALES","礼品A","礼品B")
FROM t_emp e JOIN t_dept d ON e.deptno=d.deptno;
SALES部门去平p1地点,ACCOUNTING部门去p2地点,RESEARCH部门去p3地点
SELECT
e.empno, e.ename, d.dname,
CASE
WHEN d.dname="SALES" THEN "p1"
WHEN d.dname="ACCOUNTING" THEN "p2"
WHEN d.dname="RESEARCH" THEN "p3"
END AS place
FROM t_emp e JOIN t_dept d ON e.deptno=d.deptno;
SALES部门中工龄超过20年,10%
SALES部门中工龄不满20年,5%
ACCOUNTING部门,300元
RESEARCH部门里低于部门平均底薪,200元
没有部门的员工,100元
UPDATE t_emp e LEFT JOIN t_dept d ON e.deptno = d.deptno
LEFT JOIN (SELECT deptno, AVG(sal) AS avg FROM t_emp GROUP BY deptno) t
ON e.deptno=t.deptno
SET sal=(
CASE
WHEN d.dname= "SALES" AND DATEDIFF(NOW(), e.hiredate)/365>=20
THEN e.sal*1.1
WHEN d.dname= "SALES" AND DATEDIFF(NOW(), e.hiredate)/365<20
THEN e.sal*1.05
WHEN d.dname="ACCOUNTING" THEN e.sal+300
WHEN d.dname="RESEARCH" AND e.sal<t.avg THEN e.sal+200
WHEN e.deptno IS NULL THEN e.sal+100
ELSE e.sal
END
);
不按字段原值排序小技巧
当排序字段值不多,排序需求变更时,又不想关联查询加重SQL时,可以在SQL语句的order by语句后添加case when then语句。
select * from table_name
order by case
when level = 1 then 1
when level = 4 then 2
when level = 2 then 3
when level = 3 then 4
else 5 end desc
第四章、数据导入与导出
一、数据导出
数据导出:导出的纯粹是业务数据
数据备份:备份的数据文件、日志文件、索引文件等等
1、数据导出的分类
2、导出SQL文件
mysqldump 用来把业务数据导出成SQL文件,其中也包括了表结构。
3、导入SQL文件
source命令用于导入SQL文件,包括创建数据表,写入记录等。
4、导出文本文档
导出的文档里有纯粹的数据,而不是SQL语句。导入文本文档的时候是跳过词法分析和语法优化,把文本文档的数据写入到MySQL的数据文件里,导入速度非常快。所以逻辑库数据非常多的情况使用这种方法。
命令比较复杂,一般用navicat
图形界面方式操作:
第一步,备份表结构。
数据表上右键,点击【转存SQL文件】下的【仅结构…】选择备份的路径保存。
第二步,导出数据。
数据表上右键,点击【导出向导…】按照后续步骤选择选项导出即可。
二、数据导入
1、导入文本文档
一般用navicat
图形界面方式操作:
第一步,导入表结构。
逻辑库上右键,点击【运行SQL文件】选择备份的路径开始。
第二步,导入数据。
数据表上右键,点击【导入向导…】按照后续步骤选择选项导出即可。