MySQL数据库的基本使用

  • 开启mysql

    net start mysql;
    
  • 关闭MySQL

  • net stop mysql;
    
  • 登陆mysql

  • 语法:mysql -u 用户名 -p 密码(密码可以省略)

    mysql -u root -p
    

一、数据库的创建、删除、修改、备份、查看

1.创建数据库

  • 语法: CREATE DATABASE 数据库名称 CHARACTER SET 字符集 COLLATE 校验规则;

  • 创建数据库和创建表时为了避免使用到关键字可以使用反引号 ` 规避

  • 字符集和校验规则部分可以省略,使用默认字符集 "utf8",默认校验规则 "utf8_general_ci";

  • 默认校验规则不区分大小写,使用 "utf8_bin" 区分大小写

CREATE DATABASE hsp_db03 CHARACTER SET utf8 COLLATE utf8_bin;

2.删除数据库

  • 谨慎使用

  • 语法: DROP DATABASE 数据库名称;

  • DROP DATABASE hsp_db02;
    

3.数据库的修改

4.数据库的备份

  • 数据库备份需要在Dos下执行mysqldump指令(保存路径最好不要有中文)

  • 语法: mysqldump -u 用户名-p -B 数据库名称(同时备份多个使用空格隔开) > 备份路径+文件名称.sql;

  • mysqldump -u root -p -B hsp_db01 hsp_db02 > d:\\2023\\DATABASE_LEARN\\hsp_mysql\\dump01.sql;
    
  • 表的备份,(与数据库备份的区别:不带"-B")

  • 语法: 语法: mysqldump -u 用户名-p 数据库名称 表名(同时备份多个使用空格隔开) > 备份路径+文件名称.sql;

  • mysqldump -u root -p hsp_db01 t1 > D:\\2023\\DATABASE_LEARN\\hsp_mysql\\dump02.sql;
    
    

5.数据库的恢复

  • 恢复数据库需要在mysql命令行执行命令

  • 语法: source 备份路径+文件名称.sql;

  • source d:\\2023\\数据库学习\\hsp_mysql\\dump01.sql;
    

6.数据库的查看

#查看当前数据库服务中的的所有数据库
SHOW DATABASES; 
#查看创建数据库时的定义信息
SHOW CREATE DATABASE hsp_db01;
# 查看数据库中的所有表
SHOW TABLES;

二、表的创建、删除、备份、修改、查看、查询

1.表的创建

  • 语法: CREATE TABLE 表名称 (字段名 数据类型(长度),字段名 数据类型(长度),...)CHARACTER SET 字符集 COLLATE 校验规则 ENGINE 存储引擎类型;

  • 创建数据库和创建表时为了避免使用到关键字可以使用反引号 ` 规避

  • 没有指定长度,则为最大长度

  • 字符集、校验规则和引擎部分可以省略,默认使用数据库的字符集和校验规则,默认引擎:INNODB

    CREATE TABLE `user`(id INT,`name` VARCHAR(255),`psw` VARCHAR(32),`birthday` DATE)CHARACTER SET utf8 COLLATE utf8_bin ENGINE INNODB;
    

    快速创建一个结构相同的表

    • 语法: CREATE TABLE 要创建的表名 LIKE 作为模板的表;
    CREATE TABLE hsp_db04 LIKE hsp_db03;
    

2.表的删除

  • 语法: DROP TABLE 表名称;

     DROP TABLE hsp_db03;
    

3.表的备份

  • 表的备份,(与数据库备份的区别:不带"-B")
  • 语法: 语法: mysqldump -u 用户名-p 数据库名称 表名(同时备份多个使用空格隔开) > 备份路径+文件名称.sql;
  • 表的恢复方法和数据库一样
mysqldump -u root -p hsp_db01 t1 > D:\\2023\\DATABASE_LEARN\\hsp_mysql\\dump02.sql;

4.表的修改 (ALTER )

(1)添加字段 (ADD )

  • 语法: ALTER TABLE 表名 ADD 字段名 数据类型 AFTER 已经存在的字段名;

(2)修改字段 (MODIFY )

  • 语法: ALTER TABLE 表名 MODIFY 字段名 数据类型;

    • 语法: ALTER TABLE 表名 MODIFY 字段名 数据类型;

    (3)删除字段 (DROP )

(3)删除字段 (DROP )

  • 语法: ALTER TABLE 表名 DROP 字段名;

(4)修改表名 (RENAME )

  • 语法: RENAME TABLE 要修改的表名 TO 修改后的表名;

(5)修改表的字符集 (CHARACTER SET)

  • 语法: ALTER TABLE 表名 CHARACTER SET 字符集;

(6)修改字段名 (CHANGE )

  • 语法:ALTER TABLE 表名 CHANGE 要修改的字段名 修改后的字段名;

(7)修改存储引擎

  • 语法:ALTER TABLE 表名 ENGINE = 存储引擎类型

    ALTER TABLE t25 ENGINE = INNODB;

#在resume字段后天加imge字段
ALTER TABLE emp ADD imge VARCHAR(32) NOT NULL DEFAULT '' AFTER resume;
#修改job列
ALTER TABLE emp MODIFY job VARCHAR(69) NOT NULL DEFAULT '';
#删除sex列
ALTER TABLE emp DROP sex;
#修改表名
RENAME TABLE emp TO employee;
#修改表的字符集
ALTER TABLE employee CHARACTER SET utf8;
#修改字段名name -> user_name
ALTER TABLE employee CHANGE `name` `user_name` VARCHAR(60) NOT NULL DEFAULT '';

5.表的结构查看 (DESC )

  • 语法: DESC 表名;
DESC hsp_db03;

6.表的查询 (SELECT )

  • 字段使用 " * " 代表所有字段

  • 语法: SELECT 字段名(*) FROM 表名(多个使用 " , " 隔开) WHERE 过滤条件;

  • 去重查询使用, "DISTINCT" 关键字

    #去重查询,一条数据完全相同时去重
    SELECT DISTINCT english FROM student;
    
  • 使用别名使用 "AS" 关键字

    SELECT `name` AS '名字',(chinese + english + math +10) AS total_score FROM student;
    

