*
MySQL 的安装与配置在解压文件包中添加文件 my.ini [mysql] # 设置mysql客户端默认字符集 default-character-set=utf8 [mysqld] # 设置3306端口 port = 3306 # 设置mysql的安装目录 basedir=D:\mysql-8.0.19-winx64 # 设置 mysql数据库的数据的存放目录 # datadir=D:\mysql-8.0.19-winx64\data # 允许最大连接数 max_connections=20 # 服务端使用的字符集默认为8比特编码的latin1字符集 character-set-server=utf8 # 创建新表时将使用的默认存储引擎 default-storage-engine=INNODB 然后可以设置环境变量 MYSQL_HOME 路径为压缩包的根路径,最后在path中加入即可(后面跟上/bin) 进行bin里面 mysqld --initialize-insecure 生成空的密码 或者 mysqld --initialize --console 初始化,后面有系统自动生成的密码 安装mysql服务 命令:mysqld install 若要删除mysql服务,可执行命令 mysqld --remove mysql 修改密码 alter user’root’@‘localhost’ identified with mysql_native_password by ‘新密码’;
*
SQL 语言分类DML(数据操作语言):添加、修改、删除、查询(CRUD)
DCL(数据控制语言):用户、权限、事务
DDL(数据定义语言):逻辑库、数据表、视图、索引
# DDL 语言 use test; # 创建数据表 CREATE TABLE student( id INT UNSIGNED PRIMARY KEY, name VARCHAR(20) NOT NULL, sex CHAR(1) NOT NULL, birthday DATE NOT NULL, tel CHAR(11) NOT NULL, remark VARCHAR(200) ); # 插入数据 INSERT INTO student VALUES(1, "bright", "男", "2000-10-13", "18380743125", NULL); # 显示当前数据库所有数据表 SHOW TABLES; # 删除 student表 DROP TABLE student; # 显示student表各字段的结构 DESC student; # 修改student表结构 ALTER TABLE student ADD address VARCHAR(200) NOT NULL, ADD home_tel CHAR(11) NOT NULL; ALTER TABLE student MODIFY home_tel VARCHAR(20) NOT NULL # 修改字段的名称(将address字段改为home_address ALTER TABLE student CHANGE address home_address VARCHAR(20) NOT NULL; # 删除表中的字段 ALTER TABLE student DROP home_address, DROP home_tel; # 唯一约束UNIQUE可以为NULL且表中字段不能重复 CREATE TABLE t_teacher( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20) NOT NULL, tel CHAR(11) NOT NULL UNIQUE, married BOOLEAN NOT NULL DEFAULT FALSE ); # 创建附表 CREATE TABLE t_dept( deptno INT UNSIGNED PRIMARY KEY, dname VARCHAR(20) NOT NULL UNIQUE, tel CHAR(4) UNIQUE ); # 创建主表 CREATE TABLE t_emp( empno INT UNSIGNED PRIMARY KEY, ename VARCHAR(20) NOT NULL, sex ENUM("男", "女") NOT NULL, deptno INT UNSIGNED NOT NULL, hiredate DATE NOT NULL, # 外键约束 FOREIGN KEY(deptno) REFERENCES t_dept(deptno) );
*
范式*
索引# 在创建表时为消息类型添加索引 CREATE TABLE t_message( id INT UNSIGNED PRIMARY KEY, content VARCHAR(200) NOT NULL, type ENUM("公告", "通告", "个人通知") NOT NULL, create_time TIMESTAMP NOT NULL, # 索引名: idx_type INDEX idx_type(type) ); #对已存在的表添加索引 # 删除索引 DROP INDEX idx_type ON t_message; # 在已存在的表中创建索引 CREATE INDEX idx_type ON t_message(type); # 显示表中所有的索引, 主键也是索引 SHOW INDEX FROM t_message; # 通过修改表的形式添加索引 ALTER TABLE t_message ADD INDEX idx_type(type);
*
数据库的查询查询语句的子句执行顺序
数据分页
# SELECT ... FROM ... LIMIT 起始位置, 偏移量 SELECT empno, ename FROM t_emp LIMIT 0,5; # 如果LIMIT 子句只有一个参数则表示偏移量, 起始值默认为0 SELECT empno, ename FROM t_emp LIMIT 20; # 前20条数据
结果集排序
# SELECT ... FROM ... ORDER BY 字段名 DESC/ASC(默认); SELECT empno, ename FROM t_emp ORDER BY empno DESC; SELECT empno, ename FROM t_emp ORDER BY empno ASC LIMIT 0,5; # 对多个字段进行排序 SELECT empno, ename, sal, hiredate FROM t_emp ORDER BY sal DESC, hiredate DESC;
结果集中的重复记录
SELECT DISTINCT job FROM t_emp; # 会失效,内容不完全相同 SELECT DISTINCT job, ename FROM t_emp;
条件查询
WHERE子句的注意事项
比较运算符
# 条件:工龄超过20年且部门号为10且年薪超过15000的员工信息 SELECT empno, sal FROM t_emp WHERE deptno=10 # IFUNLL(comm, 0) 如果comm为null则返回0 AND (sal + IFNULL(comm, 0)) * 12 >= 15000 # NOW() 返回当前时间, DATEDIFF 计算两个参数之间的天数 AND DATEDIFF(NOW(),hiredate) / 365 >= 20; SELECT empno, ename, sal, deptno, hiredate FROM t_emp # deptno IN(10,20,30) 若 deptno 为10,20,30 则返回true WHERE deptno IN(10,20,30) AND job != "SALESMAN" AND hiredate < "1985-01-01"; SELECT empno, ename, sal, deptno, comm FROM t_emp WHERE comm IS NOT NULL AND sal BETWEEN 1000 and 2000 # ename 必须为2到4个的汉字 AND ename REGEXP "^[\\u4e00-\\u9fa5]{2,4}$" # AND ename LIKE "%A%"; ename字段含有A SELECT empno, ename, sal, deptno, comm FROM t_emp WHERE NOT deptno IN(10, 30) # 查询30部门的信息 XOR comm IS NOT NULL
分组查询
# ROUND 四舍五入函数 SELECT deptno, ROUND(AVG(sal)) FROM t_emp GROUP BY deptno ORDER BY deptno ASC; # 逐级分组 SELECT deptno, job, COUNT(empno) "人数", ROUND(AVG(sal)) FROM t_emp GROUP BY deptno, job ORDER BY deptno ASC SELECT deptno, COUNT(empno) "人数", ROUND(AVG(sal)) "平均值", SUM(sal), MAX(sal) "最大值", MIN(sal) "最小值" FROM t_emp GROUP BY deptno # 对分组查询集再一次统计 WITH ROLLUP
having 子句
SELECT deptno FROM t_emp GROUP BY deptno HAVING AVG(sal) > 2000 # 查询每个部门中,1982年以后入职的员工超过2个人的部门编号 SELECT deptno FROM t_emp WHERE hiredate >= "1982-01-01" GROUP BY deptno HAVING COUNT(deptno) >= 2 # 1是值select后的第一个查询属性 SELECT deptno, COUNT(empno) "人数" FROM t_emp WHERE deptno IN(20, 30) GROUP BY 1;
表连接查询
# 内连接三种写法 1. select ... from 表1 [INNER] JOIN 表2 ON 连接条件 2. select ... from 表1 [INNER] JOIN 表2 where 连接条件 3. select ... from 表1, 表2 where 连接条件 # 查询每位员工的部门信息(内连接) SELECT e.empno, e.ename, d.dname # INNER 一般省略 FROM t_emp e INNER JOIN t_dept d ON e.deptno = d.deptno # 查询每个员工的工号、姓名、部门名称、底薪、职位、工资等级(三表连接) SELECT e.empno, e.ename, d.dname, e.sal, e.job, s.grade FROM t_emp e JOIN t_dept d ON e.deptno=d.deptno JOIN t_salgrade s ON e.sal BETWEEN s.losal AND s.hisal; # 查询与SCOTT相同部门的人 SELECT ename FROM t_emp # 效率比较低,deptno=后面会执行很多次 WHERE deptno = (SELECT deptno FROM t_emp WHERE ename="SCOTT") AND ename!="SCOTT"; # 查询与SCOTT相同部门的人(对上面做的优化,提高查询的性能) SELECT e2.ename FROM t_emp e1 JOIN t_emp e2 ON e1.deptno=e2.deptno # 上面做完内连接后,条件是:e1=scott e2!=scott, 筛选结果在e2中 WHERE e1.ename="SCOTT" AND e2.ename!="SCOTT"; # 查询底薪超过公司平均底薪的员工信息(将查询到的结果当成表作为条件) SELECT e.deptno, e.ename, e.sal FROM t_emp e JOIN (SELECT AVG(sal) avg FROM t_emp) t ON e.sal > t.avg; # 查询RESEARCH部门的人数、最高底薪、最低底薪、平均底薪、平均工龄 SELECT COUNT(empno) "人数", MAX(sal) "最高底薪", MIN(sal) "最低底薪", AVG(sal) "平均底薪", # FLOOR 向下取整函数 CEIL 向上取整函数 FLOOR(AVG(DATEDIFF(NOW(),hiredate) / 365)) FROM t_emp e JOIN t_dept d ON e.deptno=d.deptno WHERE d.dname="RESEARCH" # 查询每种职业的最高工资、最低工资、平均工资、最高工资等级和最低工资等级 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 # 查询每个底薪超过部门平均底薪的员工信息 SELECT e.empno, e.ename, 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
外连接
左外连接就是保留左表所有的记录与右表做连接。如果右表有符合条件的记录就与左表连接,若没有符合条件的的记录则用NULL与左表连接,同理右外连接
若某人是临时员工,他没有部门号,若根据内连接部门号查询,会漏掉该人信息
外连接的注意事项:
SELECT e.empno, e.ename, d.dname FROM t_emp e LEFT JOIN t_dept d ON e.deptno=d.deptno # 查询每个部门的名称和部门的人数 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 关键字可以将多个查询语句的结果集合并 # 查询每个部门的名称和部门的人数, 没有部门的用null来统计出来 (SELECT d.dname, COUNT(*) FROM t_dept d RIGHT JOIN t_emp e ON d.deptno=e.deptno GROUP BY d.deptno ) UNION (SELECT d.dname, COUNT(e.deptno) FROM t_dept d LEFT JOIN t_emp e ON d.deptno=e.deptno GROUP BY d.deptno); # 查询每名员工的编号、姓名、部门、月薪、工资等级、工龄、上司编号、上司姓名。上司部门 SELECT e.empno "员工号", e.ename "姓名", d.dname "部门名称", e.sal + IFNULL(e.comm, 0) "月薪", s.grade "工资等级", FLOOR(DATEDIFF(NOW(),e.hiredate) / 365) "工龄", t.empno "上司编号", t.ename "上司姓名", t.dname "上司部门" FROM t_emp e LEFT JOIN t_dept d ON e.deptno=d.deptno LEFT JOIN t_salgrade s ON e.sal BETWEEN s.losal AND s.hisal LEFT JOIN ( SELECT e1.empno, e1.ename, d1.dname FROM t_emp e1 JOIN t_dept d1 ON e1.deptno=d1.deptno ) t ON e.mgr=t.empno;
子查询
SELECT empno, ename, sal FROM t_emp WHERE sal >= (SELECT AVG(sal) FROM t_emp)
单行子查询与多行子查询
# 查询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"); # 查询比FORD和MARTIN底薪都高的员工信息 ALL都要满足 SELECT ename, sal FROM t_emp WHERE sal >= ALL(SELECT sal FROM t_emp WHERE ename IN("FORD", "MARTIN")) AND ename NOT IN("FORD","MARTIN"); # 查询至少比FORD和MARTIN高一个的员工信息 ANY满足一个即可 SELECT ename, sal FROM t_emp WHERE sal >= ANY(SELECT sal 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 grade FROM t_salgrade WHERE sal BETWEEN losal AND hisal AND grade IN(3,4) )
*
INSERT# 向技术部添加一条员工记录(根据部门名称查询部门号然后再插入) # 该子查询只能单行单列的 INSERT INTO t_emp VALUES(8001, "刘娜", "SALESMAN", 8000, "1988-12-20", 2000, NULL, (SELECT deptno FROM t_dept WHERE dname="技术部")) # MySQL的方言 INSERT [INTO] t_emp SET empno=8002, ename="JACK", job="SALESMAN", mgr=8000, hiredate="1985-3-19", sal=2500, deptno=50 # INGORE的使用 INSERT IGNORE t_emp SET empno=8002, ename="JACK", job="SALESMAN", mgr=8000, hiredate="1985-3-19", sal=2500, deptno=50
*
UPDATEUPDATE t_emp SET empno=empno+1, mgr=mgr+1 ORDER BY empno DESC; # 把月收入前三名的员工的底薪减100元 UPDATE t_emp SET sal = sal - 100 ORDER BY sal + IFNULL(comm,0) DESC LIMIT 3; # 把10部门中,工龄超过20年的员工,底薪增加200元 UPDATE t_emp SET sal = sal + 200 WHERE deptno=10 AND (DATEDIFF(NOW(),hiredate) / 365) >=20; # 把ALLEN调往RESEARCH部门,职务调整为ANALYST UPDATE t_emp e, (SELECT deptno FROM t_dept WHERE dname="RESEARCH") t SET e.deptno=t.deptno , job="ANALYZE" WHERE e.ename="ALLEN" # 表连接写法, 上面是子查询写在update中 UPDATE t_emp e JOIN t_dept d SET e.deptno=d.deptno, job="ANALYZE" WHERE e.ename="ALLEN" AND d.dname="RESEARCH"; # 把底薪低于公司平均底薪的员工,底薪增加150元 UPDATE t_emp e, (SELECT AVG(sal) avg FROM t_emp) t SET sal=sal+150 WHERE e.sal < t.avg;
*
DELETEDELETE 语句是在事务机制下删除记录,删除记录之前,先把将要删除的记录保存到日志文件中,然后再删除记录。
临时表是不能删除的
TRUNCATE 语句在事务机制之外删除记录,速度元超于DELETE语句
# 删除10部门中,工龄超过20年的员工记录 DELETE FROM t_emp WHERE deptno=10 and (DATEDIFF(NOW(),hiredate) / 365) > 50; # 删除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) avg_sal FROM t_emp GROUP BY deptno) t ON e.deptno=t.deptno AND e.sal < t.avg_sal; # 删除员工KING和他的直接下属的员工记录,用表连接实现 DELETE e1, e2 FROM t_emp e1 JOIN t_emp e2 ON e1.empno=e2.mgr WHERE e1.ename="KING"; #或者 DELETE e FROM t_emp e JOIN (SELECT empno FROM t_emp WHERE ename="KING") t ON e.mgr=t.empno 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; # 使用TRUNCATE语句删除表 TRUNCATE TABLE t_emp;
*
MySQL 内置函数SELECT ABS(-100); # 100 SELECT ROUND(4.6288*100) / 100; # 4.63 SELECT FLOOR(9.9); # 9 SELECT CEIL(9.1); # 10 SELECT POW(2,3); # 8 SELECT LOG(2,8); # 3 SELECT LN(1); # 0 SELECT PI(); # 3.141593 SELECT SQRT(9); # 3 SELECT COS(RADIANS(60)); # 0.5 # 查询1981年上半年入职的员工人数 SELECT COUNT(empno) FROM t_emp WHERE DATE_FORMAT(hiredate,"%Y") = 1981 AND DATE_FORMAT(hiredate,"%m") <= 6 SELECT DATE_FORMAT(DATE_ADD(NOW(),Interval 100 DAY),"%y/%m/%d"); # 21/09/27
SELECT INSERT("你好", 1, 0, "先生"); # 先生你好 SELECT LOWER(ename), UPPER(ename), LENGTH(ename),CONCAT("$", sal), INSTR(ename, "A") FROM t_emp SELECT INSERT("你好", 1, 1, "先生"); # 先生好
SELECT TRIM(" hello world! "); # hello world! SELECT LPAD(SUBSTRING("18380743125",8,4), 11, "*"); // *******3125 SELECT RPAD(SUBSTRING("18380743125",1,4), 11, "*"); // *******1838 SELECT RPAD(SUBSTRING("李晓娜", 1, 1),LENGTH("李晓娜") / 3,"*");
条件函数
# 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; # 复杂的判断 SELECT e.empno, e.ename, CASE WHEN d.dname="SALES" THEN "P1" WHEN d.dname="ACCOUNTING" THEN "P2" WHEN d.dname="RESEARCH" THEN "P3" END place FROM t_emp e JOIN t_dept d ON e.deptno=d.deptno;
*
事务机制事务的ACID属性:原子性、一致性、隔离性、持久性
事务的四个隔离级别
# 可以读取到未提交的临时数据 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; START TRANSACTION; SELECT empno, ename, sal FROM t_emp COMMIT; # 只能读到已提交后的数据 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; START TRANSACTION; SELECT empno, ename, sal FROM t_emp COMMIT; SET SESSION TRANSACTION ISOLATION LEVEL repeatable read; START TRANSACTION; SELECT empno, ename, sal FROM t_emp COMMIT; # 较少使用,上一个事务执行完了,才会执行该事务 SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; START TRANSACTION; SELECT empno, ename, sal FROM t_emp COMMIT;
数据导出与备份的区别
数据导出,导出的纯粹是业务数据
mysqldump -uroot -p demo > E:\data\demo.sql(导出到的物理路径) 然后输入密码即可
数据导入
USE demo SOURCE E:/data/demo.sql;(导入的来源--物理路径)
数据备份,备份的是数据文件、日志文件、索引文件等