B站MySQL(尚硅谷)学习笔记
B站MySQL基础(尚硅谷)学习笔记
最近在学习数据库技术,并且把视频中的知识点进行了汇总,字数较多,仅供参考。
会持续更新
欢迎读者提出问题与错误,一起交流~
视频前几集所讲述的基本知识:
DB:数据库,保存一组有组织的数据的容器。
DBMS:数据库管理系统:又称为数据库软件(产品),用于管理DB中的数据。
SQL:结构化查询语言,用于和DBMS通信的语言。
将数据先放到表里面,再把表放到库里。
一个数据库中可以有多张表,每个表都有一个的名字,用来标识自己,表名具有唯一性。
表具有一些特性,这些特性定义了数据在表中如何存储,类似java中类的设计。
表由列组成,我们也称为字段,所有表都是由一个或者多个列组成的,每一个列类似于Java中的属性。
MySQL不区分大小写,但建议关键字大写,表名,列名小写。
每条命令最好用分号结尾。
每条命令根据需要,可以进行缩进和换行。
注释:单行注释: # 注释文字 单行注释: – 注释文字 多行注释: /* 645465 */
DQL语言的学习(数据查询语言)(针对于查询(select))
DML语言的学习(数据操作语言)(针对于增删改)
DDL语言的学习(数据定义语言)(针对库和表的定义,创建删除等)
TCL语言的学习(事物控制语言)
DQL学习
进阶一:基础查询
select 查询列表 from 表名;
类似于: System.out.println(‘’打印的东西‘’);
特点:查询列表可以是:表中的字段、常量值、表达式、函数。查询的结果是一个虚拟的表格。
1.查询表中的单个字段
SELECT last_name FROM employees;
2.查询表中的多个字段
SELECT last_name,salary,email FROM employees;
3.查询表中的所有字段
SELECT * FROM employees;
4.查询常量值
SELECT 100;
SELECT 'john';
5.查询表达式
SELECT 100*98;
SELECT 100%98;
6.查询函数
SELECT VERSION();
7.起别名
1.便于理解。
2.如果要查询的字段有重名的情况,使用别名可以区分开来
方式一
SELECT 100%98 AS 结果;
SELECT last_name AS 姓,first_name AS 名 FROM employees;
方式二
SELECT last_name 姓, first_name 名 FROM employees;
案例:查询salary ,显示结果是 out put。
SELECT salary AS "OUT put" FROM employees;
8.去重
里面只可以放一个
案例 :查询员工表中涉及到的所有部门编号
SELECT DISTINCT department_id FROM employees;
9.+号的作用
java中的+号作用:
1.运算符(数值型)
2.连接符,只要有一个操作数为字符串。
mysql中的+号只有一个功能:运算符
select 100+90;
两个操作数都是数值型,则做加法
select '123'+90;
(为90)
其中一方为字符型,试图将字符型数值转换为数值型
如果转换成功,就继续左加法运算。如果转换失败,则将字符型数值转换成0
select null+10;
为null
案例:查询员工名和姓链接成一个字段,并显示为姓名
SELECT CONCAT(last_name,first_name) AS 姓名 FROMemployees;
10.` 的作用
着重号,用于区分NAME(关键字)和NAME(表内容)的区别。
建议还是不要使用 ,当需要命名name时,可以将name前面加上一些别的字母,用来于关键字区别。
如:s_name,t_name 等。
进阶二:条件查询
语法:
select 查询列表
from表名
where筛选条件;
分类:
一、按条件表达式筛选
条件运算符: > < =(等于) <>(不等) >= <=
案例一:查询工资大于12000的员工。
SELECT * FROM employees WHERE salary>12000 ;
案例二:查询部门编号不等于90号的员工名和部门编号。
SELECT last_name , department_id
FROM employees
WHEREdepartment_id<>90;# 或者 department_id!=90
二、按逻辑表达式筛选
作用:用于连接条件表达式
逻辑运算符 : && || !
推荐:and or not
案例一:查询工资在10000-20000之间的员工名、工资以及奖金。
SELECT last_name,salary,commission_pctFROM employees WHERE salary>=10000&&salary<=20000;#或者用and
案例二:查询部门编号不是在90-110之间,或者工资大于15000的员工信息。
SELECT * FROM employees WHERE department_id > 110 or department_id< 90 OR salary>15000;
或者:
SELECT *
FROM employees
WHERE NOT(department_id>=90 AND department_id<=110) OR salary>15000;
三、模糊查询
like、between and、in、is null
like
特点:一般和通配符搭配使用
通配符:
% 任意多个字符(包含零个)
_ 任一单个字符
案例一:查询员工名中包含字符a的员工信息。
SELECT * FROM employees WHERE last_name LIKE '%a%' ;
案例二:查询员工中第三个字符为e,第五个字符为a的员工名和工资。
SELECT last_name,salary
FROMemployees
WHERElast_name LIKE '___e_a%';
案例三:查询员工名中第二个字符为下划线的员工名。
SELECT last_name
FROMemployees
WHERElast_name LIKE '_\_%';
between and
使用between and可以提高语句的简洁度,包含两个临界值,两个临界值不要颠倒顺序。
案例一:查询员工编号在100-120之间的员工信息。
SELECT *
FROMemployees
WHEREemployee_id BETWEEN 100 AND 120;
in
含义:判断某字段的值是否属于in列表中的某一项。
特点:1.使用in提高语句简洁度。
2.in列表的值类型必须统一或者兼容。
案例一:查询员工的工种编号是IT_RPOG、AD_VP、AD_PRES中的一个员工名和工种编号
SELECT last_name,job_id
FROMemployees
WHEREjob_id IN ('IT_RPOG','AD_VP','AD_PRES');
is null
案例一:查询到没有奖金的员工和奖金率。
SELECTlast_name,commission_pct
FROMemployees
WHEREcommission_pct IS NOT NULL;
<=>
安全等于:相当于是否等于
案例一:
SELECTlast_name,commission_pct
FROMemployees
WHEREcommission_pct <=>NULL;
前几节课总结
数据库相关概念
一、数据库的好处
1.可以持久化数据到本地。
2.结构化查询。
二、数据库的常见概念
1.DB:数据库。
2.DBMS:数据库管理系统,又称为数据库软件或者数据库产品,用于创建或者管理DB。
3.SQL:结构化查询语言,用于和数据库通信的语言,不是某个软件所特有的,是都用这个。
三、数据库存储数据的特点
1.数据存放到表中,然后表再放到库中。
2.一个库中可以有多张表,每张表具有唯一的表名来标识自己。
3.表中有一个或者多个列,列又称为字段,相当于Java中的属性。
4.表中的每一个数据,相当于Java中的对象 。
四、常见的数据库管理系统
MySQL oracle db2 sqlserver
进阶三:排序查询
语法:
SELECT 查询列表
FROM表
【WHERE 筛选条件】
ORDER BY 排序列表 【asc|desc】
ASC从低到高(不填默认为升序) desc从高到低
ORDER BY 子句中可以支持单个字段、多个字段、表达式、函数、别名
ORDER BY 子句一般放在查询语句的最后面,除了limit子句。
注:【】表示可以有也可以无
案例一:查询员工信息。要求工资从高到低排序、从低到高。
SELECT *
FROM employees
ORDER BY salary DESC;SELECT *
FROM employees
ORDER BY salary ;
案例二:查询部门编号>=90的员工信息,按入职时间的先后顺序进行排序。
SELECT *
FROM employees
WHERE department_id>=90
ORDER BY hiredate ASC;
案例三:【按表达式排序】 按年薪的高低显示员工的信息和年薪。
SELECT * ,salary*12*(1+IFNULL(commission_pct,0)) #年薪
FROM employees
ORDER BY salary*12*(1+IFNULL(commission_pct,0)) DESC;
#利用别名更好
ORDER BY 年薪 DESC;
案例四:按姓名的长度显示员工的姓名和工资【按函数排序】。
SELECTLENGTH(last_name) 字节长度,last_name,salary
FROM employees
ORDER BY LENGTH(last_name) DESC;
案例五:查询员工信息,要求先按工资升序,再按员工编号降序【按多个字段排序】。
SELECT *
FROM employees
ORDER BY salary ASC,employee_id DESC;
进阶四:函数
功能:类似于Java的方法,将一组逻辑语句封装在方法中,对外暴露方法名。
好处:
1.隐藏了实现细节 。
2.提高代码的重用性 。
调用:
SELECT 函数名(实参列表) 【FROM 表】;
特点:1.函数名 2.函数功能
分类:
1.单行函数 如:CONCAT length IFNULL
2.分组函数:又称为统计函数,聚合函数,组函数 用于统计使用
1.字符函数
length:获取子节个数
SELECT LENGTH('jack');
SELECT LENGTH('哈哈哈');# 一个汉字是三个子节
concat:拼接字符串
SELECT CONCAT(last_name,'_',first_name)
FROM employees;
upper、lower: 大小写转换
SELECT UPPER('ohhh');SELECT LOWER('DADASDA');
实例:将姓变成大写,名变成小写
SELECTCONCAT(UPPER(last_name),LOWER(first_name)) 姓名
FROM employees;
SUBSTR、 SUBSTRING: 字符串裁剪
注意:索引是从1开始的
案例:截取从指定索引处后面的所有字符
SELECT SUBSTR('李莫愁爱上了路展元',7) out_put;#输出路展元
案例:截取从指定索引处指定字符长度的字符
SELECT SUBSTR('李莫愁爱上了路展元',1,3) out_put;#输出李莫愁
案例:姓名中首字符大写,其他字符小写然后用_拼接,显示出来
SELECTCONCAT(UPPER(SUBSTR(last_name,1,1)),'_',LOWER(SUBSTR(last_name,2))) out_put
FROM employees;
INSTR: 返回子串第一次出现的索引,如果找不到返回0
SELECT INSTR('杨不悔爱上了印巴下','印巴下') AS out_put;
trim :去掉前后的空格或者指定的字符
SELECT LENGTH(TRIM(' 张翠山 ')) AS out_put;
SELECT TRIM('a' FROM'aaaaaaaaa大aaa旭aaaaa') AS out_put;
lpad: 用指定的字符实现左填充指定长度
SELECT LPAD('畅',5,'#');
rpad: 右填充
SELECT RPAD('畅',5,'@');
replace :替换
SELECT REPLACE('Java畅学Java','Java','SQL');
2.数学函数
round:四舍五入
SELECT ROUND(1.55);#1.6
SELECT ROUND(1.567,2);#1.57
ceil :向上取整
返回>=该参数的最小整数
SELECT CEIL(1.02);#2
floor: 向下取整
SELECT FLOOR(5.01);#5
truncate:截断
SELECT TRUNCATE(1.66,1);# 1.6
mod:取余
mod(a,b)相当于a-a/b×b
SELECT MOD(10,3);
3.日期函数
now 返回当前系统日期+时间
SELECT NOW();
可以获取指定的部分,年月日小时分钟秒
SELECT YEAR(NOW()) 年;
SELECT YEAR('2001-05-03') 年;
curdate 返回日期不含时间
SELECT CURDATE();
curtime 返回时间不返回日期
SELECT CURTIME();
str_to_date 将字符通过指定格式转换成日期
SELECT STR_TO_DATE('1998-3-2','%Y-%c-%d')AS out_put;
4.流程控制函数
1.if函数:
if else效果
SELECT IF(10>4,'大','小');
SELECT last_name,commission_pct,IF(commission_pct IS NULL,'呜呜','哈哈') FROM employees;
2.case函数:
1 :与switch case 一样的效果
case 要判断的字段或表达式when 常量1 then 要显示的值或者语句1when 常量1 then 要显示的值或者语句2 ....else 要显示的值或者语句n;end
2:类似于多重if
casewhen 条件一 then 要显示的值或者语句when 条件二 then 要显示的值或者语句...else 要显示的值或者语句end
案例: 显示不同编号的不同工资
SELECT salary 原始工资, department_id,case department_idwhen 30 then salary*1.1when 40 THEN salary*1.2WHEN 50 THEN salary*1.3ELSE salaryEND AS 新工资FROM employees;
案例二 :查询员工工资情况, 如果大于20000显示a级别 大于15000显示b级别 大于10000显示c级别 否则显示d级别
SELECT salary 工资,CASE WHEN salary>20000 then 'a'WHEN salary>15000 THEN 'b'when salary>10000 THEN 'c'ELSE 'd'ENDFROM employees;
5. 分组函数
分类:sum求和,avg平均,max,min,count(计算个数)
USE myemployees;SELECT SUM(salary) 和 FROM employees;SELECT AVG(salary) 平均 FROM employees;SELECT MAX(salary) 最大 FROM employees;SELECT MIN(salary) 最小 FROM employees;SELECT COUNT(salary) 总计 FROM employees;
参数支持哪些类型
SELECT SUM(last_name), AVG(last_name) FROM employees;# sum和avg不支持字符/日期
忽略null
和distinct搭配
SELECT SUM(DISTINCT salary), SUM(salary) FROM employees;
SELECT COUNT(DISTINCT salary),COUNT(salary) FROM employees;
count 函数详细介绍
SELECT COUNT(*) FROM employees; # 显示行数
SELECT COUNT(1) FROM employees; # 显示行数 多加一列常量值,用来统计个数
效率
MYISAM 存储引擎下,count(*) 的效率最高
INNODB存储引擎下, count(*) 和 count(1)的效率差不多 ,比count(字段)效率高
进阶五:分组查询
语法: SELECT 分组函数,列(要求出现在group by的 后面)from 表【WHERE 筛选条件】GROUP BY 分组的列表【order by 子句】
查询列表比较特殊:要求是分组函数和group by后出现的字段
特点:
1.分组查询中的筛选条件分为两类
数据源 | 位置 | 关键字 |
---|---|---|
分组前筛选 | 原始表 | group by 前面 WHERE |
分组后筛选 | 分组后的结果集 | group by后面 having |
分组函数做条件肯定放在having子句中
能用分组前筛选的,就优先使用
2.GROUP BY 子句支持单个字段分组,也支持多个字段分组(多个字段)
3.也可以添加排序(排序放在整个分组查询的最后)
案例:查询每个工种的最高工资
SELECT MAX(salary),job_id
FROM employeesGROUP BY job_id;
案例:查询每个位置上的部门个数
SELECT COUNT(*), location_idFROM departmentsGROUP BY location_id;
添加筛选条件
案例1:查询邮箱中包含字符a的,每个部门的平均工资
SELECT AVG(salary),department_idFROM employeesWHERE email like '%a%'GROUP BYdepartment_id;
案例2:查询有奖金的每个领导手下员工的最高工资
SELECT MAX(salary),manager_id FROM employeesWHERE commission_pct is NOT NULLGROUP BY manager_id;
添加复杂的筛选条件
案例1:查询哪个部门的员工个数>2
#拆分为两步:
1.查询每个部们的员工个数
2.根据1的去筛选哪个部门的员工个数>2
SELECT count(*),department_idFROM employeesGROUP BY department_id HAVING count(*)>2;
案例2:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
SELECTMAX(salary),job_idFROM employeesWHERE commission_pct is NOT NULLGROUP BYjob_idHAVING MAX(salary)>12000;
案例3:查询领导编号大于102的每个领导手下的最低工资>5000的领导编号是哪个
SELECT MIN(salary),manager_idFROM employeesWHERE manager_id>102GROUP BY manager_idHAVING MIN(salary)>5000;
按表达式(函数)分组
案例:按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的有哪写
1.查询每个长度的员工个数
SELECT COUNT(*),LENGTH(last_name) len_nameFROM employeesGROUP BY LENGTH(last_name);
2.添加筛选条件
SELECT COUNT(*),LENGTH(last_name) len_nameFROM employeesGROUP BY LENGTH(last_name)HAVING COUNT(*)>5;
按多个字段分组
案例:查询每个部门每个工种的员工的平均工资
SELECT AVG(salary),department_id,job_idFROM employeesGROUP BY department_id,job_id;
添加排序
案例:查询每个部门每个工种的员工的平均工资 ,并且按平均工资的高低显示
SELECT AVG(salary),department_id,job_idFROM employeesGROUP BY department_id,job_idORDER BY AVG(salary) DESC;
进阶六:连接查询
又称为多表查询,当查询的字段来自于多个表时,就会用到连接查询。
笛卡尔乘积现象:表1 有m行 表2有n行 ,结果有m*n行
发生原因:没有有效的连接条件
如何避免:添加有效的连接条件
分类:
按年代分类:
sq192标准:仅仅支持内连接
sq199标准:【推荐】 就不支持全外连接
按功能分类:
内连接:等值连接、非等值连接、自连接
外连接:左外连接、右外连接、全外连接、交叉连接
1.sql92标准
等值连接
1.等值连接的结果为多表的交集部分。
2.n表连接至少需要n-1个连接条件。
案例一:查询女神名和对应的男神名
SELECTNAME,boyName
FROM boys,beauty
WHERE beauty.boyfriend_id =boys.id;
案例二:查询员工名和对应的部门名
SELECT last_name, department_nameFROM employees,departmentsWHERE employees.department_id=departments.department_id;
为表起别名
提高语句的简洁度,区别多个重名字段 (如果为表起了别名,查询时就不可以再用以前的表名了)
查询员工名,工种号,工种名
SELECT last_name,e.job_id,job_titleFROMemployees e ,jobs jWHERE e.job_id =j.job_id;
可以加筛选
案例:查询有奖金的员工名和部门名
SELECT last_name,department_name,e.commission_pctFROM employees e,departments dWHERE e.department_id=d.department_idAND e.commission_pct is NOT NULL;
案例2:查询城市名中第二个字符为‘o’的部门名和城市名
SELECT department_name,cityFROM departments d,locations lWHERE d.location_id=l.location_idAND city LIKE '_o%';
可以加分组
案例1.查询每个城市的部门个数
SELECT COUNT(*) 个数,cityFROM departments d,locations lWHERE d.location_id=l.location_idGROUP BY city;
案例2.查询有奖金的每个部门的部门名和部门的领导编号和该部门最低工资
SELECT MIN(salary),d.manager_id,d.department_nameFROM departments d ,employees eWHERE d.department_id=e.department_idAND e.commission_pct is NOT NULLGROUP BY department_name,d.manager_id;
可以加排序
案例:查询每个工种的工种名和员工的个数,并且按员工个数降序
SELECT job_title,COUNT(*)FROM jobs j,employees eWHERE j.job_id=e.job_idGROUP BY job_titleORDER BY COUNT(*) DESC;
三表连接
案例:查询员工名、部门名、和所在城市名
SELECT last_name,department_name,cityFROMemployees e,departments d,locations lWHERE e.department_id=d.department_idAND d.location_id=l.location_idORDER BYdepartment_name DESC;
非等值连接
案例1:查询员工的工资和工资级别
SELECT salary,grade_levelFROM employees e,job_grades jWHERE salary BETWEEN j.lowest_sal AND j.highest_sal;
自连接
案例:查询 员工名和上级的名称
SELECT e.employees_id,e.last_name,m.employees_id,m.last_nameFROM employees e,employees mWHERE e.manager_id = m.employee_id;
2.sql99语法
内连接:INNER
外连接:
1.左外:left
2.右外:right
3.全外:full
交叉连接:cross
语法:
SELECT查询列表from 表1 别名【连接类型】join 表2 别名on 连接条件【where筛选条件】【group by分组】【having 筛选 条件】【order by 排序列表】
内连接
语法:
SELECT 查询列表from 表1 别名inner join 表二 别名
on 连接条件;
分类:等值、非等值、自连接
特点:
1.inner可以省略
2.添加排序、分组和筛选
3.筛选条件放在where后面,连接条件放在了on后面、提高了分离性,便于阅读。
等值连接
查询员工名、部门名
SELECT last_name,department_nameFROM employees eINNER JOINdepartments dON e.department_id =d.department_id;
案例2:查询名字中包含e的员工名和工种名(添加筛选)
SELECTlast_name,job_titleFROM employees eINNER JOIN jobs jON e.job_id=j.job_idWHEREe.last_name like '%e%';
案例3:查询部门个数 >3的城市名和部门个数,(添加分组和筛选)
SELECTcity,COUNT(*)FROM departments dINNER JOIN locations lon d.location_id= l.location_idGROUP BYcityHAVING COUNT(*)> 3;
案例4:查询哪个部门的员工个数>3的部门名和员工个数,并按个数降序(添加排序)
1:查询每个部门的员工个数
SELECTCOUNT(*) ,department_nameFROM employees eINNER JOINdepartments dON e.department_id=d.department_idGROUP BYdepartment_name;
2:在1的基础上筛选个数大于三的并记录
SELECT COUNT(*) ,department_nameFROM employees eINNER JOIN departments dON e.department_id=d.department_idGROUP BY department_nameHAVING COUNT(*)>3ORDER BYCOUNT(*) DESC;
案例五:查询员工名,部门名,工种名,并按部门名称降序()
SELECT last_name,department_name,job_titleFROM employees eINNER JOINdepartments d on e.department_id=d.department_idINNER JOINjobs j ON j.job_id=e.job_idORDER BY department_name DESC;
非等值连接
查询员工的工资级别
SELECT salary,grade_levelFROM employees eJOIN job_grades gONe.salary BETWEEN g.lowest_sal AND g.highest_sal;
查询公司级别个数大于20,并按工资级别降序
SELECT COUNT(*) ,grade_levelFROM employees eJOIN job_grades gon e.salary BETWEEN g.lowest_sal AND g.highest_salGROUP BYgrade_levelHAVING COUNT(*)>20ORDER BYgrade_level DESC
自连接
查询员工的名字,上级的名字
SELECTe.last_name,m.last_nameFROM employees eJOIN employees mON e.manager_id=m.employee_id;
查询姓名中包含k的员工的名字,上级的名字
SELECT e.last_name,m.last_nameFROM employees eJOIN employees mON e.manager_id=m.employee_idWHERE e.last_name LIKE '%k%';
外连接
应用场景:查询一个表中有,另一个表中没有的记录
特点:1.外连接的查询结果为主表中的所有记录,如果从表中有和它匹配的,则显示匹配的值。如果没有匹配的,则显示null。
外连接的查询结果=内连接结果+主表中有而从表中没有的记录
2.左外连接,left join左边的是主表。
右外连接,left join右边是主表。
3.左外和右外如果交换两表顺序,可以实现同样的效果
4.全外连接=内连接中结果+表1中没有表2中有的+表1中有表2中没有
案例引入:查询男朋友,不在男神表中的女神名
左外连接
SELECT b.name,bo.*FROM beauty bLEFT OUTER JOIN boys boON b.boyfriend_id=bo.idWHERE bo.id is NULL;
右外连接
SELECT b.name,bo.*FROM boys boRIGHT OUTER JOIN beauty bON b.boyfriend_id=bo.idWHERE bo.id is NULL;
案例1:哪个部门没有员工
左外
SELECT d.* ,e.employee_idFROM departments dLEFT OUTER JOIN employees eON d.department_id=e.department_idWHERE e.employee_id IS NULL;
右外
SELECT d.*,e.employee_idFROM employees eRIGHT OUTER JOINdepartments dON d.department_id=e.department_idWHERE e.employee_id IS NULL;
全外
USE girls;SELECTb.* , bo.*FROM beauty bFULL OUTER JOIN boys boon b.boyfriend_id-bo.id;
交叉连接
SELECTb.*,bo.*FROM beauty bCROSS JOIN boys bo;
进阶七:子查询
含义:出现在其他语句中的select语句,称为子查询或者内查询
外部的查询语句,称为主查询或者外查询
分类:
按子查询出现的位置:
SELECT后面:仅仅支持标量子查询
from后面:支持表子查询
where或having后面:标量子查询、列子查询、行子查询
exits后面(相关子查询):表子查询
按结果集的行列数不同:
标量子查询(结果集只有一行一列)
列子查询(结果集只有一列多行)
行子查询(结果集只有一行多列)
表子查询(结果集为多行多列)
where或having后面
1.标量子查询(单行子查询)
2.列子查询(多行子查询)
3.行子查询(多列多行)
特点:
1.子查询放在小括号内,
2.子查询一般放在条件的右侧
3.标量子查询,一般搭配着单行操作符使用
> < >= <= <> =
4.列子查询一般搭配着多行操作符使用
in any/some all
1.标量子查询
案例一:谁的工资比 Abel高?
查询Abel的工资
SELECTsalaryFROM employeesWHERE last_name ='Abel';
查询员工的信息,满足条件1的结果
SELECT *FROM employeesWHERE salary > (SELECT salaryFROM employeesWHERE last_name = 'Abel'
);
案例2:返回job_id与141号员工相同,salary比143号员工多 姓名,job_id和工资
查询141号的job_id
SELECTjob_idFROM employeesWHERE employee_id = 141;
143号员工的salary
SELECTsalaryFROM employeesWHERE employee_id =143;
查询员工的姓名 job_id=1和工资>2
SELECT last_name,job_id,salaryFROM employeesWHERE job_id = (SELECT job_idFROM employeesWHERE employee_id = 141) AND salary >(SELECT salaryFROM employeesWHERE employee_id =143);
案例3:返回公司工资最少的员工last_name ,job_id和salary
查询工资最少
SELECT MIN(salary) FROM employees;
查询对应值 salary = 1.
SELECT last_name,job_id,salaryFROM employeesWHERE salary = (SELECT MIN(salary)FROM employees);
案例4:查询最低工资 大于50号部门最低工资的部门id和其最低工资
查询50号部门的最低工资
SELECTMIN(salary)FROM employeesWHERE department_id = 50
查询每个部门的最低工资
SELECTMIN(salary),department_idFROM employeesGROUP BYdepartment_id;
筛选2满足 min(salary)>1的结果
SELECT MIN(salary),department_idFROM employeesGROUP BYdepartment_idHAVING MIN(salary)> (SELECT MIN(salary)FROM employeesWHERE department_id = 50);
2.列子查询(多行子查询)
案例1:返回location_id是1400或者是1700的部门中的所有员工姓名
查询location_id是1400或者1700的部门编号
SELECT department_idFROM departmentsWHERE location_id in(1400,1700);
查询员工姓名,要求部门号是1列表中的某一个
SELECT last_nameFROM employeesWHERE department_id IN(SELECT department_idFROM departmentsWHERE location_id in(1400,1700));
案例2:返回其他工种中比job_id 为‘IT_PROG’部门任一工资低的员工的员工号,姓名,job_id以及salary
查询job_id为‘IT_PROG’部门任一工资
SELECT DISTINCTsalaryFROM employeesWHERE job_id = 'IT_PROG';
查询员工号,姓名,job_id以及salary,salary<any(1的结果)
SELECT last_name,employee_id,job_id,salaryFROM employeesWHERE salary < any(SELECT DISTINCT salaryFROM employeesWHERE job_id = 'IT_PROG')AND job_id <>'IT_PROG';
另一种写法
SELECT last_name,employee_id,job_id,salaryFROM employeesWHERE salary < (SELECT MAX(salary)FROM employeesWHERE job_id = 'IT_PROG')AND job_id <>'IT_PROG';
3.行子查询(一行多列,多行多列)
案例:查询员工编号最小并且工资最高的员工编号
查询最小的员工编号
SELECT MIN(employee_id)FROM employees;
查询出最高的工资
SELECTMAX(salary)FROM employees;
查询员工信息
SELECT*FROM employeesWHERE employee_id = (SELECT MIN(employee_id)FROM employees)AND salary = (SELECT MAX(salary)FROM employees);
另一种写法
SELECT *FROM employeesWHERE (employee_id,salary)=(SELECT MIN(employee_id),MAX(salary)FROM employees );
放在select后面
案例:查询每个部门的员工个数
SELECT d.*,(SELECT COUNT(*)FROM employees eWHERE e.department_id =d.department_id) 个数FROM departments d;
放在from后面
案例:查询每个部门的平均工资的工资等级
查询每个部门的平均工资
SELECT AVG(salary) ,department_idFROM employeesGROUP BYdepartment_id;
连接1的结果集和job_grades表,筛选条件平均工资 BETWEEN lowest_sal and highest_sal
SELECT ag_dep.*,g.grade_levelFROM (SELECT AVG(salary) ag,department_idFROM employeesGROUP BY department_id) ag_dep INNER JOIN job_grades gON ag_dep.ag BETWEEN lowest_sal AND highest_sal;
进阶八:分页查询
应用场景:当要显示的数据,一页显示不全,需要分页提交sql请求
语法:
SELECT 查询列表
FROM 表【JOIN type join 表2ON 连接条件WHERE 筛选条件GROUP BY 分组字段having 分组后筛选ORDER BY 排序的字段】limit offset,size;#offset表示要显示条目的起始索引(从0开始)#size表示显示的条目个数
特点:
1.limit语句放在查询语句的最后,并且执行也是最后执行。
2.公式:要显示的页数是page,每页显示的条目数是size
SELECT 查询列表FROMlimit (page-1)*size ,size;
案例1:查询前五条员工信息
SELECT * FROM employeesLIMIT 0,5;
或者
SELECT * FROM employeesLIMIT 5;
案例2:查询第11-25条的信息
SELECT * FROM employeesLIMIT 10,15;
案例3:有奖金的员工信息,并且工资较高的排名前10的员工信息
SELECT *
FROM employees WHERE commission_pct is NOT NULLORDER BY salary DESCLIMIT 10;
进阶九:联合查询
UNION 联合/合并 :将多条语句的查询结果合并成一个结果。
语法:
查询语句1union查询语句2union...
应用场景:要查询的结果来自于多个表,且多个表之间没有直接连接关系,但查询的信息一致时。
特点:
1.要求多条查询语句的查询列数是一致的
2.要求多条查询语句的查询的每一列的类型和顺序最好一致!
3.不想去重用 :UNION ALL,默认是去重的
引入的案例:查询部门编号>90或者邮箱包含a的员工信息
以前的方法
SELECT *FROMemployeesWHERE email LIKE '%a%'OR department_id>90;
union方法
SELECT * FROM employees WHERE email like '%a%'UNIONSELECT * FROM employees WHERE department_id>90;
进阶十:DML语言
数据操纵语言:
数据插入:INSERT
数据修改:UPDATE
数据删除:DELETE
一、插入语句
经典插入
语法:
insert INTO 表名(列名,...) values(值1,...);INSERT INTO 表名set 列名=值,列名=值,...
1.插入的值类型要和列的类型兼容或一致
2.不可以为null的列必须插入值,可以为null的列是如何插入值的?
方式一:直接写NULL
方式二:列不写,NULL也不写
3.**列的顺序是否可以颠倒?**yes,可以。
4.列数和值的个数必须一致
5.可以省略列名,默认是所有列,而且列的顺序和表中列的顺序一致
INSERT INTO beauty
VALUES(18,'畅','男',NULL,'1165654',NULL,NULL);
直接插入案例
INSERT INTO beautySET id=19,NAME='大哥',phone='456465';
两种方式大PK
方式一有方式二无:支持插入多行(一次性加入多个数据行),支持子查询。
二、修改语句
1.修改单表的记录 ★
语法:
update 表名sset 列=新值,列=新值,...WHERE 筛选条件;
2.修改多表的记录【补充】
语法:
sql92语法:
update 表1 别名, 表2 别名SET 列=值,...where 连接条件and 筛选条件;
Sql99语法:
update 表1 别名inner|left|right join 表2 别名on 连接条件set 列=值,...where 筛选条件;
案例1:修改单表的记录
修改beauty表中姓唐的女神的电话为156456465
UPDATE beauty SET phone = '156456465'WHERE NAME LIKE '唐%';
案例2:修改boys表中的id号为2的名称为张非,并且魅力值改为10
UPDATE boys SET boyname='张非',usercp='10'WHERE id ='2';
2.修改多表的记录【补充】
案例1:修改张无忌的女朋友的手机号为“156465465”
UPDATE boys boINNER JOIN beauty b ON bo.id = b.boyfriend_idSET b.phone ='156465465'WHERE bo.boyName = '张无忌';
案例2:修改没有男朋友的女神的男朋友编号都为2号(张飞)
UPDATE boys boRIGHT JOIN beauty b ON bo.id = b.boyfriend_idSET b.boyfriend_id = '2'WHERE b.id is NULL;
3.删除语句
方式一:delete
语法:
(一删就是整行,所以需要加筛选条件)
1.单表删除
delete FROM 表名 where 筛选条件
2.多表删除【补充】
方式二:TRUNCATE
语法: TRUNCATE table 表名; (全部删掉)
sql92语法:
delete 表1的别名,表2的别名from 表1 别名 ,表2 别名WHERE 连接条件AND 筛选条件
sql99语法:
DELETE 表1的别名,表2的别名 FROM 表1 别名INNER|left|right| join 表2 别名 on 连接条件where 筛选条件
方式一:delete
单表删除
案例一:删除手机号以9为结尾的女生信息
DELETE FROM beauty WHERE phone LIKE '%9';
多表删除
案例:删除张无忌的女朋友的信息
DELETE b FROM beauty bINNER JOIN boys bo ON b.boyfriend_id=bo.idWHERE bo.boyName ='张无忌'
案例:删除黄晓明的信息以及他女朋友的信息
DELETE b,boFROM beauty bJOIN boys bo ON b.boyfriend_id=bo.idWHERE bo.boyName = '黄晓明'
DELETE pk TRUNCATE**
1.delete可以加where条件,TRUNCATE不可以。
2.TRUNCATE删除效率稍微高点。
3.假如要删除的表中有自增长列,
如果用delete删除后,再插入数据,自增长列的值从断点开始,
而truncate删除后。再插入数据,自增长列的值从1开始。
4.TRUNCATE 删除没有返回值,delete有。
5.TRUNCATE删除后不可以回滚,DELETE可以。
进阶十一:DDL语言
数据定义语言
库和表的管理
一、库的管理:创建、修改、删除
二、表的管理:创建、修改、删除
创建:create
修改:alter
删除:Drop
1.表的创建 ★
create table 表名(列名 列的类型【(长度) 约束】,列名 列的类型【(长度) 约束】,列名 列的类型【(长度) 约束】,...列名 列的类型【(长度) 约束】)
案例:创建表book
CREATE TABLE if NOT EXISTS book(id INT,#书的编号bName VARCHAR(20),#图书名price DOUBLE,#价格authorId INT, #图书作者 publishDate DATETIME#出版日期);
创建作者表author
CREATE TABLE author(Id INT,au_name VARCHAR(20),nation VARCHAR(20));
2.表的修改
修改列名、修改列的类型或者约束
添加新列、删除列、修改表名
修改列名
ALTER TABLE book CHANGE COLUMN publishdate pubDate DATETIME;
修改列的类型
ALTER TABLE book MODIFY COLUMN pubdate TIMESTAMP;
添加新列
ALTER TABLE author ADD COLUMN annual DOUBLE;
删除列
ALTER TABLE author DROP COLUMN annual;
修改表名
ALTER TABLE author RENAME TO book_author;
3.表的删除
DROP TABLE IF EXISTS book_author
;
通用的写法:
DROP DATABASE is EXISTS 旧的库名CREATE DATABASE 新库名;DROP TABLE IS EXISTS 旧表名;CREATE TABLE 新表名();
**4.**表的复制
INSERT INTO author VALUES(1,'村上春树','日本'),(2,'莫言','中国'),(3,'冯唐','中国'),(4,'金庸','中国');
1.仅仅复制表的结构
CREATE TABLE copy LIKE author;
2.复制表的结构+数据
CREATE TABLE copy2
SELECT * FROM author;
3.只复制一部分
CREATE TABLE copy3SELECT id,au_nameFROM author WHERE nation='中国';
复制一部分,没内容
CREATE TABLE copy4SELECT id,au_nameFROM authorWHERE 1=2;
进阶十二:常见的数据类型
数值型:
整型
小数:定点数,浮点数
字符型:
较短的文本:char,varchar
较长的文本:text,blob(较长的二进制数字)
日期型
1.整型
分类:TINYINT 1, SMALLINT 2, MEDIUMINT 3, int/INTEGER 4, BIGINT 8 (个子节)
特点:
1.如果不设置有无符号,默认是有符号,想设置无符号需要设置UNSIGNED
2.如果插入的数值超过了整型的范围,会报异常,并且插入的是临界值
3.如果不设置长度,会有默认的长度。
4.长度代表了显示的最大宽度,如果不够会用0在左边填充,但是必须搭配zerofill使用
如何设置无符号和有符号
CREATE TABLE tab_int(t1 INT,t2 INT UNSIGNED);
INSERT INTO tab_int VALUES (-123456,12456);
2.小数
浮点型:float(M,D) double(M,D)
定点型:dec(M,D) DECIMAL(M,D)
特点:1.关于M和D的意思—M:整数部位+小数部位 D:小数部位 如果超过范围,则插入临界值。
2.M和D都可以省略,如果是decimal,则M默认是10,D默认是0,
如果插入的是float或double,则会随着插入的数值的精度来决定精度。
对比:定点型的精度较高,如果要求插入的数值的精度较高,则优先使用它(货币运算等)。
举例子
CREATE TABLE tab_float(f1 FLOAT(5,2),f2 DOUBLE(5,2),f3 DECIMAL(5,2));SELECT * FROM tab_float;INSERT INTO tab_float VALUES(123.45,123.45,123.45);INSERT INTO tab_float VALUES(123.456,123.456,123.456);INSERT INTO tab_float VALUES(123.4,123.4,123.4);INSERT INTO tab_float VALUES(1523.4,1523.4,1523.45);#原则:所选择的类型越简单越好
3.字符型
较短的文本:
char
VARCHAR
其他:
VARBINARY和binary适用于保存较短的二进制
enum用于保存枚举,set用于保存集合
较长的文本:
text
blob(较大的二进制)
比较:
写法 | M的意思 | 特点 | 空间耗费 | 效率 |
---|---|---|---|---|
char char(M) | 最大字符数 | 固定长度的字符 | 比较耗费 | 高 |
VARCHAR VARCHAR(M) | 最大的字符数 | 可变长度的字符 | 比较节省 | 低 |
4.日期型
分类:
date只保存日期
time只保存时间
year只保存年
datetime保存日期+时间
TIMESTAMP保存日期+时间
比较:
字节 | 范围 | 时区等的影响 | |
---|---|---|---|
datetime | 8 | 较大1000-9999年 | 不受 |
TIMESTAMP | 4 | 较小1970-2038年 | 受 |
进阶十三:常见约束
一种限制,用于限制表中的数据,为了保证表中的数据的准确和可靠性
分类:
NOT NULL :非空,用于保证该字段的值不能为空
比如姓名、学号等
DEFAULT:默认,用于保证该字段的值有默认值
比如性别
PRIMARY KEY :主键,用于保证该字段的值有唯一值,并且非空
比如学号、员工编号等
UNIQUE : 唯一,用于保证该字段的值有唯一值,可以为空
比如座位号
CHECK:检查约束【MySQL中不支持】[兼容性…不报错,但是没效果]
比如:年龄和性别
FOREIGN KEY :外键,用于限制两个表的关系,用于保证该字段的值必须来自于主表的关联列的值
比如:学生表的专业编号,员工表的部门编号,员工表的工种编号
1.添加约束的时机
1.创建表时
2.修改表时
2.约束的添加分类
1.列级约束
六大约束语法上都支持,但外键约束没有效果。
2.表级约束
除了非空,默认,其他的都支持。
CREATE TABLE 表名(字段名 字段类型 列级约束字段名 字段类型 表级约束
);
创建表时添加约束
#1.添加列级约束
语法:
直接在字段名和类型后面追加约束类型即可
CREATE table stuinfo(id INT PRIMARY KEY,#主键stuName VARCHAR(20) NOT NULL ,#非空gender CHAR(1) CHECK(gender='男'OR gender='女'),#检查性别seat INT UNIQUE ,#唯一age INT DEFAULT 18 #默认约束);
CREATE TABLE major(id INT PRIMARY key,majorName VARCHAR(20));
添加表级约束
在各个字段最下面
【CONSTRAINT 约束名】(可以去掉) 约束类型(字段名)
#通用写法:
CREATE table IF NOT EXISTS stuinfo(id INT PRIMARY KEY,stuname VARCHAR(20) NOT NULL,gender CHAR(1),age INT DEFAULT 18,seat INT UNIQUE ,majorid INT,FOREIGN KEY(majorid) REFERENCES major(id));
主键和唯一的区别
1.均可以保证唯一性
2.主键不允许为空,唯一可以为空
3.主键最多为一个(0/1)
唯一可以有多个
4.都允许组合,但是不推荐
外键的特点
1.要求在从表设置外键关系
2.从表的外键列的类型和主表中的关联列的类型要求一致或者兼容,名称无要求
3.主表的关联列必须是个key(一般是主键或者唯一)
4.插入数据时,必须先插入主表(科目),再插入从表(学生),
删除数据时,先删除从表,再删除主表。
3.标识列
又称为自增序列
含义:可以不用手动的插入值,系统提供默认的序列值
特点:1.标识列和key搭配
2.一个表中可以有至多一个标识列
3.标识列类型只能是数值型
4.标识列可以通过 SET auto_increment_increment=3;设置步长,可以通过手动插入值,设置起始值。
创建表时设置标识列
DROP TABLE IF EXISTS tab_identity;CREATE TABLE tab_identity(id INT PRIMARY KEY auto_increment,NAME VARCHAR(20) );
修改表时设置标识列
ALTER TABLE tab_identity MODIFY COLUMN id INT PRIMARY KEY auto_increment;
修改表时删除标识列
ALTER TABLE tab_identity MODIFY COLUMN id INT PRIMARY KEY;
进阶十四:TCL语言 事务控制语言
事务:一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行。
案例:转账
张三丰 1000
郭襄 1000
张三丰转给郭襄500
张三丰 500
郭襄 1500
事务(ACID)的属性:
1.原子性:原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生要么都不发生。
2.一致性:事务必须使数据库从一个一致性状态变成另外一个一致性状态。
3.隔离性:事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务
是隔离的,并发执行的各个事务之间是不能互相干扰的。
4.持久性:持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,
接下来的其他操作和数据库故障不应该对其有任何影响。
事务的创建:
隐式事务:事务没有明显的开启和结束标记 比如:INSERT UPDATE DELETE 语句
显式事务:事务具有明显的开启和结束的标记(前提,必须先设置自动提交功能为禁用)
1.开启事务
SET autocommit=0;(关闭自动提交)
2.编写事务中的sql语句(SELECT INSERT UPDATE SELECT)
语句1;
语句2;
…
3.结束事务
COMMIT; 提交事务
ROLLBACK; 回滚事务
NOT NULL :非空,用于保证该字段的值不能为空
比如姓名、学号等
DEFAULT:默认,用于保证该字段的值有默认值
比如性别
PRIMARY KEY :主键,用于保证该字段的值有唯一值,并且非空
比如学号、员工编号等
UNIQUE : 唯一,用于保证该字段的值有唯一值,可以为空
比如座位号
CHECK:检查约束【MySQL中不支持】[兼容性…不报错,但是没效果]
比如:年龄和性别
FOREIGN KEY :外键,用于限制两个表的关系,用于保证该字段的值必须来自于主表的关联列的值
比如:学生表的专业编号,员工表的部门编号,员工表的工种编号
1.添加约束的时机
1.创建表时
2.修改表时
2.约束的添加分类
1.列级约束
六大约束语法上都支持,但外键约束没有效果。
2.表级约束
除了非空,默认,其他的都支持。
CREATE TABLE 表名(字段名 字段类型 列级约束字段名 字段类型 表级约束
);
创建表时添加约束
#1.添加列级约束
语法:
直接在字段名和类型后面追加约束类型即可
CREATE table stuinfo(id INT PRIMARY KEY,#主键stuName VARCHAR(20) NOT NULL ,#非空gender CHAR(1) CHECK(gender='男'OR gender='女'),#检查性别seat INT UNIQUE ,#唯一age INT DEFAULT 18 #默认约束);
CREATE TABLE major(id INT PRIMARY key,majorName VARCHAR(20));
添加表级约束
在各个字段最下面
【CONSTRAINT 约束名】(可以去掉) 约束类型(字段名)
#通用写法:
CREATE table IF NOT EXISTS stuinfo(id INT PRIMARY KEY,stuname VARCHAR(20) NOT NULL,gender CHAR(1),age INT DEFAULT 18,seat INT UNIQUE ,majorid INT,FOREIGN KEY(majorid) REFERENCES major(id));
主键和唯一的区别
1.均可以保证唯一性
2.主键不允许为空,唯一可以为空
3.主键最多为一个(0/1)
唯一可以有多个
4.都允许组合,但是不推荐
外键的特点
1.要求在从表设置外键关系
2.从表的外键列的类型和主表中的关联列的类型要求一致或者兼容,名称无要求
3.主表的关联列必须是个key(一般是主键或者唯一)
4.插入数据时,必须先插入主表(科目),再插入从表(学生),
删除数据时,先删除从表,再删除主表。
3.标识列
又称为自增序列
含义:可以不用手动的插入值,系统提供默认的序列值
特点:1.标识列和key搭配
2.一个表中可以有至多一个标识列
3.标识列类型只能是数值型
4.标识列可以通过 SET auto_increment_increment=3;设置步长,可以通过手动插入值,设置起始值。
创建表时设置标识列
DROP TABLE IF EXISTS tab_identity;CREATE TABLE tab_identity(id INT PRIMARY KEY auto_increment,NAME VARCHAR(20) );
修改表时设置标识列
ALTER TABLE tab_identity MODIFY COLUMN id INT PRIMARY KEY auto_increment;
修改表时删除标识列
ALTER TABLE tab_identity MODIFY COLUMN id INT PRIMARY KEY;
进阶十四:TCL语言 事务控制语言
事务:一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行。
案例:转账
张三丰 1000
郭襄 1000
张三丰转给郭襄500
张三丰 500
郭襄 1500
事务(ACID)的属性:
1.原子性:原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生要么都不发生。
2.一致性:事务必须使数据库从一个一致性状态变成另外一个一致性状态。
3.隔离性:事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务
是隔离的,并发执行的各个事务之间是不能互相干扰的。
4.持久性:持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,
接下来的其他操作和数据库故障不应该对其有任何影响。
事务的创建:
隐式事务:事务没有明显的开启和结束标记 比如:INSERT UPDATE DELETE 语句
显式事务:事务具有明显的开启和结束的标记(前提,必须先设置自动提交功能为禁用)
1.开启事务
SET autocommit=0;(关闭自动提交)
2.编写事务中的sql语句(SELECT INSERT UPDATE SELECT)
语句1;
语句2;
…
3.结束事务
COMMIT; 提交事务
ROLLBACK; 回滚事务
SAVEPOINT 节点名;设置节点(保存点)类似于断点
DELETE 和 TRUNCATE在事务使用时的区别:
演示delete:支持回滚:
SET autocommit = 0;
START TRANSACTION;
DELETE FROM account;
ROLLBACK;
演示truncate:不支持回滚
SET autocommit=0;
START TRANSACTION;
TRUNCATE TABLE account;
ROLLBACK;
演示savepoint的使用
#SAVEPOINT只搭配rollback使用
SET autocommit=0;
START TRANSACTION;
DELETE FROM account WHERE id=25;
SAVEPOINT a;#设置保存点
DELETE FROM account WHERE id=28;
ROLLBACK TO a;#回滚到保存点处
#最终效果只有id25删掉了28没有删掉
进阶十五:视图
MySQL从5.0.1版本开始提供视图功能。一种虚拟存在的表,行和列的数据来自定义视图的查询中使用的表,并且
是在使用视图时动态生成的,只保存了sql逻辑,并不保存查询结果。
应用场景:
1.多个地方用到同样的查询结果
2.该查询结果使用sql语句较复杂
案例:查询姓张的学生名和专业名
普通解法
SELECT stuname,majornameFROM stuinfo sINNER JOIN major m on s.majorid=m.idWHERE s.stuname like '张%';
利用视图
CREATE VIEW v1ASSELECT stunname,majornameFROM stuinfo sINNER JOIN major m on s.majorid=m.id;SELECT * FROM v1WHERE s.stuname like '张%';#注意:为什么使用*,因为视图中就只有一开始指定好的信息
1.如何创建视图?
语法:SELECT VIEW 视图名AS查询语句;
案例1:查询邮箱中包含a字符的员工名、部门名和工种信息
#1.创建CREATE VIEW myv1ASSELECT last_name,department_name,job_titleFROM employees eJOIN departments d ON e.department_id=d.department_idJOIN jobs j on j.job_id= e.job_id;#2.使用SELECT * FROM myv1 WHERE last_name like '%a%';
案例2:查询各部门的平均工资级别
#创建视图查看每个部门的平均工资CREATE VIEW myv2ASSELECT AVG(salary) ag,department_idFROM employeesGROUP BY department_id;#使用SELECT myv2.ag,g.grade_levelFROM myv2JOIN job_grades gON myv2.ag BETWEEN g.lowest_sal AND g.highest_sal;
案例3:查询平均工资最低的部门信息
SELECT * FROM myv2ORDER BY ag LIMIT 1;
案例4:查询平均工资最低的部门名和工资
CREATE VIEW myv3AS SELECT * FROM myv2 ORDER BY ag LIMIT 1;SELECT d.*,m.ag FROM myv3 mJOIN departments don m.department_id = d.department_id;
2.视图的修改
#方式一:CREATE or REPLACE view 视图名as查询语句;#例:CREATE OR REPLACE VIEW myv3AS SELECT AVG(salary),job_idFROM employeesGROUP BY job_id;
#方式二:#语法:ALTER view 视图名AS查询语句; #例:ALTER view myv3ASSELECT * FROM employees;
3.删除视图
语法:drop VIEW 视图名,视图名,...;
例:
DROP view myv1,myv2;
4.查看视图
SHOW CREATE view myv3;
5.视图的更新
CREATE OR REPLACE VIEW myv1AS SELECT last_name,emailFROM employees;
#1.插入INSERT INTO myv1 VALUES('张飞','zf@qq.com');#注意:这里的修改视图会影响到原来的表的内容#2.修改UPDATE myv1 SET last_name ='张无忌' WHERE last_name='张飞';#3.删除DELETE FROM myv1 WHERE last_name ='张无忌';
视图和表的对比 | 是否占用物理空间 | 使用 |
---|---|---|
视图:CREATE view | 没有(仅仅保存了逻辑,没有保留数据) | 增删改查,一般不能增删改 |
表:CREATE TABLE 占用 | 占用 | 增删改查 |
进阶十六:变量
系统变量:
全局变量
会话变量
自定义变量:
用户变量
局部变量
1、系统变量
说明:变量由系统提供,不是用户定义,属于服务器层面。
使用的语法:
1.查看所有的系统变量
SHOW GLOBAL |【session】 VARIABLES;
2.查看满足条件的部分系统变量
SHOW GLOBAL|【SESSION】 VARIABLES like '%char%';
3.查看指定的某个系统变量的值
SELECT @@global|【SESSION】.系统变量名
4.为某个系统变量赋值
方式一
set GLOBAL |【session】 系统变量名 = 值;
方式二
set @@GLOBAL |【session】.系统变量名 =值;
注意:如果是全局级别,用GLOBAL
如果是会话级别,则需要加session,如果不写,则默认是session
全局变量:
作用域:服务器每次启动将为所有的全局变量赋初始值,针对于所有的会话(连接)有效,但不能跨重启。
1.查看所有的全局变量
SHOW GLOBAL VARIABLES;
2.查看部分的全局变量
SHOW GLOBAL VARIABLES LIKE '%CHAR%';
3.查看指定的全局变量的值
SELECT @@global.autocommit;
SELECT @@tx_isolation;
4.为某个指定的全局变量赋值
SET @@global.autocommit=0;
会话变量:
作用域:仅仅针对于当前会话(连接)有效。
1.查看所有的会话变量
SHOW VARIABLES;
2.查看部分的会话变量
SHOW VARIABLES LIKE '%CHAR%';
SHOW SESSION VARIABLES LIKE '%CHAR%';
3.查看指定的会话变量的值
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;
4.为某个指定的会话变量赋值
SET @@session.tx_isolation='read-UNCOMMITTED';
SET SESSION tx_isolation = 'read-COMMITTED';
2、自定义变量
说明:变量是用户自定义的,不是由系统的。
使用步骤:声明、赋值、使用(查看、比较、运算等)
用户变量
作用域:针对于当前会话(连接)有效,和会话变量的作用域一致应用在任何地方,也就是begin end里面或者begin end外面
赋值的操作符 : =或:=
1.声明并初始化
SET @用户变量名 =值;
SET @用户变量名:=值;
SELECT @用户变量名:=值;
2.赋值(更新用户变量的值)
方式一:通过set或者select
SET @用户变量名 =值;
SET @用户变量名:=值;
SELECT @用户变量名:=值;
例:
SET @name = 'john';
SET @name=100;
方式二:通过select INTO
SELECT 字段名 INTO 变量名
FROM 表;
例:
SET @count =1SELECT COUNT(*) INTO @countFROM employees;
3.(使用)查看用户变量的值
SELECT @用户变量名;
SELECT @count;
局部变量
作用域 :仅仅在定义他的begin END中有效,应用在begin end中的第一句话。
1.声明
DECLARE 变量名 类型;
DECLARE 变量名 类型 DEFAULT 值;
2.赋值
方式一:通过set 或select
set 局部变量名=值;
set 局部变量名:=值;
SELECT @局部变量名:=值;
方式二:通过select INTO
SELECT 字段 into 局部变量名
FROM 表;
3.使用
SELECT 局部变量名;
对比用户变量和局部变量
作用域 | 定义和使用的位置 | 语法 | |
---|---|---|---|
用户变量 | 当前会话 | 会话中的任何地方 | 必须加@符号,不用限定类型 |
局部变量 | begin END中 | 只能在begin end中,且为第一句话 | 一般不用加@符号,需要限定类型 |
案例:声明两个变量并赋初始值,求和并打印
1.用户变量
SET @m=1;SET @n=2;SET @sum=@m+@n;SELECT @sum;
2.局部变量
DECLARE m INT DEFAULT 1;DECLARE n INT DEFAULT 2;DELETE sum INT;SET sum=m+n;SELECT sum;
进阶十七:存储过程和函数
类似于Java中的方法,好处
1.提高代码的重用性
2.简化操作
存储过程
含义:一组预先编译好的SQL语句的集合,理解成批处理语句
1.提高代码的重用性
2.简化操作
3.减少了编译次数并且减少了和数据库服务的连接次数,提高了效率。
1:创建语法
CREATE PROCEDURE 存储过程名(参数列表)BEGIN存储过程体(一组合法的SQL语句)END
注意:
1.参数列表包含三个部分:
参数模式 参数名 参数类型
举例:
IN stuname VARCHAR(20);
参数模式:
in :该参数可以作为输入:也就是该参数需要调用方传入值
OUT:该参数可以作为输出,也就是该参数可以作为返回值
inout:该参数既可以作为输入也可以作为输出,也就是该参数既需要传入值又可以返回值。
2.如果存储过程体仅仅只有一句话,begin END 可以省略
存储过程体中的每条SQL语句的结尾要求必须加分号。
存储过程的结尾可以使用 delimiter重新设置 语法:delimiter 结束标记
2:调用语法
CALL 存储过程名(实参列表);
1.空参的存储过程
SELECT * FROM admin;delimiter $CREATE PROCEDURE myp1()BEGININSERT INTO admin(username,`password`) VALUES('john1','156456'),('lily','0000'),('jvaad','56465'),('dasd','465465'),('4dasd','41324');END $
2.创建带in模式参数的存储过程
案例1:创建存储过程实现 根据女神名查询对应的男神信息
delimiter $CREATE PROCEDURE myp2(IN beautyName VARCHAR(20))BEGINSELECT bo.*FROM boys boRIGHT JOIN beauty b ON bo.id = b.boyfriend_idWHERE b.name = beautyName;END $#调用delimiter $CALL myp2('柳岩')$
案例2:创建存储过程实现,用户是否登录成功
delimiter $CREATE PROCEDURE myp3(in username VARCHAR(20),IN PASSWORD VARCHAR(20))BEGINDECLARE result INT DEFAULT 0;#声明并初始化SELECT COUNT(*) INTO result;#赋值FROM adminWHERE admin.username=usernameAND admin.password=password;SELECT IF(rusult>0,'成功','失败');#使用end $
3.带out模式的存储过程
案例1:根据女神名,返回对应的男神名
delimiter $USE girlsCREATE PROCEDURE myp4(in beautyName VARCHAR(20),OUT boyName VARCHAR(20))BEGINSELECT bo.boyNameFROM boys boINNER JOIN beauty b ON bo.id=b.boyfriend_idWHERE b.name=beautyName;END $#调用:delimiter $CALL myp4('王语嫣',@bname)$SELECT @bname$
案例2:根据女神名,返回对应的男神名和男神魅力值
delimiter $CREATE PROCEDURE myp5(in beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT userCP INT)BEGINSELECT bo.boyName,bo.userCP INTO boyName,userCPFROM boys boINNER JOIN beauty b ON bo.id=b.boyfriend_idWHERE b.name=beautyName;END $#调用CALL myp5('王语嫣',@bname,@usercp);SELECT @bname,@usercp$
4.带inout模式的存储过程
案例1:传入a和b两个值,最终要求a和b都翻倍并返回
delimiter $CREATE PROCEDURE myp3(INOUT a INT,INOUT b INT)BEGIN SET a = a*2;SET b = b*2;END $
#调用
delimiter $SET @m=10$SET @n=20$CALL myp3(@m,@n)$SELECT @m,@n$
题目1:创建存储过程实现传入用户名和密码,插入到admin表中
delimiter $CREATE PROCEDURE test1 (IN username VARCHAR(20),IN loginPwd VARCHAR(20))BEGININSERT INTO admin(admin.username,PASSWORD)VALUES(username,loginPwd);END$
题目2:创建存储过程实现传入女神编号,返回女神名称和电话
delimiter $CREATE PROCEDURE test2(IN id INT,OUT name VARCHAR(20),OUT phone VARCHAR(20))BEGINSELECT b.name ,b.phone INTO NAME ,phoneFROM beauty bWHERE b.id=id;END $
题目3:创建存储过程或函数实现传入两个女神生日,返回大小
delimiter $CREATE PROCEDURE test3(IN birth1 datetime,IN birth2 datetime,out result INT)BEGINSELECT DATEDIFF(birth1,birth2) INTO result;END $
3.删除存储过程
语法:drop procedure 存储过程名
DROP PROCEDURE p1;
DROP PROCEDURE p2,p3;#不可以! 只可以放一个
4.查看存储过程的信息
SHOW CREATE PROCEDURE myp2;
函数
含义:一组预先编译好的SQL语言的集合,理解成批处理语句
优点:
1.提高了代码的重用性
2.简化操作
3.减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率
区别:
存储过程:可以有零个返回,也可以有多个返回。
函数:必须有且仅有一个返回,零个多个均不行。
1.函数创建语法
CREATE FUNCTION 函数名(参数列表) RETURNS 返回类型BEGIN函数体END
1.参数列表包含两部分:参数名 参数类型
2.函数体:肯定会有return语句,如果没有会报错。如果return语句没有放在函数体的最后也不会报错,但是不建议。
3.函数体中仅有一句话,则可以省略begin end
4.使用delimiter语句设置结束标记
2.调用语句
SELECT 函数名(参数列表)
案例演示:
1.无参有返回
案例:返回公司的员工个数
SET GLOBAL = TRUE;delimiter $USE myemployees;CREATE FUNCTION myf1() RETURNS INTBEGINDECLARE c INT DEFAULT 0;SELECT count(*) INTO cFROM employees;RETURN c;END $SELECT myf1()$
2.有参有返回值
案例1:根据员工名,返回他的工资
CREATE FUNCTION myf2(empName VARCHAR(20)) RETURNS DOUBLEBEGIN SET @sal=0;#定义用户变量SELECT salary INTO @sal #赋值FROM employeesWHERE last_name = empName;RETURN @sal;END $SELECT myf2('k_ing')$
案例2:根据部门名,返回该部门的平均工资。
CREATE FUNCTION myf3(deptName VARCHAR(20)) RETURNS DOUBLEBEGINDECLARE sal DOUBLE;SELECT AVG(salary) INTO salFROM employees eJOIN departments d ON e.department_id=d.department_idWHERE d.department_name = deptName;RETURN sal;END$ SELECT myf3('IT')$
3.函数的查看
SHOW CREATE FUNCTION myf3;
4.函数的删除
DROP FUNCTION myf3;
案例:创建函数,实现传入两个float,返回二者之和
delimiter $CREATE FUNCTION test4(num1 FLOAT ,num2 FLOAT) RETURNS FLOATBEGINDECLARE sum FLOAT DEFAULT 0;SET sum=num1+num2;RETURN sum;end$SELECT test4(1,2)$
进阶十八:流程控制结构
- 顺序结构:程序从上往下依次执行
- 分支结构:程序从两条或多条路径中选择一条去执行
- 循环结构:程序在满足一定条件的基础上,重复执行一段代码
1.分支结构
IF函数
功能:实现简单的双分支
语法:
IF(表达式1,表达式2,表达式3)执行顺序:如果表达式1成立,则返回2值,否则返回3值。
应用:任何地方
case结构
情况1:类似于Java中的switch语句,一般用于实现的等值判断
语法:
CASE 变量|表达式|字段WHEN 要判断的值 THEN 返回的值1或语句n1;WHEN 要判断的值 THEN 返回的值2或语句n2;...ELSE 要返回的值或者语句n;end CASE;
情况2:类似于Java中的多重if语句,一般用于实现区间判断
CASE WHEN 要判断的条件1 THEN 返回的值1或语句n1;WHEN 要判断的条件2 THEN 返回的值2或语句n2;...ELSE 要返回的值或语句nend CASE;
特点:
1.可以作为表达式,嵌套在其他语句中使用,可以放在任何地方, BEGIN END 中或begin END 的外面
可以作为独立的语句去使用,只能放在begin end中
2.如果when中的值满足或条件成立,则执行对应的then语句并且结束case,都不满足则执行else中的语句或值
3.else可以省略,如果else省略,并且所有的when条件都不满足,则返回null
if结构
功能:实现多重分支
语法:
if 条件1 then 语句1;ELSEIF 条件2 then 语句2;...【else 语句n;】END IF;
应用在begin end中
2.循环结构:
分类:while loop repeat
循环控制:
ITERATE 类似于continue ,继续
leave类似于break
while
语法:
【标签:】while循环条件 do循环体;end WHILE 【标签】;
LOOP
语法:
【标签:】LOOP 循环体;end LOOP 【标签】;#可以用来模拟简单的死循环
REPEAT
语法:
【标签:】repeat循环体;UNTIL 结束循环的条件end REPEAT 【标签】;
案例: 批量插入,根据次数插入到admin表中多条记录(没有添加循环控制语句)
delimiter $DROP PROCEDURE pro_while1$delimiter $CREATE PROCEDURE pro_while1(IN insertCount INT)BEGIN DECLARE i INT DEFAULT 1;WHILE i<=insertCount DOINSERT INTO admin(username,PASSWORD) VALUES(CONCAT('rose',i),'666');SET i=i+1;END WHILE; END $delimiter $CALL pro_while1(100)$SELECT * FROM admin$
添加leave语句
案例:批量插入,根据次数插入到admin表中多条记录,如果次数>20则停止
TRUNCATE TABLE admin$DROP PROCEDURE test_while1$delimiter $CREATE PROCEDURE test_while1(IN insertCount INT)BEGINDECLARE i INT DEFAULT 1;a:WHILE i<=insertCount DOINSERT INTO admin(username,PASSWORD) VALUES(CONCAT('re',i),'666');IF i>=20 THEN LEAVE a;END IF;SET i=i+1;END WHILE a;END$delimiter $CALL test_while1(50)$SELECT * FROM admin$
笔记到这里就结束了,希望您能通过本文的阅读,掌握数据库的基础知识。
4.查看存储过程的信息
SHOW CREATE PROCEDURE myp2;
函数
含义:一组预先编译好的SQL语言的集合,理解成批处理语句
优点:
1.提高了代码的重用性
2.简化操作
3.减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率
区别:
存储过程:可以有零个返回,也可以有多个返回。
函数:必须有且仅有一个返回,零个多个均不行。
1.函数创建语法
CREATE FUNCTION 函数名(参数列表) RETURNS 返回类型BEGIN函数体END
1.参数列表包含两部分:参数名 参数类型
2.函数体:肯定会有return语句,如果没有会报错。如果return语句没有放在函数体的最后也不会报错,但是不建议。
3.函数体中仅有一句话,则可以省略begin end
4.使用delimiter语句设置结束标记
2.调用语句
SELECT 函数名(参数列表)
案例演示:
1.无参有返回
案例:返回公司的员工个数
SET GLOBAL = TRUE;delimiter $USE myemployees;CREATE FUNCTION myf1() RETURNS INTBEGINDECLARE c INT DEFAULT 0;SELECT count(*) INTO cFROM employees;RETURN c;END $SELECT myf1()$
2.有参有返回值
案例1:根据员工名,返回他的工资
CREATE FUNCTION myf2(empName VARCHAR(20)) RETURNS DOUBLEBEGIN SET @sal=0;#定义用户变量SELECT salary INTO @sal #赋值FROM employeesWHERE last_name = empName;RETURN @sal;END $SELECT myf2('k_ing')$
案例2:根据部门名,返回该部门的平均工资。
CREATE FUNCTION myf3(deptName VARCHAR(20)) RETURNS DOUBLEBEGINDECLARE sal DOUBLE;SELECT AVG(salary) INTO salFROM employees eJOIN departments d ON e.department_id=d.department_idWHERE d.department_name = deptName;RETURN sal;END$ SELECT myf3('IT')$
3.函数的查看
SHOW CREATE FUNCTION myf3;
4.函数的删除
DROP FUNCTION myf3;
案例:创建函数,实现传入两个float,返回二者之和
delimiter $CREATE FUNCTION test4(num1 FLOAT ,num2 FLOAT) RETURNS FLOATBEGINDECLARE sum FLOAT DEFAULT 0;SET sum=num1+num2;RETURN sum;end$SELECT test4(1,2)$
进阶十八:流程控制结构
- 顺序结构:程序从上往下依次执行
- 分支结构:程序从两条或多条路径中选择一条去执行
- 循环结构:程序在满足一定条件的基础上,重复执行一段代码
1.分支结构
IF函数
功能:实现简单的双分支
语法:
IF(表达式1,表达式2,表达式3)执行顺序:如果表达式1成立,则返回2值,否则返回3值。
应用:任何地方
case结构
情况1:类似于Java中的switch语句,一般用于实现的等值判断
语法:
CASE 变量|表达式|字段WHEN 要判断的值 THEN 返回的值1或语句n1;WHEN 要判断的值 THEN 返回的值2或语句n2;...ELSE 要返回的值或者语句n;end CASE;
情况2:类似于Java中的多重if语句,一般用于实现区间判断
CASE WHEN 要判断的条件1 THEN 返回的值1或语句n1;WHEN 要判断的条件2 THEN 返回的值2或语句n2;...ELSE 要返回的值或语句nend CASE;
特点:
1.可以作为表达式,嵌套在其他语句中使用,可以放在任何地方, BEGIN END 中或begin END 的外面
可以作为独立的语句去使用,只能放在begin end中
2.如果when中的值满足或条件成立,则执行对应的then语句并且结束case,都不满足则执行else中的语句或值
3.else可以省略,如果else省略,并且所有的when条件都不满足,则返回null
if结构
功能:实现多重分支
语法:
if 条件1 then 语句1;ELSEIF 条件2 then 语句2;...【else 语句n;】END IF;
应用在begin end中
2.循环结构:
分类:while loop repeat
循环控制:
ITERATE 类似于continue ,继续
leave类似于break
while
语法:
【标签:】while循环条件 do循环体;end WHILE 【标签】;
LOOP
语法:
【标签:】LOOP 循环体;end LOOP 【标签】;#可以用来模拟简单的死循环
REPEAT
语法:
【标签:】repeat循环体;UNTIL 结束循环的条件end REPEAT 【标签】;
案例: 批量插入,根据次数插入到admin表中多条记录(没有添加循环控制语句)
delimiter $DROP PROCEDURE pro_while1$delimiter $CREATE PROCEDURE pro_while1(IN insertCount INT)BEGIN DECLARE i INT DEFAULT 1;WHILE i<=insertCount DOINSERT INTO admin(username,PASSWORD) VALUES(CONCAT('rose',i),'666');SET i=i+1;END WHILE; END $delimiter $CALL pro_while1(100)$SELECT * FROM admin$
添加leave语句
案例:批量插入,根据次数插入到admin表中多条记录,如果次数>20则停止
TRUNCATE TABLE admin$DROP PROCEDURE test_while1$delimiter $CREATE PROCEDURE test_while1(IN insertCount INT)BEGINDECLARE i INT DEFAULT 1;a:WHILE i<=insertCount DOINSERT INTO admin(username,PASSWORD) VALUES(CONCAT('re',i),'666');IF i>=20 THEN LEAVE a;END IF;SET i=i+1;END WHILE a;END$delimiter $CALL test_while1(50)$SELECT * FROM admin$
笔记到这里就结束了,希望您能通过本文的阅读,掌握数据库的基础知识。
笔者后面有时间也会将MySQL高级进阶笔记发出来,仅供大家学习。如果您觉得本文还不错,三连+关注一下我吧,我也会持续更新出高质量的文章。
B站MySQL(尚硅谷)学习笔记相关推荐
- Java 基础 第3阶段:高级应用——尚硅谷学习笔记(含面试题) 2023年
Java 基础 第 3 阶段:高级应用--尚硅谷学习笔记(含面试题) 2023 年 Java 基础 第 3 阶段:高级应用--尚硅谷学习笔记(含面试题) 2023 年 第 9 章 异常处理 9.1 异 ...
- SpringBoot(尚硅谷学习笔记)
1.SpringBoot优点(官网 spring.io) Create stand-alone Spring applications 创建独立Spring应用 Embed Tomcat, Jetty ...
- 8-zookeeper算法基础(尚硅谷学习笔记)
目录 拜占庭将军问题 paxos算法 paxos算法流程 情况一 情况二 情况1 情况2 ZAB协议 ZAB协议内容 消息广播 过程 可能出现的问题 崩溃恢复 异常假设 leader选举 数据恢复 C ...
- 尚硅谷学习笔记-节点的常用属性和方法
节点的常用属性和方法[图片在末尾] 方法: 通过具体的元素节点调用 getElementsByTagName() 方法,获取当前节点的指定标签名孩子节点 appendChild( oChildNode ...
- [React] 尚硅谷 -- 学习笔记(七)
第七章 react-ui 最流行的开源React UI组件库 material-ui(国外) 官网 GitHub ant-design(国内蚂蚁金服) PC官网 GitHub 移动官网 GitHub ...
- [React] 尚硅谷 -- 学习笔记(六)
第六章 react-router4 理解 react-router react的一个插件库 专门用来实现一个SPA应用 基于react的项目基本都会用到此库 SPA 单页Web应用(single pa ...
- [React] 尚硅谷 -- 学习笔记(五)
第五章 总结 组件间通信 通过props传递 共同的数据放在父组件上, 特有的数据放在自己组件内部(state) 通过props可以传递一般数据和函数数据, 只能一层一层传递 一般数据–>父组件 ...
- [React] 尚硅谷 -- 学习笔记(四)
第四章 react ajax 理解 React本身只关注于界面, 并不包含发送ajax请求的代码 前端应用需要通过ajax请求与后台进行交互(json数据) react应用中需要集成第三方ajax库( ...
- [React] 尚硅谷 -- 学习笔记(三)
第三章 react应用(基于react脚手架) 使用create-react-app创建react应用 react脚手架 xxx 脚手架:用来帮助程序员快速创建一个基于 xxx 库的模板项目 包含了所 ...
最新文章
- 【消息中间件】Spring Boot整合RabbitMQ
- Java Web Start入门基础教程
- mysql ado.net 实体数据模型_Visual Studio2017中如何让Entity Framework工具【ADO.NET实体数据模型】支持MYSQL数据源...
- Javascript 常见使用误区
- Aqara 2021发布会:万物互联的家庭智慧全景
- 通过Jinq简化数据库查询
- vs 和 rider 一决高下 结合开发dotnet应用
- win10出现的异常解决
- 嵌入式——嵌入式与单片机傻傻分不清
- 山东理工大学ACM平台题答案关于C语言 1181 C语言实验——最小公倍数和最大公约数...
- 用Python徒手撸一个股票回测框架!
- 下次激活策略10_陈金凌:年流量1-10万独立站关键词策略案例(1)
- 微信会员卡跳转小程序实现
- Web mfw Writeup
- 微信小程序 展示地图指定位置导航
- Word中插入手写体签名
- 浅谈技术管理之日式管理的殊途同归
- windows7蓝牙怎么打开_【windows7】IP地址查询方法
- HCIP笔记(13)
- 从neo4j-broswer中剥离graph图表
热门文章
- [STM32问题解决(1)]一类问题的解决办法——编译错误:XXX.axf: Error: L6218E: Undefined symbol xxx (referred from xxxx.o).
- keil5下载程序后提示“internal command error”
- 备战2021成龙电影节的院线电影《 完美情侣 》正式开拍
- tensorflow 二阶导数计算
- python按顺序遍历字典中的所有键_python中怎么遍历字典
- ipad怎样分屏_【工具】ZotExpert:实现iPad文献管理的无缝同步
- python爬取28万足球运动员数据,告诉你中国队为什么不能出线
- C17500铍钴铜棒C17500铍钴铜锻件C17500圆饼
- 集团货币金额与本位币金额不一致的原因及解决办法
- Excel如何按照要求将整行数据复制多行