分组查询(group by)

  • 分组查询使用 "GROUP BY" ,过滤通常使用 "HAVING" 关键字

    #分组(查询)统计
    -- 显示每个部门的平均工资和最高工资
    SELECT AVG(sal),MAX(saL),deptno FROM emp GROUP BY deptno; 
    -- 显示每个部门每个岗位的平均工资和最低工资
    SELECT AVG(sal),MIN(saL),deptno,job FROM emp GROUP BY deptno,job;
    -- 显示平均工资低于2000的部门和它的平均工资
    SELECT AVG(sal) AS 'avg',deptno FROM emp GROUP BY deptno HAVING avg < 2000;-- 使用having过滤
    #增强group by 的使用演示
    -- 显示每种岗位的雇员人数和平均工资
    SELECT COUNT(*),job,FORMAT(AVG(sal),2) FROM emp GROUP BY job;
    -- 显示雇员总数,以及获得补助的员工人数
    SELECT COUNT(*),COUNT(comm) FROM emp;-- COUNT(列),不会统计为null的行
    -- 统计没有获得补助的人数
    SELECT COUNT(*),COUNT(IF(comm IS NULL,1,NULL)) FROM emp;
    -- 显示管理者的人数
    SELECT COUNT(DISTINCT mgr) FROM emp;-- 使用distinct去重,DISTINCT
    -- 显示工资最大和最小的差值
    SELECT MAX(sal) - MIN(sal) FROM emp;
    
  • 模糊查询使用 "LIKE" 关键字

    • "%" (百分号)表示0到多个字符, "_"(下划线)表示单个任意支付

      # "%" (百分号)表示0到多个字符, "_"(下划线)表示单个任意字符
      -- 显示首字母为S的员工的工资
      SELECT ename,sal FROM emp WHERE ename LIKE 'S%';
      -- 显示名字第三个字母为O的员工
      SELECT ename,sal FROM emp where ename LIKE '__O%';
      
  • 也支持使用正则表达式进行查询(使用REGEXP)

    • 语法:REGEXP '匹配规则'

查询排序(order by)

  • 查询后排序使用 "ORDER BY"关键字,默认降序排列(DESC),后接 "ASC" 为升序排列

    -- 按照工资升序排列
    SELECT * FROM emp ORDER BY sal ASC;
    -- 按照部门号升序,然后按照工资降序
    SELECT * FROM emp ORDER BY deptno ASC,sal DESC;-- 先第一个条件,加逗号再写第二个条件
    
  • 分页查询使用 "LIMIT" 关键字

    #LIMIT start,rows,表示从start + 1(start从0开始计算),开始显示,显示rows行,为一页,写在查询语句的最后
    -- 按 雇员的ID升序排列,每一页显示三行
    SELECT * FROM emp ORDER BY empno LIMIT 0,3;-- 第一页
    SELECT * FROM emp ORDER BY empno LIMIT 3,3;-- 第二页
    SELECT * FROM emp ORDER BY empno LIMIT 6,3;-- 第三页
    
  • 过滤条件:逻辑与: "AND",逻辑或: "OR", 逻辑否: "NOT"

  • 判断是否为空使用 "IS" 关键字,不能使用等号 "=" 或 双等号 "=="

    #select的使用
    SELECT * FROM student;-- 查询表中的所有数据
    #查询姓名的对应的英语成绩,限定查询
    SELECT `name`,english FROM student;
    #去重查询,一条数据完全相同时去重
    SELECT DISTINCT english FROM student;
    #在查询过程可以进行运算
    -- 统计学生的总分
    SELECT `name`,(chinese + english + math) FROM student;
    #在总分的基础上加10分
    SELECT `name`,(chinese + english + math +10) FROM student;
    #使用别名显示统计的数据
    SELECT `name` AS '名字',(chinese + english + math +10) AS total_score FROM student;
    
    #使用where过滤的查询
    -- 查询名字为赵云的数据
    SELECT * FROM student WHERE `name`  = '赵云';
    -- 查询英语成绩大于90的数据
    SELECT * FROM student WHERE english > 90;-- 使用条件表达式
    #查询总分大于200的数据
    SELECT * FROM student WHERE (chinese + english + math) > 200;
    ALTER TABLE student CHANGE `NAME` `name` VARCHAR(4);-- 修改字段名
    #查询math大于60 并且(and)id大于4的数据
    SELECT * FROM student WHERE math > 60 and id > 4;
    #查询英语成绩大于语文成绩的数据
    SELECT * FROM student WHERE english > chinese;
    #查询总分大于200分,并且数学成绩下雨语文成绩并且姓'韩'的学生
    SELECT * FROM student WHERE (chinese + english + math) > 200 and math > chinese and `name` LIKE '韩%';-- 模糊查询
    #查询英语成绩在80 ~ 90之间的数据
    SELECT * FROM student WHERE english >= 80 and english <= 90;
    SELECT * FROM student WHERE english BETWEEN 80 AND 90;
    #查询数学成绩为89,90,91的数据
    SELECT * FROM student WHERE math = 89 or math = 90 or math = 91;
    SELECT * FROM student WHERE math IN (89,90,91);
    #查询姓李的的数据
    SELECT * FROM student WHERE `name` LIKE '李%';
    #查询数学成绩大于80,语文成绩大于80的数据
    SELECT * FROM student WHERE math > 80 and chinese > 80;
    #演示order by的使用,默认是升序排列
    #对数学成绩升序排列
    SELECT * FROM student ORDER BY math;
    #按总分降序排列
    SELECT `name`,(chinese + english + math) AS total_socre FROM student ORDER BY total_socre DESC;
    #对姓韩的成绩进行升序排列
    SELECT `name`,(chinese + english + math) AS total_socre FROM student WHERE `name` LIKE '韩%' ORDER BY total_socre ASC;
    
    
    

三、流程控制函数 (IF,IFNULL)

#流程控制函数
#IF(expr1,expr2,expr3),如果expr1为true,就返回expr2,否则返回expr3,类似Java的三元运算符
SELECT IF(TRUE,'杨逸','hsp') FROM DUAL;
#IFNULL(expr1,expr2),如果expr1为null,就返回expr2,否则返回expr1
SELECT IFNULL('hsp','杨逸') FROM DUAL;
-- 查询emp表,如果comm是null,则显示0.0
SELECT IFNULL(comm,0.0) FROM emp;
SELECT IF(comm IS	NULL,0.0,comm) FROM emp;-- 判断是否为空使用 "IS" 
#多分支流程
/*CASE case_value
	WHEN when_value THEN
		statement_list
	ELSE
		statement_list
END CASE;
case
*/
# 多分支使用 "WHEN" 和 "THEN" 关键字
SELECT ename,(SELECT CASE job
	WHEN 'CLERK' THEN '职员' 
		WHEN 'MANAGER'THEN '经理' 
		WHEN 'SALESMAN' THEN '销售人员'
	ELSE job
END) AS job FROM emp;

四、日期时间相关的函数

#日期相关的函数
-- 返回当前的日期,CURRENT_DATE
SELECT CURRENT_DATE() FROM DUAL;
-- 返回当前的时间,CURRENT_TIME
SELECT CURRENT_TIME() FROM DUAL;
-- 返回当前的时间戳,CURRENT_TIMESTAMP
SELECT CURRENT_TIMESTAMP() FROM DUAL;
-- 返回当前的时间, NOW()
SELECT NOW() FROM DUAL;
# 创建测试表
CREATE TABLE mes(id INT,content CHAR(16),date TIMESTAMP) CHARACTER SET utf8;
#添加测试数据
INSERT INTO mes(id,content,date) VALUE(1,'八甲新闻',CURRENT_TIMESTAMP),(2,'北京新闻',CURRENT_TIMESTAMP),(3,'阳春新闻',CURRENT_TIMESTAMP); 
SELECT * FROM mes;

#查询数据,只显示日期不显示时间,DATE(expr)
SELECT id,content,DATE(date) FROM mes;
#查询在十分钟内发布的新闻
#DATE_ADD(date,INTERVAL expr unit),返回date时间加上某一时间
#DATE_SUB(date,INTERVAL expr unit),返回date时间减去某一时间
SELECT * FROM mes WHERE DATE_ADD(date,INTERVAL 10 MINUTE) >= NOW();
SELECT * FROM mes WHERE DATE_ADD(NOW(),INTERVAL 10 MINUTE) <= date;
#求日期差,DATEDIFF(expr1,expr2),返回的是天数
#求时间差,TIMEDIFF(expr1,expr2),返回的是时分秒
SELECT TIMEDIFF(NOW(),date) AS '时间差' FROM mes;
#求2011-11-11和1990-1-1相差多少天
SELECT DATEDIFF('2011-11-11','1990-1-1') AS '日期差' FROM DUAL;
#求你自己活了多少天
SELECT DATEDIFF(NOW(),'2004-5-15') FROM DUAL;
#假设你能活到80岁,求你现在还能活多少天
SELECT DATEDIFF(DATE_ADD('2004-5-15',INTERVAL 80 YEAR),NOW()) AS '剩余天数' FROM DUAL;
#显示日期和时间的指定部分
SELECT TIMESTAMP(NOW()) FROM DUAL;-- 显示完整日期和时间
SELECT YEAR(NOW()) FROM DUAL;-- 只显示年
SELECT MONTH(NOW()) FROM DUAL;-- 只显示月
SELECT DAY(NOW()) FROM DUAL;-- 只显示日
SELECT HOUR(NOW()) FROM DUAL;-- 只显示小时
SELECT MINUTE(NOW()) FROM DUAL;-- 只显示分钟
SELECT SECOND(NOW()) FROM DUAL;-- 只显示秒
#返回1970-1-1到现在的秒数
SELECT UNIX_TIMESTAMP() FROM DUAL;
#将一个 unix_timestamp 秒数[时间戳],转换成指定的时间格式,FROM_UNIXTIME(unix_timestamp)
# '%Y-%m-%d %h:%i:%s' 是固定格式
SELECT FROM_UNIXTIME(UNIX_TIMESTAMP(),'%Y-%m-%d') FROM DUAL;
SELECT FROM_UNIXTIME(UNIX_TIMESTAMP(),'%Y-%m-%d %h:%i:%s') FROM DUAL;
SELECT FROM_UNIXTIME(UNIX_TIMESTAMP(),'%h:%i:%s') FROM DUAL;
#日期的比较
-- 查询在1992-1-1后入职的员工
SELECT * FROM emp WHERE hiredate > '1992-1-1';
# 返回日期所在月的最后一天,last_day(日期)
SELECT LAST_DAY(NOW()) FROM DUAL;

五、统计函数和数学相关的函数

#统计查询
# 统计所有:count(*),结果为null会统计进去
# 统计部分count(字段...),结果为null的不统计
-- 统计数学成绩大于90的学生有多少个
SELECT COUNT(*) FROM student WHERE math > 90;
-- 统计总分大于250的人数
SELECT COUNT(*) FROM student WHERE (chinese + math + english) > 250;
DESC student;
INSERT INTO student (id,`name`) VALUES(7,'jack'),(8,NULL),(9,NULL);
SELECT * FROM student;
-- 统计所有字段
SELECT COUNT(*) FROM student;
-- 统计部分字段
SELECT COUNT(`name`) FROM student;-- 为null的字段没有被统计

#合计(求和)函数, SUN()
-- 统计一个班的数学总成绩
SELECT SUM(math) FROM student;
-- 统计各科的总成绩
SELECT SUM(math),SUM(chinese),SUM(english) FROM student;
-- 统计一个所有成绩的总和
SELECT SUM(chinese + math + english) FROM student;
-- 统计语文的平均分
SELECT SUM(chinese)/COUNT(*) FROM student;

#求平均的函数,AVG()
-- 求数学平均分
SELECT FORMAT(AVG(math),2) FROM student;
-- 求班级平均分
SELECT FORMAT(AVG(chinese + math + english),2) FROM student;

#求最大值,MAX()
#求最小值,MIN()
-- 求班级最高分和最低分
SELECT MAX(chinese + math + english) AS'MAX',MIN(chinese + math + english) AS 'MIN'FROM student;
-- 求数学最高分和最低分
SELECT MAX(math) AS'MAX',MIN(math) AS 'MIN'FROM student;
#演示数学相关的函数
-- 绝对值,ABS(X)
SELECT ABS(-10) FROM DUAL;
-- 十进制转二进制,BIN(N)
SELECT BIN(8) FROM DUAL;
-- 向上取整, CEILING(X)
-- 向下取整, FLOOR(X)
SELECT CEILING(9.99) FROM DUAL;
SELECT FLOOR(9.99) FROM DUAL;
-- 进制转换, CONV(N,from_base,to_base),将from_base的N,转换成to_base进制
SELECT CONV(8,10,2) FROM DUAL;
-- 控制保留小数的位数,FORMAT(X,D),保留D位小数,四色五入保留
SELECT FORMAT(12.3456,2) FROM DUAL;
-- 转成16进制,HEX(N_or_S)
SELECT HEX(16) FROM DUAL;
-- 求最小值,LEAST(value1,value2,...)
SELECT LEAST(2,2,3,1) AS 'MIN' FROM DUAL;
-- 求余,MOD(N,M),N模M
SELECT MOD(10,3) FROM DUAL;
-- 返回一个随机数,范围在[0,1],RAND()
SELECT RAND() FROM DUAL;
SELECT RAND(1) FROM DUAL; -- 如果加入参数,则返回一个固定的随机数

六、系统函数和加密函数

#演示加密函数和系统函数
#查询用户,USER()
#查询登陆到MySQL的用户的IP地址
SELECT USER() FROM DUAL; -- 用户名@IP地址
#查询当前使用的数据库的名称,DATABASE()
SELECT DATABASE() FROM DUAL;
# MD5(str),加密一个字符串得到一个32位的字符串
SELECT MD5('hsp') FROM DUAL;
SELECT LENGTH(MD5('hsp')) FROM DUAL;

#PASSWORD(str),加密函数,数据库用户的密码就是使用PASSWOED(str)进行加密
SELECT LENGTH(PASSWORD('h12sp')) FROM DUAL;-- 加密后的长度是41

七、字符串常用函数

#字符串常用函数的演示
-- CHARSET(str),返回字符串的字符集
SELECT CHARSET(ename) FROM emp;
-- CONCAT(str1,str2,...),拼接字符串
SELECT CONCAT(ename,' 的工作是 ',job) FROM emp;
-- INSTR(str,substr), 返回substr在str中出现的位置,没有就返回0,MySQL字符串的开始位置为1
SELECT INSTR('杨逸好帅','好') FROM DUAL;-- DUAL 是亚元表,系统自带的表,用于可以测试
-- UCASE(str),将字符串转换成大写
-- LCASE(str),将字符串转换成小写
SELECT UCASE(ename) FROM emp;
SELECT LCASE(ename) FROM emp; 
-- LEFT(str,len),从str的左边起取len个字符
-- RIGHT(str,len),从str的右边取len个字符
SELECT LEFT(ename,2) FROM emp;
SELECT RIGHT(ename,2) FROM emp;
-- LENGTH(str),返回字符串的长度(单位:字节),按字节的方式
SELECT LENGTH(ename) FROM emp;
SELECT LENGTH('   hsp  ') FROM emp;-- 空格占一个字节
-- 字符串的替换,REPLACE(str,from_str,to_str),将字符串str中的from_str替换成to_str
SELECT REPLACE(job,'MANAGER','经理') FROM emp;
-- 字符串比较大小,STRCMP(expr1,expr2),逐字比较
-- 返回0则相等,-1则前者小于后者,1则前者大于后者
SELECT STRCMP('zsp','yangyi') FROM emp;
-- 截取字符串, SUBSTRING(str,pos,len),从pos开始截取,截取len个支符
SELECT SUBSTR(ename,1,1) FROM emp;-- MySQL的字符串从1开始
-- 去除左右两端的空格, TRIM(str)
-- 去除左边的空格,LTRIM(str)
-- 去除右边的空格,RTRIM(str)
SELECT TRIM('  杨逸是软件工程师    ') FROM emp;
SELECT LTRIM('  杨逸是软件工程师    ') FROM emp;
SELECT RTRIM('  杨逸是软件工程师    ') FROM emp;

-- 作业:以首字母小的形式显示emp表的姓名
#	1.截取第一个字符和剩余的字符
# 2.将第一个字符转成小写,其他的字符不变
# 3.将字符进行拼接
SELECT CONCAT(LCASE(SUBSTR(ename,1,1)),SUBSTR(ename,2)) AS 'name' FROM emp;

八、数据库的增删改查(CRUD)

1.添加数据(INSERT)

  • 语法: INSERT INTO 表名(字段名1,字段名2,... ) VALUES (数据1,数据2, ... );

2.更新数据 (UPDATA)

  • 语法: UPDATE 表名 SET 要修改的字段 = 值 WHERE 过滤条件;
  • 不带过滤条件会将整个字段都更新

3.删除数据 (DELETE)

  • 语法: DELETE FROM 表名WHERE 过滤条件;
  • 不带过滤条件会将整个字段都删除
#insert的使用,添加数据
CREATE TABLE goods (id INT,`name` VARCHAR(10),price DOUBLE);
-- 添加数据
INSERT INTO goods(id,`name`,price)VALUES(1,'手机',3999);
INSERT INTO goods(id,`name`,price)VALUES(2,'电脑',9999);

#update的使用,更新数据,可以同时更新多个字段,用逗号隔开
#where是条件筛选,可以带多个字段条件
-- 不带where慎用
UPDATE goods SET price = 6666,`id` = 00;-- 不带where,将所有的price都改成6666
UPDATE goods SET price = 66686 WHERE `name` = '电脑';-- 将指定的列的price修改
#在原有价格的基础上添加1000
UPDATE goods SET price = price + 1000 WHERE `name`  = '手机';

#delete删除数据
-- 不带where会删除表中的所有数据
DELETE FROM goods;
DELETE FROM goods WHERE `name` = '手机';-- 删除name为"手机的整条数据" 

九、多表查询

1.多表查询

  • 多表查询的过滤条件不能少于,表的个数 - 1,否则会出现"笛卡尔集"的现象
-- 默认情况直接查询两张表,结果是:从第一张表取出一行和第二张表的每一行进行拼接
SELECT * FROM emp,dept;
-- 多表查询,需要正确处理过滤条件
SELECT * FROM emp,dept WHERE emp.deptno = dept.deptno;
-- 显示特定的字段
SELECT ename,sal,emp.deptno,dname FROM emp,dept WHERE emp.deptno = dept.deptno;-- 当两张表存在相同的字段是,要指定查询的是哪一张表的
-- 显示部门号为10的部门名和员工名和工资
SELECT ename,sal,emp.deptno,dname FROM emp,dept WHERE emp.deptno = dept.deptno AND emp.deptno = 10;
### 2.自连接 --同时查询同一张表
  • #两个字段都在同一个表,但没有直接指向,
    #员工的上级通过一个员工编号进行指向,一个编号就代表一个员工
    #查询同一张表需要指定表的别名,指定表的别名不需要使用"AS",
    -- 显示员工和他的上级
    SELECT worker.ename AS '员工',boss.ename AS '上级' FROM emp worker,emp boss WHERE worker.mgr = boss.empno;
    

十、子查询

  • 查询中包含查询的查询语句

  • 返回的数据可以当使用,也到字段使用

  • 当表使用时,放在表的位置,"FROM"后面

  • 当字段使用时,放在过滤条件的位置,"WHERE"后面

    1.单行子查询

  • 子查询只返回一行的查询语句

    -- 显示与SMITH同一个部门的员工
    # 先查询到SMITH的部门号,再使用部门号作为条件进行查询
    # 子语句需要括号
    # 单行子查询,子语句只返回一条数据的查询
    SELECT deptno FROM emp WHERE ename = 'SMITH';
    SELECT ename FROM emp WHERE (SELECT deptno FROM emp WHERE ename = 'SMITH');
    

2.多行子查询

  • 子查询只多行的查询语句
  • 过滤条件配合 "IN" 关键字使用
-- 查询和部门10的工作相同的员工的名字、岗位、工资、部门号,但不包含部门10
-- 先查询到部门10有那些岗位,注意去重
# MySQL中不等于可以使用 "!="或者 "<>"
SELECT DISTINCT job FROM emp WHERE deptno = 10;
SELECT ename,job,sal,deptno FROM emp WHERE job IN(SELECT DISTINCT job FROM emp WHERE deptno = 10) AND deptno <> 10;

3. 多列子查询

  • 返回多列数据
-- 查询与SMITH的部门和岗位完全相同的所有员工,不包含SMITH本人
-- 先得到SIMTH的部门和岗位,再查询表进行比较
SELECT deptno,job FROM emp WHERE ename = 'SMITH';
-- 方式一
SELECT * FROM emp WHERE (deptno,job) = (SELECT deptno,job FROM emp WHERE ename = 'SMITH') AND ename != 'SMITH';
-- 方式二
SELECT ename,emp.deptno,emp.job FROM emp,(SELECT deptno,job FROM emp WHERE ename = 'SMITH') temp WHERE ename != 'SMITH' AND emp.job = temp.job AND emp.deptno = temp.deptno; 

4.子查询当作临时表使用

-- 查询ecshop中各个类别中价格最高的商品
-- 先得到,各个类别中价格最高的商品
SELECT cat_id,MAX(shop_price) FROM ecs_goods GROUP BY cat_id;
-- 再将得到的结果当作为临时表使用,在真正的表中对比得到结果
-- 为了发表处理,给临时表取个别名
SELECT goods_id,ecs_goods.cat_id,goods_name,shop_price FROM (SELECT cat_id,MAX(shop_price) AS max_price FROM ecs_goods GROUP BY cat_id) temp,ecs_goods WHERE temp.cat_id = ecs_goods.cat_id AND temp.max_price = ecs_goods.shop_price;

十一、 ALL 、 ANY、IN 、ENUM(枚举)关键字的使用

  • "ALL" 和 "ANY" 一般用在比较大小的语句中
  • "IN" 一般用在比较相等的语句中,表示存在

1.ALL

-- 查询比部门30所有员工工资高的员工的姓名、工资、部门
# ALL 代表所有的
SELECT ename,sal,deptno FROM emp WHERE sal > ALL(SELECT sal FROM emp WHERE deptno = 30);
SELECT ename,sal,deptno FROM emp WHERE sal > (SELECT MAX(sal) FROM emp WHERE deptno = 30);

2.ANY

-- 查询比部门30其中一个员工工资高的员工的姓名、工资、部门
# ANY 代表其中一个
SELECT ename,sal,deptno FROM emp WHERE sal > ANY(SELECT sal FROM emp WHERE deptno = 30);
SELECT ename,sal,deptno FROM emp WHERE sal > (SELECT MIN(sal)FROM emp WHERE deptno = 30);

3.IN

-- 查询与部门30其中一个员工工资相同的员工的姓名、工资、部门
# IN 代表在其中,一般用在相等对比语句中
SELECT ename,sal,deptno FROM emp WHERE sal = IN(SELECT sal FROM emp WHERE deptno = 30);

4.ENUM(枚举)

CREATE TABLE hsp_db (id INT,`name` VARCHAR,sex ENUM('男','女'));

十二、表的自我复制和去重

1.表的自我复制(蠕虫复制)

  • 查询一个表,将查询到的数据,插入到本表

    INSERT INTO my_tab01 (id,`name`,job,denptno,sal) (SELECT id,`name`,job,denptno,sal FROM my_tab01);
    
  • 一般用创建海量数据表,

2.表的去重

  • 思路:
  1. 先创建一个结构相同的临时表 my_tab
  2. 把要去重的表 my_tab02 通过distinct 关键字处理后,插入到临时的表 my_tab
  3. 清除 my_tab02 的记录
  4. 将 临时表 my_tab 插入到 my_tab02
  5. 最后删除 临时表 my_tab
# 先创建一个结构相同的临时表 my_tab
CREATE TABLE my_tab LIKE my_tab02;
# 把要去重的表 my_tab02 通过distinct 关键字处理后,插入到临时的表 my_tab
INSERT INTO my_tab (id,`name`,job,denptno,sal) (SELECT DISTINCT id,`name`,job,denptno,sal FROM my_tab02);
# 清除 my_tab02 的记录
DELETE FROM my_tab02;
# 将 临时表 my_tab 插入到 my_tab02
INSERT INTO my_tab02 (id,`name`,job,denptno,sal) (SELECT id,`name`,job,denptno,sal FROM my_tab);
# 最后删除 临时表 my_tab
DROP TABLE my_tab;

十三、合并查询

1. 不去重合并 (UNION ALL)

# "UNION ALL" 合并所有行,不会去掉重复行
SELECT ename,job,sal FROM emp WHERE sal > 2500 UNION ALL SELECT ename,job,sal FROM emp WHERE job = 'MANAGER';

2.去重合并 (UNION)

# "UNION" 合并会去掉重复行
SELECT ename,job,sal FROM emp WHERE sal > 2500 UNION SELECT ename,job,sal FROM emp WHERE job = 'MANAGER';

十四、外连接

  • 多数情况使用的是前面学内连接,少数情况属于外连接

1.左外连接

  • 左外连接,左表所有行都显示,右表没有匹配的显示为null
  • 语法: SELECT 字段 FROM 表1 LEFT JOIN 表2 ON 判断条件
# 左外连接,左表所有行都显示,右表没有匹配的显示为null
# 语法:SELECT 字段 FROM 表1 LEFT JOIN 表2 ON 判断条件
-- 显示id,姓名,成绩
SELECT `name`,stu.id,sorce FROM stu LEFT JOIN grder ON stu.id = grder.id;

2.右连接

  • 右外连接,右表所有行都显示,左表没有匹配的显示为null
  • 语法: SELECT 字段 FROM 表1 RIGHT JOIN 表2 ON 判断条件
# 右外连接,右表所有行都显示,左表没有匹配的显示为null
# 语法:SELECT 字段 FROM 表1 RIGHT JOIN 表2 ON 判断条件
-- 显示id,姓名,成绩
SELECT `name`,stu.id,sorce FROM stu RIGHT JOIN grder ON stu.id = grder.id;

十五、MySQL数据约束

  • 五种约束:not null,unique,primary key,foreign key,check

1.主键(primary key)

  • 语法: 字段名 字段类型 primary key,也可以在表定义最后使用: primary key (字段1,字段2,...)

  • 使用主键约束的字段不能重复,也不能为null

  • 一张表最多只能有一个主键,但可以是复合主键(比如: id + name)

CREATE TABLE t17 (id INT PRIMARY KEY,`name` VARCHAR(32),email VARCHAR(32));-- id 使用主键约束
CREATE TABLE t18 (id INT,`name` VARCHAR(32),email VARCHAR(32),PRIMARY KEY (id,`name`));-- id + name 使用复合主键约束

2.非空约束(not null)

# 非空约束,not null,被约束的字段不能为null
CREATE TABLE t19 (id INT NOT NULL DEFAULT '');

3.唯一约束(unique)

  • 使用后不能出现重复,如果没有指定非空,则可以出现多个null
  • 一张表可以有多个unique
CREATE TABLE t20 (id INT UNIQUE NOT NULL);

4.外键约束(foreign key)

  • 语法: foreign key (从表字段名) references 主表名(主键字段名 或者 unique字段名)

  • 要带括号,不然会报错

  • 用于定义主表的从表之间的关系,外键约束要定义在从表上,

  • 主表必须具有主键约束或unique约束,外键数据在主表上存在或者为null

  • 形成外键关系的主表的数据不能随意删除,需要从表没有字段指向时才能删除

  • 主表的类型要求是innodb,这样的表才支持外键

  • 一张表可以存在多个外键

CREATE TABLE class (id INT PRIMARY KEY,`name` VARCHAR(32),address VARCHAR(32));-- 主表
CREATE TABLE stu (id INT,`name` VARCHAR(32),class_id INT,FOREIGN KEY (class_id) REFERENCES class(id));-- 从表
-- 删除外键
ALTER TABLE sc DROP FOREIGN KEY sno;-- sc是表名,sno是外键的名称

5.条件约束 (check)

  • 语法: CHECK (约束条件);
  • 加在需要约束的字段后
  • mysql5.7目前还不支持check,只做语法的校验,不会真的生效
  • oracle,sql server,这两个数据库是会生效的
CREATE TABLE t23(id INT,`name` VARCHAR(32),sex VARCHAR(6) CHECK (sex IN('man','woman')),sal INT CHECK (sal > 1000 AND sal < 3000) );-- 性别限制为男女,工资限制为1000~3000

十六、自增长(auto_increment)

  • 语法: 字段名 整型 auto_increment;
  • 一般自增长配合主键使用,也可以配合unique使用
  • 当添加数据时,自增长的字段为null或者没有写时,启动自增长
  • 默认从1开始增长
  • 当指定数字时,以指定的数字为准,下个以最大的数字开始增长
  • 修改自增长开始值为100,alter table t23 auto_increment = 100
  • 修改自增长开始值语法: alter table 表名 auto_increment = 开始值
# 自增长
# 语法: 字段名 整型 auto_increment;
# 一般自增长配合主键使用,也可以配合unique使用
# 当添加数据时,自增长的字段为null或者没有写时,启动自增长
# 默认从1开始增长
# 当指定数字时,以指定的数字为准,下个以最大的数字开始增长
# 修改自增长开始值为100,alter	table t23 auto_increment = 100
# 修改自增长开始值语法: alter	table 表名 auto_increment = 开始值
CREATE TABLE t23(id INT PRIMARY KEY AUTO_INCREMENT,
								email VARCHAR(32),
								`name` VARCHAR(32));-- 创建id自增长的表
# 添加数据的方式
INSERT INTO t23 (id,`name`,email) VALUES(NULL,'jack','jack.com');-- 自增长的字段填null
INSERT INTO t23 (`name`,email) VALUES('jack','jack.com');-- 省略自增长的字段
INSERT INTO t23 (id,`name`,email) VALUES(5,'jack','jack.com');-- 指定数字

十七、MySQL索引

  • 索引不提高占用内存,但提高占用磁盘空间

- 索引能提高查询(select)速度,但会影响数据的更新(update)、删除(delete)和插入(insert)的效率

  • 删除索引语法: drop 索引名称 on 表名

1.索引类型

  • 主键索引(primary key),主键同时也是索引
  • 唯一索引(unique),
  • 普通索引(index)
  • 全文索引(fulltext)[适用于MyISAM数据引擎]

3.创建索引

  • 创建索引语法一: create 索引类型 创建索引的名称 on 表名 (要创建索引的字段名)
  • 创建索引语法二: alter table 表名 add 索引类型 创建索引的名称 (要创建索引的字段名)
# 创建索引语法一: create 索引类型 创建索引的名称 on 表名 (要创建索引的字段名)
# 创建索引语法二: alter table 表名 add 索引类型 创建索引的名称 (要创建索引的字段名)
CREATE TABLE t25(id INT,`name` VARCHAR(32));
# 创建索引
CREATE UNIQUE INDEX id_index ON t25 (id);-- 添加唯一索引
CREATE INDEX id_index ON t25 (id);-- 添加普通索引
ALTER TABLE t25 ADD INDEX id_index (id); -- 添加普通索引

4.删除索引

# 删除索引
# 语法: drop 索引名称 on 表名
DROP id_index ON t25;
-- 删除主键索引
ALTER TABLE t25 DROP PRIMARY KEY;

5.修改索引

  • 修改思路:先删除,再创建一个新的索引

6.查看索引的四种方式

#查看索引的四种方式
SHOW INDEX FROM t25;
SHOW INDEXES FROM t25;
SHOW KEYS FROM t25;
DESC t25;

7.创建索引的一般规则

  1. 频繁查询的字段应该创建索引
  2. 唯一性太差的字段不适合创建索引(例如性别)
  3. 更新频繁的字段不适合创建索引
  4. 不会作为查询条件的字段不应该创建索引

十八、MySQL的事务机制

  • MySQL的事务机制需要innodb类型的存储引擎,其他的存储引擎不支持事务机制
  • 事务用于保证数据的一致性,由一组dml语句组成,该组语句要么全部成功,要么全部失败
  • dml语句就是,insert、updata、delete操作
  • 当执行事务操作时,mysql会在表上加锁

1.事务的基本操作

  1. 开始事务语法: start transaction,set auto_commit=off
-- 开始事务
START TRANSACTION;
SET AUTOCOMMIT=off;
  1. 保存点语法: savepoint 保存的点名
-- ,添加数据,并设置保存点a
INSERT INTO t27(id,`name`) VALUES(100,'jk');
SAVEPOINT a;
-- 设置保存点b
INSERT INTO t27 VALUES(300,'kl');
SAVEPOINT b;
  1. 会退事务语法:rollback to 要回退到的点名;rollback(不带"to"表示回退全部事务,回到事务开始的状态)
-- 回退到b点
ROLLBACK b;
-- 回退到a点,可以直接回退到a点,但就不能再回退到b点了
ROLLBACK a;
-- 回退到事务开始状态
ROLLBACK;
  1. 提交事务
-- 提交事务
COMMIT;
#不开启事务,dml语句默认自动提交,就不能回退

2.事务隔离级别

  • 当多个连接使用事务操作数据库时,数据库系统负责隔离操作,保证数据的正确性

脏读:当一个事务读取到另一个事务未提交的修改时,就说明产生了脏读

不可重复读:同一个查询在同一事务多次进行,由于其他提交事务做的修改或删除,每次返回不同的结果集,此时就发生了不可重复读

幻读:同一个查询在同一事务多次进行,由于其他提交事务做的插入,每次返回不同的结果集,此时就发生了幻读

1.四种隔离级别

  • 读未提交(Read uncommitted)
  • 读已提交(Read committed)
  • 可重复读(Repeatable read)
  • 可串型化(Serializable)
# 查看当前MySQL的隔离级别
SELECT @@tx_isolation;
# 查看系统的隔离级别
SELECT @@global.tx_isolation;
# 设置隔离级别
# 语法:SET SESSION TRANSACTION ISOLATION LEVEL 隔离级别的类型;
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
# 设置系统隔离级别
# 语法:SET GLOBAL TRANSACTION ISOLATION LEVEL 隔离级别的类型;
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
  • 还可以在配置文件设置系统默认隔离级别

3.事务的特性

  • 原子性:事务是一个不可分割的工作单位,事务中的操作要么全部发生,要么全都不发生
  • 一致性:事务必须使数据库从一个一致性转换的另一个一致性
  • 隔离型:多个用户并发访问数据库时,数据库为每一个用户开启事务,不能被其他用户的操作数据干扰,多个并发事务之间要相互隔离
  • 持久性:事务一旦提交,对数据库的影响是永久性的

十九、MySQL的表类型和存储引擎(Storage Engines)

  • MySQL的表类型由存储引擎决定,MySQL常用三种:INNODB、MYISAM、Memory
  • MySQL支持六种类型:CSV、Memory、ARCHIVE、MRG_MYISAM、MYISAM、INNODB
  • 事务安全型:INNODB
  • 非事务安全型:CSV、Memory、ARCHIVE、MRG_MYISAM、MYISAM
#查看所有的存储引擎
SHOW ENGINES;
# INNODB 存储引擎
-- 1.支持事务2.支持外键3.支持行级锁
# MyISAM 存储引擎
-- 1.添加数独快2.不支持事务和外键3.支持表级锁
# MEMORY 存储引擎
-- 重启MySQL时数据会丢失
-- 1.数据存储在内存中2.执行速度快(没有IO读写)3.默认支持哈希索引

# 修改存储引擎
# 语法:ALTER TABLE 表名 ENGINE = 存储引擎类型;
ALTER TABLE t25 ENGINE = INNODB;

二十、MySQL视图

  • 通过视图查询数据可以隐藏隐私数据,只允许查询指定的字段

  • 视图是根据基表(可以有多个基表)创建的

  • 视图是虚拟的表,只是一个结构,没有数据,只映射基表的数据

  • 通过视图可以修改基表的数据

  • 基表的改变也会影响到视图的数据

# 创建视图
# 语法: CREATE VIEW 视图名称 AS SELECT语句(相当于子查询)
CREATE VIEW my_view AS SELECT id,`name` FROM emp;
# 修改视图
# 语法: ALTER VIEW 视图的名称 AS SELECT语句(相当于子查询);
ALTER VIEW my_view AS SELECT `name`,sal FROM emp;
# 显示创建视图的信息
# 语法:SHOW CREATE VIEW 视图名称;
SHOW CREATE VIEW my_view;
# 删除视图
# 语法:DROP VIEW 视图名称;
DROP VIEW my_view;
# 查看视图结构
# 语法:DESC 视图名称
DESC my_view;
# 查询所有视图
show table status where comment='view';
select * from information_schema.views;

二十一、存储过程和存储函数

  • 存储过程可以没有返回,存储函数必须有返回
  • 存储过程的关键字是procedure,存储过程的关键字是function
  • 存储过程有三种参数,in,out,inout
  • in表示传入的参数,out表示返回的参数,inout表示即可当传入的参数也可当返回的参数
  • 使用call关键字调用存储过程,存储过程不能在查询语句中调用
# 创建存储过程的语法
create procedure 存储过程的名称(in 参数的名称 参数的数据类型 ...,out 参数的名称 参数的数据类型 ... ,inout 参数的名称 参数的数据类型)
begin
	语句...
end;
# 创建存储过程
CREATE PROCEDURE proc_info (IN id VARCHAR(10))
-- 传入一个学号,查询相关的信息
BEGIN
	SELECT sname,ssex,saddress FROM student WHERE sno = id;
END
# 调用存储过程
CALL proc_info('2007010109');
-- 显示所有存储过程
SHOW PROCEDURE STATUS;
# 删除存储过程
DROP PROCEDURE 存储过程名;
  • 存储函数只能且必须有一个返回值,存储过程可以多个返回值
  • 存储过程一般用于更新数据,存储函数一般由于查询
# 创建存储函数的语法
create function 函数名称 ([参数列表]) return 数据类型 -- 指明返回的数据类型
begin
	语句...
end;

# 创建存储函数
CREATE FUNCTION func_saddress(id VARCHAR(10)) -- 参与一个参数
RETURNS VARCHAR(32) -- 返回一个varchar(32)类型的数据
BEGIN
	DECLARE result VARCHAR(32); -- 声明了一个varchar(32)类型的变量
	SELECT saddress INTO result FROM student WHERE sno = id; -- 将查询到的值赋给了变量result
	RETURN result;-- 最后将变量result返回
END

# 调用存储函数
SELECT func_saddress('2007010115');

# 删除存储函数
drop function 函数名;

二十二、触发器

  • 当表的数据发生改变(插入|更新|删除)时,就会触发触发器
  • 触发器的关键字是trigger
  • afterbefore表示触发时机,after表示数据发生改变后进行触发器里的操作,before表示数据发生改变前进行触发器里的操作
  • insertupdatedelete表示触发的条件,instert表示发生插入操作时触发的触发器,update表示发生更新操作时触发的触发器,delete表示发生删除操作时触发的触发器
  • for each row表示是行级触发器,每一行数据发生改变就触发一次,mysql5.7只支持行级触发器
  • 在触发器中有两个特殊的行newold,new表示插入的新数据行,old表示被覆盖或删除的数据行
  • 在插入触发器器中只有new行,没有old行,使用old行会报错
  • 在更新触发器中,new行和old行都可以使用
  • 在删除触发器中只有old
# 创建触发器的语法
create	trigger 触发器的名称 after|before insert|update|delete on 数据表 for each row
begin
	语句...
end

# 创建一个删除触发器
CREATE TRIGGER sc_delete AFTER DELETE ON student FOR EACH ROW
BEGIN
	DELETE FROM sc WHERE sc.sno = old.sno; 
END;

# 查看当前数据库中的触发器
show triggers;

# 删除触发器
drop trigger [数据名] sc_delete;-- 也可以不带数据库名,默认删除当前数据库的触发器

二十三、MySQL用户管理

  • host:允许登陆的"位置",localhost表示只允许本地登陆,也可以指定IP地址和IP网段

  • user:用户名

  • autherntication_string:密码,通过PASSWORD加密后的密码

  • 查看系统的所有用户

SELECT * FROM mysql.user;

1.创建用户

  • 语法:CREATE USER '用户名'@'可以登陆的地址' IDENTIFIED BY '设置的密码';
  • 创建用户时,没有指定host,则为"%","%" 表示该用户在所有IP都可以登陆,表示创建了一个'xxx'@'%'用户
  • 也可以指定IP段,'xxx'@'192.168.1.%',表示可以在"192.168.1.*"网段登陆
CREATE USER 'Jack';-- 不带密码,默认没有密码
CREATE USER 'yangyi'@'localhost' IDENTIFIED BY '123';

2.修改密码

# 语法:SET PASSWORD = PASSWORD('修改后的密码')
SET PASSWORD = PASSWORD('123456')
# 修改其他用户的密码
# 语法:SET PASSWORD FOR '用户名'@'可以登陆的地址' = PASSWORD('修改后的密码');
SET PASSWORD FOR 'yangyi'@'lacalhost' = PASSWORD('123456');
update user set password=password('new password') where user='root';
# mysql8.0修改密码
alter user 'root'@'localhost' identified with mysql_native_password by 'password';

3.授予权限

  • 语法:GRANT 权限列表 ON 库.对象名 TO '用户名'@'登陆位置' IDENTIFIED BY '密码' WITH GRANT OPTION
  • "IDENTIFIED BY" 可以省略,如果没有省略,当用户存在时修改它的密码同时授予权限,不存在时创建该用户同时授予权限
  • WITH GRANT OPTION:表示被授予权限的用户可以授予其他用户该权限

# 语法:GRANT 权限列表 ON 库.对象名 TO '用户名'@'登陆位置' IDENTIFIED BY '密码'
# "*.*" 代表本系统中的所有数据库的所有对象
# "库.*" 代表某个数据库的所有对象
# "IDENTIFIED BY" 可以省略,如果没有省略,当用户存在时修改它的密码同时授予权限,不存在时创建该用户同时授予权限
GRANT ALL ON hsp_db02 TO 'yangyi'@'localhoat' IDENTIFIED BY '123456';

4.撤销权限

  • 语法:REVOKE 权限列表 ON 库.对象名 FROM '用户名'@'登陆地址';

# 撤销授权
# 语法:REVOKE 权限列表 ON 库.对象名 FROM '用户名'@'登陆地址';
REVOKE ALL ON hsp_db02 FROM 'yangyi'@'localhost';

#撤销所有用户的查询权限
REVOKE SELECT ON TABLE test FROM PUBLIC;
# 权限生效指令
# 如果修改权限没有生效时使用
FLUSH PRIVILEGES;
flush privileges;

5.删除用户

  • 语法:语法:DROP USER '用户名'@'可以登陆的地址';
# 删除用户
# 语法:DROP USER '用户名'@'可以登陆的地址';
# 删除用户时,如果host不是"%",则需要指明host
DROP USER 'jack';
DROP USER 'yangyi'@'localhost';

6.常见的权限