MySQL基础笔记
写在前面,课程来自李玉婷老师。
1.初始MySQL
1.1 基本概念和操作
保存数据的容器
1.数组——内存
2.集合——内存
3.文件
……
数据库的好处
- 实现数据持久化
- 使用完整的管理系统统统管理,易于查询
数据库的相关概念
- DB ——– (Database):存储数据的“仓库”。它保存了一系列有组织的数据。
- DBMS—–(Database Management System)数据库是通过DBMS创建和操作的容器
- SQL——–(Structure Query Language)结构化查询语言,专门用来与数据库通信的语言
数据库存储数据的特点
1.将数据放到表中,表再放到库中
2.一个数据库中可以有多个表,每个表都有一个名字,用来标识自己。表名具有唯一性。
3.表具有一些特性,此些特性定义了数据库在表中如何存储,类似Java中“类”的设计。
4.表由列组成,即字段。所有表都是由一个或多个列组成的,每一个类似java中的“属性”。
5.表中是数据时按行存储的,每一行类似于java中的“对象”。
数据库服务端的登录和退出
登录:
方式1:
通过Windows自带的客户端
打开命令提示符,输入
mysql (-h主机名 -P端口号) -u用户名 -p密码
mysql -h localhost -P 3306 -u root -p
按回车以后输入密码
方式2:
mysql自带的客户端
只限于root用户
退出:
exit回车即可
mysql的常见命令
显示数据库:
show database;
ps:Database是系统自带的数据库,里面有4个库
information_shema——-存储源数据
mysql—————————存储用户数据
performance_schama—-存储姓名
test——————————-测试数据,暂时为空
进入仓库查看数据:
1.use 仓库名;
2.show tables;
例如 :use sys;
再如:
查看其他库的所有表
show tablas from mysql;
查看现在在哪个库里:
select database();
创建表:
语法:
1 | create table 表名( |
查看表结构:
desc 表名;
查看服务器版本:
方法1:先退出mysql,再输入:
1 | mysql -V; |
方法2:登录mysql,语法:
select version();
语法规范:
不区分大小写,但建议关键字大写,表名、列名小写
每条命令最好用分号结尾
每条命令可以根据需要进行缩进或换行
注释
单行注释:#注释文字
· 单行注释:– 注释文字(注意有空格)
多行注释:/* 注释文字 */#
2. DQL语言
2.1 基础查询
快速复制表:查询创建工具,勾选即可。(针对navicat用户)
1 |
|
执行:快捷键—-F9
查询时注意的细节:
需要打开某个库,再查询
语法:
USE 库名;
1
UES myemployee;
2.着重号:用于区分字段和关键字 ``其上档符号是“~ ”,使用Shift键可以换挡输入。
3.查询常量
1
2
3
4USE myemployees;
SELECT 'John'; #注意这里是单引号不是着重号!!!
SELECT 100;注意:字符型和日期型的常量值必须用单引号括起来
4.查询表达式
1
SELECT 100%98;
5.查询函数
1
SELECT VERSION();
6.起别名
1
2
3
4
5
6
7#方式一:使用as
SELECT 100%98 AS 结果;
SELECT last_name AS 姓,first_name AS 名 FROM employees;
#方式二:使用空格
SELECT last_name 姓,first_name 名 FROM employees;起别名的意义:
便于理解。
- 如果要查询的字段有重名的情况,使用别名可以区分开来。
1
2#如果别名中含有关键字或者空格或者"#",建议使用"括起来,如:
SELECT salary AS "OUT PUT" FROM employees;7.去重(即去除重复的字段)
不去重写法:
1
SELECT department_id FROM employees;
去重:加上关键字
DISTINCT
1
2#查询员工表中涉及到的所有的部门编号
SELECT DISTINCT department_id FROM employees;8.加号的作用:mysql中的加号只有一个功能:运算符
如果两个操作符都为整数值,则做加法运算
其一字符型,试图将字符型数值转换为数值型,若成功,就继续做加法运算,如果失败,则将字符型数值转换成0
只要其中一方为NULL,则结果为NULL
案例:查询员工名和姓连接成一个字段,并显示为姓名。
解决:引入关键字 CONCAT
1
2
3
4
5
6SELECT CONCAT('a','b','c') AS 结果;
SELECT
CONCAT(last_name,first_name) AS 姓名
FROM
employees;题目:显示出表employee的全部列,各个列之间用逗号隔连接,列头显示成out_put.
如果我们直接这样写:
1
2
3
4
5
6SELECT
CONCAT(employees.first_name,',',employees.last_name,',',employees.job_id,',',employees.commission_pct) AS OUT_PUT
FROM
employees结果如下:
可以看到,即使有些地方commission_pct不等于NULL,结果也全为NULL了。
解决办法:引入IFNULL函数
函数原型:ifnull(expr1,expr2)
expr1是可能为NULL的值,expr2是假如expr1真的为NULL了,你所期待函数返回的值。
正确写法:
1
2
3
4
5
6SELECT
CONCAT(employees.first_name,',',employees.last_name,',',employees.job_id,',',IFNULL(employees.commission_pct,0)) AS OUT_PUT
FROM
employees查询后可以从结果看出
即使有时利息为0,但奖金不为0,都可以正常显示
2.2 条件查询
语法:
1 | SELECT |
分类:
按条件表达式筛选
条件运算符:> < = != <> >= <=
按逻辑表达式筛选
&& || !
and or not
模糊查询
like,between and in is null
特点:一般和通配符搭配使用。
通配符:
% 任意多个字符,包含0个字符
_ 任意单个字符
1.按条件表达式式筛选
案例1:查询工资>12000的员工信息
1 | SELECT |
案例2:查询部门编号不等于90号的员工和部门编号
1 | SELECT |
2.按逻辑表达式筛选
案例1:查询工资在10000到20000之间的员工名、工资以及奖金
1 | SELECT |
案例2:查询部门编号不是在90到110之间,或者工资高于15000的员工信息
1 | SELECT |
3.模糊查询
like
案例1:查询员工名中包含字符a的员工信息
1 | SELECT |
案例2:查询员工名中第三个字符为n,第五个字符为l的员工名和工资
1 | SELECT |
案例3:查询员工中第二个字符为_的员工名
1 | SELECT |
between and—–提高语句简洁度,包含临界值,临界值不能交换位置
案例1:查询员工编号在100到120之间的员工信息
1 | SELECT |
in——–判断某字段的值是否属于in列表中的某一项
特点:
- 使用in提高语句简洁度
- in列表的值类型必须是一致或兼容(不支持通配符)
案例:查询员工的工种编号是 IT_PROG、AD_VP、AD_FRES中的一个员工名和工种编号
1 | #普通写法 |
is null
注意:
- =或<>不能用于判断null值
- is nulll 或 is not null 可以判断null值
案例1:查询没有奖金的员工名和奖金率
1 | SELECT |
案例2:查询有奖金的员工名和奖金率
1 | SELECT |
补充:
安全等于 <=> ——–用来判断是否相等
案例1:查询没有奖金的员工名和奖金率
1 | SELECT |
案例2:查询工资为12000的员工信息
1 | SELECT |
is null 和 <=> 的区别
- is null:仅仅可以判断null值,可读性较高,建议使用
- <=> : 既可以判断null值, 又可以判断普通数值,可读性较低
案例:查询员工号为176的员工的姓名和部门号和年薪
1 | SELECT |
2.3 排序查询
语法:
1 | select 查询列表 |
ps:
- asc代表升序,desc代表降序。如果不写,默认是升序。
- oder by子句中可以支持单个字段,多个字段,表达式,函数,别名
- oder by一般放在查询语句的最后面,但limit子句除外
案例1:查询员工信息,要求工资从高到低排序
1 | SELECT * FROM employees ORDER BY salary DESC; |
案例2:查询员工信息,要求工资从低到高排序
1 | SELECT * FROM employees ORDER BY salary ASC; #(或省略ASC) |
案例3:查询部门编号>=90的员工信息,按入职时间的先后进行排序。
1 | SELECT * FROM employees WHERE department_id>=90 ORDER BY ASC; |
案例4:按年薪的高低显示员工的信息和和年薪———-按表达式排序
1 | SELECT *,salary*12*(1+IFNULL(commission_pct,0)) AS 年薪 |
案例5:按年薪的高低显示员工的信息和和年薪———-按别名排序
1 | SELECT *,salary*12*(1+IFNULL(commission_pct,0)) AS 年薪 |
案例6:按姓名的长度显示员工的姓名和工资————-按函数排序
1 | SELECT LENGTH(last_name) as 字节长度,last_name,salary |
案例7:查询员工信息,要求先按工资排序,再按员工编号降序————按多个字段排序
1 | SELECT * |
2.4 常见函数
概念:类似于java中的方法,将一组逻辑语句封装在方法体中,对外暴露方法名
好处:
- 隐藏了实现细节
- 提高代码的重用性
调用:select 函数名() [from 表];
特点:
- 叫什么(函数名)
- 干什么(函数功能)
分类:
- 单行函数,eg:concat,length,ifnull等
- 分组函数
- 功能:做统计使用,又称为统计函数,聚合函数,组函数
2.4.1 字符函数
- length——-获取参数值的字节个数
1 | SELECT LENGTH('john'); #返回值4个字节 |
- concat——拼接字符串
1 | SELECT CONCAT(last_name,'_',first_name) FROM employees; |
3.upper、lower
1 | SELECT UPPER('john'); |
示例:将姓变大写,名变小写,然后拼接
1 | SELECT CONCAT(UPPER(last_name),LOWER(first_name)) 姓名 FROM employees; |
4.substr、substring——-截取字符
1 | SELECT SUBSTR('花花的世界',4) out_put; #截取从索引处后面所有字符 |
ps: sql语言索引从1开始
输出:
结果1 结果2
out_put out_put
世界 花花
案例:姓名中首字符大写,其他字符小写然后用_拼接,显示出来
1 | SELECT CONCAT(UPPER(SUBSTR(last_name,1,1)),'_',LOWER(SUBSTR(last_name,2))) out_put FROM employees; |
5.instr——-返回子串第一次出现的索引,提供找不到返回0
1 | SELECT INSTR('我爱米切氏凤头鹦鹉','鹦鹉') AS out_put; #返回8 |
6.trim
1 | SELECT LENGTH(TRIM(' 花花 ')) as out_put; #返回6,说明去掉了空格 |
7.lpad——–用指定的字符实现左填充指定长度
1 | SELECT LPAD('花花',10,'*') as out_put; #输出:********花花(总共10个字符) |
8.rpad——-用指定的字符实现右填充指定长度
1 | SELECT RPAD('花花',12,'ab') as out_put; #输出:花花ababababab |
9.replace——替换
1 | SELECT REPLACE('我爱惨了鹦鹉鹦鹉鹦鹉','鹦鹉','二哈') as out_put; #输出:我爱惨了二哈二哈二哈 |
2.4.2 数学函数
1.round—–四舍五入
1 | SELECT ROUND(-1.55); #输出: -2 |
2.ceil——向上取整,返回>=该参数的最小整数
1 | SELECT CEIL(-1.02); #输出结果:-1 |
3.floor—向下取整,返回<=该参数的最大整数
1 | SELECT FLOOR(9.99); #输出结果:9 |
4.truncate—–截断
1 | SELECT TRUNCATE(1.699999999,1); #输出结果:1.6 |
参数表示保留几位小数
5.mod———–取余
1 | SELECT MOD(10,-3); #结果:1 |
ps:mod(a,b)的运算: a-a/b*b
2.4.3 日期函数
- now 返回当前系统日期+时间
1 | SELECT NOW(); |
- curdate 返回当前系统日期,不包含时间
1 | SELECT CURDATE(); |
- curtime 返回当前时间,不包含日期
1 | SELECT CURTIME(); |
- 可以获取指定的部分,年,月,日,小时,分钟,秒
1 | SELECT YEAR(now()) 年; |
- 获取英文的月份
1 | SELECT MONTHNAME(NOW()) 月; |
out_put:
月
February
- 日期转换为特定格式
序号 | 格式符 | 功能 |
---|---|---|
1 | %Y | 四位的年份 |
2 | %y | 二位的年份 |
3 | %m | 月份(01,02,…11,12) |
4 | %c | 月份(1,2,…11,12) |
5 | %d | 日(01,02…) |
6 | %H | 小时(24小时制) |
7 | %h | 小时(12小时制) |
8 | %i | 分钟(00,01…59) |
9 | %s | 秒(00,01,…59) |
1.str_to_date 将日期格式的字符转换成指定格式的日期
2021-02-18
1 | SELECT STR_TO_DATE('2021-2-18','%Y-%m-%d') AS out_put; |
2.date_format 将日期转换成字符————-2021年02月18日
1 | SELECT DATE_FORMAT(NOW(),'%y年%m月%d日') AS out_put; |
#查询有奖金的员工名和入职日期(xx月/xx日 xx年)
1 | SELECT last_name,DATE_FORMAT(hiredate,'%m月%d日 %y年') 入职日期 |
2.4.4 其他函数
1 | SELECT VERSION();#当前数据库服务器的版本 |
2.4.5 流程控制函数
- if函数:if else 效果
1 | SELECT IF(10<5,'大','小'); |
- case 函数的使用一:switch case 效果
语法:case 要判断的字段或表达式
when 常量1 then 要显示的值1或语句1
when 常量2 then 要显示的值2或语句2
…
else 要显示的值n或语句n;
end
案例:查询员工工资,要求
部门号=30,显示的工资为1.1倍
部门号=40,显示的工资为1.2倍
部门号=50,显示的工资为1.3倍
其他部门,显示的工资为原工资
1 | SELECT salary 原始工资,department_id, |
- case函数的使用二:类似于 多重if
语法:case
when 条件1 then 要显示的值1或语句1
when 条件2 then 要显示的值2或语句2
…
eles 要显示的值n或语句n;
end
案例:查询员工的工资情况
如果工资>20000,显示A级别
如果工资>15000,显示B级别
如果工资>10000,显示C级别
否则,显示D级别
1 | SELECT salary, |
2.5 分组函数
分类:
sum 求和
avg 平均值
max 最大值
min 最小值
count 计算个数
1.简单使用
1 | SELECT SUM(salary) FROM employees; |
2.参数类型
特点:
sum,avg一般用于处理数值型
MAX,MIN、COUNT可以处理任何类型
3.是否忽略null值
- 以上分组函数均忽略null值
4.和distinct搭配
1 | SELECT SUM(DISTINCT salary),SUM(salary) FROM employees; |
5.count函数的详细介绍
统计行数
1 | SELECT count(*) FROM employees; |
效率:
MYISAM存储引擎下,count(*)效率高
INNODB存储引擎下,count(*)和count(1)效率差不多,比count(字段)要高
6.和分组函数一同查询的字段有限制
和分组函数一同使用的字段要求是group by后的字段
2.6 分组查询
语法:
select 分组函数,列(要求出现在group by后面)
from 表
【where 筛选条件】
group by 分组的列表
【order by 字句】
PS:要求查询列表必须特殊,要求是分组函数和group by后面出现的字段
特点:
- 分组查询中的筛选条件分为两类
数据源 | 位置 | 关键字 | |
---|---|---|---|
分组前筛选 | 原始表 | group by子句前面 | where |
分组后筛选 | 分组后的结果表 | group by子句后面 | having |
- 分组函数做条件一定要放在having子句中
- 能用分组前筛选优先分组前筛选
- group by子句支持单个字段分组,多个字段分组(多个字段之间用逗号隔开没有顺序要求)
- 也可以添加排序(排序放在整个分组查询的最后)
1.简单查询
案例:查询每个工种的最高工资
1 | SELECT MAX(salary),job_id |
案例2:查询每个位置上的部门个数
1 | SELECT COUNT(*),location_id |
2.添加筛选条件
案例:查询邮箱中包含a字符的,每个部门的平均工资
1 | SELECT AVG(salary),department_id |
案例2:查询有奖金的每个领导手下员工的最高工资
1 | SELECT MAX(salary),manager_id |
3.添加复杂的筛选条件
案例:查询哪个部门的员工个数>2
1 | #先查询每个部门的员工个数 |
案例2:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
1 | SELECT MAX(salary),job_id |
案例3:查询领导编号>102的每个领导手下的最低工资>5000的领导编号,以及最低工资
1 | SELECT MIN(salary),manager_id |
4.按表达式或函数分组
案例:按员工姓名的长度分组,查询每一个员工个数,筛选员工个数>5的有哪些
1 | SELECT COUNT(*),LENGTH(last_name) len_name |
5.按多个字段进行分组
案例:查询每个部门每个工种的员工平均工资
1 | SELECT AVG(salary),department_id,job_id |
6.添加排序
案例:查询每个部门每个工种的员工平均工资,并按平均工资的高低显示
1 | SELECT AVG(salary),department_id,job_id |
2.7 连接查询
别称:多表查询。当查询的字段来自多个表时,就会用到连接查询
笛卡尔乘积现象:表1 有m行,表2有n行,结果=m*n行
发生原因:没有有效的连接条件
避免措施:添加有效的连接条件
1 | SELECT NAME,boyName FROM boys,beauty |
分类:
按年代分类:
sq192标准:仅仅支持内连接
sq199标准:[推荐]支持内连接,外连接(左外和右外)+交叉连接
按功能分类:
内连接 | 外连接 | 交叉连接 |
---|---|---|
等值连接 | 左外连接 | 交叉连接 |
非等值连接 | 右外链接 | |
自连接 | 全外连接 |
sq192标准
1.等值连接
特点:
- 多表等值连接的结果为多表的交集部分
- n表连接,至少需要n-1个连接条件
- 一般需要为表 起别名
- 可以搭配前面介绍的所有子句使用,比如排序,分组,筛选
案例:查询女孩名和对应的男孩名
1 | SELECT NAME,boyName |
2.为表起别名
优点:
- 提高语句的简洁度
- 区分多个重名的字段
ps:如果为表起了别名,则查询的字段就不能使用原来的表名去限定
案例2:查询员工名和对应的部门名
1 | SELECT e.last_name,e.job_id,job_title |
3.两个表的顺序可以调换
案例:上述案例
1 | SELECT e.last_name,e.job_id,job_title |
3.可以加筛选
案例:查询有奖金的员工名,部门名
1 | SELECT last_name,department_name,commission_pct |
案例2:查询城市名中第二个字符为o的部门名和城市名
1 | SELECT city,department_name |
5.可以分组
案例1:查询每个城市的部门个数
1 | SELECT COUNT(*) 个数,city |
案例2:查询有奖金的每个部门的部门名和部门的领导编号和该部门的最低工资
1 | SELECT department_name,d.manager_id,MIN(salary) |
6.可以加排序
案例:查询每个工种名和员工的个数,并且按员工个数降序
1 | SELECT job_title,COUNT(*) |
7.可以实现三表连接
查询:查询员工名、部门名和所在城市
1 | SELECT last_name,department_name,city |
在此基础上可以继续追加筛选和排序
1 | AND city like 's%'; |
非等值连接
案例:查询员工的工资和工资级别
1 | SELECT salary,grade_level |
3.自连接
案例:查询员工名和上级的名称
1 | SELECT e.employee_id,e.last_name,m.employee_id,m.last_name |
sq199语法
语法:
select 查询列表
from 表1 别名 【连接类型】
join 表2 别名
on 连接条件
【where 筛选条件】
【group by 分组】
【having 筛选条件】
【order by 排序条件】
分类:
内连接 | inner | |
---|---|---|
外连接 | 左外 | left[outer] |
右外 | right[outer] | |
全外 | full[outer] | |
交叉连接 | cross |
(1)内连接
语法:
select 查询列表
from 表名1 别名
inner join 表2 别名
on 连接条件
1.等值连接
特点:
- 添加排序、分组、筛选
- inner可以省略
- 筛选条件放在where后面,连接条件放在on后面,提高分离性,便于阅读
- inner join连接和sq192语法中的等值连接效果一样,都是查询多表的交集
案例1:查询员工名,部门名
1 | SELECT last_name,department_name |
案例2:查询名字中包含e的员工名和工种名(添加筛选)
1 | SELECT last_name,job_title |
案例3:查询部门个数>3的城市和部门个数(添加+筛选)
1 | SELECT city,COUNT(*) 部门个数 |
案例4:查询哪个部门的 员工个数>3的部门名和员工个数,并按个数降序
1 | SELECT department_name,count(*) 员工个数 |
案例5:查询员工名、部门名、工种名、并按部门名降序()—-多表连接
1 | SELECT last_name,department_name,job_title |
2. 非等值连接
#查询员工的工资级别
1 | SELECT salary,grade_level |
#查询员工的工资级别个数>20的个数,并且按工资级别降序
1 | SELECT count(*),grade_level |
- #查询姓名中包含字符k的员工姓名、上级的名字
1 | SELECT e.last_name,m.last_name |
(2)外连接
应用场景:用于查询一个表中有,另一个表没有的记录
特点:
外连接的查询结果为主表中的所有记录,如果从表中有和它匹配的,则显示匹配的值;否则,显示null
外连接查询结果=内连接结果+主表中有而从表没有的记录
左外连接,left join左边的是主表
右外连接,right join右边的是主表
左外和右外交换两个表的顺序,可以实现同样的效果
全外连接=内连接的结果+表1有的但表2没有的+表2有的但表1没有的
案例:查询男朋友不在男神表的女神名字
左外连接:
1 | SELECT b.`name` |
右外连接:
1 | SELECT b.`name` |
案例:查询哪个部门没有员工
1 | SELECT d.*,e.employee_id |
全外连接:
1 | SELECT b.*,bo.* |
交叉连接:
1 | SELECT b.*,bo.* |
总结之sq192和sql99异同:
功能:sql99支持的较多
可读性:sql99实现连接条件和筛选条件的分离,可读性较高
补充案例:
查询编号>3的女神的男朋友信息,如果有则列出,没有用null填充
1 | SELECT b.id,b.`name`,bo.* |
2.7 子查询
概念:
出现在其他语句中的select语句,称为子查询或内查询
外部的查询语句,称为主查询或外查询
分类:
按子查询出现的位置
select后面 | from后面 | where或having(☆) | exists后面(相关子查询) |
---|---|---|---|
仅仅支持标量子查询 | 支持表子查询 | 标量子查询(单行) | 表子查询 |
列子查询(多行) | |||
行子查询 |
按结果的行列不同:
- 标量子查询(结果集只有一行一列)
- 列子查询(结果集只有一行多列)
- 行子查询(结果集只有一行多列)
- 表子查询(结果集一般为多行多列)
where或having后面
1.标量子查询(单行子查询)
2.列子查询(多行子查询)
3.行子查询(多行多列)
特点:
- 子查询放在小括号内
- 子查询一般放在条件右侧
- 标量子查询,一般搭配着单行操作符使用(> < >= <= = <> )
- 列子查询,一般搭配着多行操作符使用(in,any/some,all)
2.7.1.标量子查询
案例1:谁的工资比Abel高?
第一步:查询Abel的工资
1 | SELECT salary |
第二步:查询满足的员工信息,满足salary>第一步结果
1 | SELECT * |
案例2:返回job_id与141号员工相同,salary比143号员工多的员工姓名,job_id和工资
第一步:查询141号员工的job_id
1 | SELECT job_id |
第二步:查询143号员工的工资
1 | SELECT salary |
第三步:查询员工的姓名,job_id和工资,要求……
1 | SELECT last_name,job_id,salary |
2.7.2.列子查询(多行)
案例:返回location_id是1400或1700的部门中的所有员工姓名
①查询location_id是1400或1700的部门编号
1 | SELECT department_id |
②查询员工姓名,要求部门号是①列表中的某一个
1 | SELECT last_name |
案例2:返回其他工种中比job_id为IT_PROG
工种任一工资低的员工的员工号,姓名,job_id以及salary
①查询job_id为IT_PROG
部门任一工资
1 | SELECT DISTINCT salary |
②查询员工号、姓名、job_id以及salary,salary<①的任一一个
1 | SELECT last_name,employee_id,salary |
案例3:返回其他工种中比job_id为IT_PROG
工种所有工资低的员工的员工号,姓名,job_id以及salary
1 | SELECT last_name,employee_id,salary |
2.7.3.行子查询
ps:用得少,但是面试会问
案例:查询员工编号最小并且工资最高的员工信息
之前的方式:
①查询最小的员工编号
1 | SELECT MIN(employee_id) |
②查询最高工资
1 | SELECT MAX(salary) |
③查询员工信息
1 | SELECT * |
新的方式:
1 | SELECT * |
select后面
案例:查询每个部门的员工个数
1 | SELECT d.*,( |
案例:查询员工号=102的部门名
1 | SELECT ( |
可以用连接查询写
from后面
ps:将子查询的结果充当一张表,要求必须起别名
案例:查询每个部门的平均工资的工资等级
①查询每个部门的平均工资
②连接①的结果和hob_grades表,筛选条件平均工资
1 | SELECT agb.*,g.grade_level |
exists后面
—–(相关子查询)
简单语法:
exitsts(完整的查询语句)
结果:1 or 0
案例1:查询有员工的部门名
1 | SELECT department_name |
案例2:查询没有女朋友的男神信息
1 | #in |
2.7.1 分页查询
应用场景:当要显示的数据,一页显示不全,需要分页提交sql请求
语法:
select 查询列表
from 表
【join type join 表2
where 筛选条件
group by 分组字段
order by 排序的字段】
limit offset,size;
- offset要显示条目的起始索引(起始索引从0开始)
- size要显示的条目个数
特点:
limit语句放在查询语句的最后
公式:
要显示的页数page,每页的条目数size
select 查询列表
from 表
limit (Page-1)*size,size;
案例1:查询前五条员工信息
1 | SELECT * FROM employees LIMIT 0,5; |
案例2:查询第11条—-第25条
1 | SELECT * FROM employees LIMIT 10,15; |
案例3:查询有奖金的员工信息,并且工资较高的前10名显示出来
1 | SELECT * |
案例4:查询平均工资最低的部门信息
①查询各部门的平均工资
1 | SELECT AVG(salary),department_id |
②求出最低平均工资的部门编号
1 | SELECT department_id |
③查询部门信息
1 | SELECT * |
案例:查询平均工资最低的部门信息和该部门的平均工资
①查询各部门的平均工资
1 | SELECT AVG(salary),department_id |
②求出最低平均工资的部门编号
1 | SELECT AVG(salary),department_id |
③查询部门信息
1 | SELECT d.*,ag |
2.7.2 union联合查询
联合:将多条查询语句的结果合并成一个结果
语法:
查询语句1
union
查询语句2
union
应用场景:
要查询的结果来自多个表,且多个表没有直接的连接关系,但查询的信息一致时
特点:
- 要求多条查询语句的查询列数是一致的
- 要求多条查询语句的每一列的类型和顺序最好是一致的
- union关键字默认去重,如果使用union all可以包含重复项
案例:查询中国用户中男性的信息以及外国用户中年男性的用户信息
1 | SELECT id,cname,csex FROM t_ca WHERE csex='男' |
ps:两表没有关联
3. DML语言
简介:数据库操作语言
包含:
插入:insert
修改:update
删除:delete
3.1 插入语句
方式一:
语法:
insert into 表名(列名,……)value(值1,……);
1.插入的值的类型要与列的类型一致或兼容
例如:
1 | INSERT INTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id) |
2.不可以为null的列必须插入值
3.可以为null的列如何插入值?
way one:直接写null,如上例
way two:列不写,值也不写,如下
1 | beauty(id,NAME,sex,borndate,phone,boyfriend_id) |
4.列的顺序可以调换
5.列数和值的个数必须一致
6.可以省略列名,默认所有列,而且列的顺序和表中的顺序一致
1 |
方式2:
语法:
insert into 表名
set 列名=值,…
eg:
1 | INSERT INTO beauty |
两种方式对比:
1.方式一支持插入多行,方式二不支持
eg:
1 | INSERT INTO beauty |
2.方式一支持子查询,方式二不支持
eg:
1 | INSERT INTO beauty(id,NAME,phone) |
eg:
1 | INSERT INTO beauty(id,NAME,phone) |
3.2 修改语句
1.修改单表的记录
语法:
update 表名
set 列=新值,列=新值,……
where 筛选条件;
2.修改多表的记录
示例:
1.修改单表的记录
案例1:修改beauty表中姓王的女神的电话为13899888899
1 | UPDATE beauty SET phone='13899888899' |
案例2:
1 | UPDATE boys SET boyname='张飞',usercp=1000 |
2.修改多表记录
sql92语法:
update 表1 别名,表2 别名
set 列=值,……
where 连接条件
and 筛选条件;
sql99语法:
update 表1 别名
inner|left|right join 表2 别名
on 连接条件
set 列=值,……
where 筛选条件;
案例1:修改张无忌的女朋友的手机号为114
1 | UPDATE boys bo |
案例2:修改没有男朋友的女神的男朋友编号都为2号
1 | UPDATA boys bo |
3.3 删除语句
方式一:delete
语法:
1.单表的删除★
delete from 表名 where 筛选条件
案例:删除手机号以9结尾的女神信息
1 | DELETE FROM beauty WHERE phone LIKE '%9'; |
2.多表的删除
sql92语法:
delete 表1的别名,表2的别名
from 表1 别名,表2 别名
where 连接条件
and 筛选条件;
sql99语法:where 表1的别名,表2的别名
inner|left|right join 表2 别名 on 连接条件
where 筛选条件;
案例:删除张无忌的女朋友信息
1 | DELETE b |
案例2:删除黄晓明的信息以及他女朋友的信息
1 | DELETE bo,b |
方式二:truncate
语法:truncate table 表名;
案例:将魅力值打与100的男神信息删除
1 | TRUNCATE TABLE boys;#一删全删,用来清空表的 |
总结:delete和truncate区别
- delete可以加where条件,truncate不能加
- truncate删除,效率高一点点
- 假如要删除的表中有自增长列,如果用delete删除后,再插入数据,自增长列的值从断点开始,而truncate删除后,再插入数据,自增长列的值从1开始
- truncate删除没有返回值,delete删除有返回值
- truncate删除不能回滚,delete删除可以回滚
ps:自增长列在后面会详细讲解
4. TCL语言
Transation Control Language 事务控制语言
事务:
一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行。
事务的ACID(acid)属性
1.原子性(Atomicity)
原子性是指事务一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
2.一致性(Consistency)
事务性必须使数据库从一个一致性状态变换到另外一个一致性状态。
3.隔离线(isolation)
事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
4.持久性(Durability)
持久性是指一个事务一旦改变,它对数据库中的数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响
4.1 事务的创建
- 隐式事务:事务没有明显的开启和结束的标记
比如:insert、update、delete语句
- 显示事务:事务具有明显的开启和结束的标志
前提:必须先设置自动提交功能为禁用
设置禁用:
1 | SET autocommit=0; |
显示事务书写:
步骤1:开启事务:
set autocommit=0;
start stransaction;(非必须)
步骤2:编写事务中的sql语句(select insert update delete)
语句1;
语句2;
…
步骤3:结束事务
commit;提交事务
rollback;回滚事务
示例:
1 | #准备工作: |
delete和truncate在事务使用时的区别
1 | #演示delete |
总结:delete支持回滚,而truncate不支持
savepoint 结点名;设置保存点
事务的隔离级别:
脏读 | 不可重复读 | 幻读 | |
---|---|---|---|
read uncommitted | √ | √ | √ |
read committed | × | √ | √ |
repeatable read | × | × | √ |
serializable | × | × | × |
mysql中默认第三个隔离级别 repeatable read
Oracle默认第二个隔离级别 read committed
设置隔离级别
set session|global transaction isolation level 隔离级别;
展示当前隔离机制:
select @@transaction_isolation;
设置当前的mySQL连续的隔离级别:
set transaction isolation level read committed;
设置数据库系统的全局的隔离级别:
set global transaction isolation level read committed;
4.2 视图
含义:虚拟的表,和普通表一样使用,是通过表动态生成的数据,只保存sql逻辑,不保存查询结果
比如:舞蹈班和普通班的对比
视图vs表
创建语法的关键字 | 是否实际占用物理空间 | 使用 | |
---|---|---|---|
视图 | create view | 只保存了sql逻辑 | 增删改查,一般不能增删改 |
表 | create table | 保存了数据 | 增删改查 |
应用场景:
- 多个地方用到同样的查询结果
- 该查询结果使用的sql语句较复杂
案例:查询姓张的学生名和专业名
1 | #以前 |
创建视图
语法:
create view 视图名
as
查询语句;
特点:
- 重用sql语句
- 简化复杂的sql语句,不必 知道它的查询细节
- 保护数据,提高安全性
案例1:查询员工名包含a字符的员工名、部门名和工种信息
1 | #①创建 |
案例2:查询每个部门平均工资对应的工资等级
1 | #创建视图查看每个部门的平均工资 |
案例3:查询平均工资最低的部门信息
1 | SELECT * FROM myv2 ORDER BY ag LIMIT 1; |
案例4:查询平均工资最低的部门名和工资
1 | #myway: |
视图的修改
方式一:
create or replace view 视图名
as
查询语句;
示例:
1 | CREATE OR REPLACE VIEW myv3 |
方式二:
语法:
alter view 视图名
as
查询语句;
示例:
1 | ALTER VIEW myv3 |
删除视图
语法:
drop view 视图名、视图名,…
示例:
1 | DROP VIEW myv1,myv2,myv3; |
查看视图
1 | DESC myv3; |
视图的更新
1.插入
1 | INSERT INTO myv1 VALUES('张飞','zf@qq.com'); |
ps:连原表employees的数据一起更新了
2.修改
1 | INSERT INTO myv1 VALUES('张飞','zf@qq.com'); |
ps:也是连原始表一起更新了
3.删除
1 | DELETE FROM myv1 WHERE last_name='张无忌'; |
具备以下特点的视图不允许更新:
1.包含关键字的sql语句:分组函数,distinct、group by、having、union或者union all
2.常量视图
3.select中包含子查询
4.join
5.from一个不能更新的视图
6.where字句中的子查询引用了from字句中的表
5. 变量
分类:
系统变量 | 自定义变量 |
---|---|
全局变量、会话变量 | 用户变量、局部变量 |
5.1 系统变量
ps:变量由系统提供,不是用户定义,属于服务器层面
使用语法:
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
全局变量
说明:
作用域:服务器每次启动将为所有的全局变量赋初始值,针对于所有的会话有效,但不能跨重启
查看所有的全局变量
1 | SHOW GLOBAL VARIABLES; |
查看部分的全局变量
1 | SHOW GLOBAL VARIABLES LIKE '%char%'; |
查看指定的全局变量的值
1 | SELECT @@global.autocommit; |
为某个全局变量赋值
1 | SET @@global.autocommit=0;#跨连接有效 |
会话连接
作用域:仅仅针对于当前会话(连接)有效
查看所有的会话变量
1 | SHOW (SESSION) VARIABLES; |
查看指定的某个会话变量
1 | SHOW SESSION VARIABLES LIKE '%char%'; |
查看指定的某个会话变量
1 | SELECT @@transaction_isolation; |
为某个会话变量赋值
1 | #方式一 |
自定义变量
说明:变量是用户自定义的,不是由系统定义的
使用步骤:
1.声明2.赋值3.使用(查看、比较、运算等)
用户变量
作用域:针对于当前会话(连接)有效,同于会话变量的作用域
应用场合:应用在任何地方,在begin end内也可以在begin end外
赋值的操作符:=或:=
①声明并初始化
SET @用户变量名=值;或
SET @用户变量名:=值;或
SELECT @用户变量名:=值;
②赋值(更新用户变量的值)
方式一:通过SET或SELECT
SET @用户变量名=值;或
SET @用户变量名:=值;或
SELECT @用户变量名:=值;
方式二:通过SELECT INTO
SELECT 字段 INTO 变量名
FROM 表;
③使用(查看用户变量的值)
SELECT @用户变量名;
案例:
1 | #声明并初始化 |
局部变量
作用域:仅仅定义在它的begin end中有效
应用场合:应用在begin end中的第一句话
①声明
DECLARE 变量名 类型;
declare 变量名 类型 DEFAULT 值;
②赋值
方式一:通过SET或SELECT
SET 局部变量名=值;或
SET 局部变量名:=值;或
SELECT @局部变量名:=值;
方式二:通过SELECT INTO
SELECT 字段 INTO 局部变量名
FROM 表;
③使用
SELECT 局部变量名;
对比用户变量和局部变量
作用域 | 定义和使用的位置 | 语法 | |
---|---|---|---|
用户变量 | 当前会话 | 会话中的任何地方 | 必须加@符号,不用限定类型 |
局部变量 | BEGIN END中 | 只能在BEGIN END中,且为第一句话 | 一般不用加@符号,需要限定类型 |
案例:声明两个变量并赋初值,求和,并打印
1 | #1.用户变量 |
6. 存储过程和函数
存储过程和函数
含义:类似于java中的方法
好处:
1.提高代码的重用性
2.简化操作
存储过程
含义:一组预先编译好的SQL语句的集合,理解成批处理语句
好处:
1.提高代码的重用性
2.简化操作
3.减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率
一、创建语法
CREATE PROCEDURE 存储过程名(参数列表)
BEGIN
存储过程体(一组合法的SQL语句)
END
ps:
1.参数列表包含三部分(参数模式 参数名 参数类型)
eg:
1 | IN stuname VARCHAR(20); |
2.参数模式:
IN: 该参数可以作为输入,也就是该参数需要调用方法传入值
OUT: 该参数可以作为输出,也就是该参数可以作为返回值
INOUT:该参数既可以作为输入又可以作为输出
3.如果存储过程体仅仅只有一句话,BEGIN END 可以省略
存储过程体中每条SQL语句的结尾要求必须加分号
存储过程的结尾可以使用DELIMITER 重新设置
语法:
DELIMITER 结束标记
案例:
1 | DELIMITER $ |
二、调用语法
CALL 存储过程名(实参列表);
1.空参列表
案例:插入到admin表中五条记录
1 | SELECT * FROM admin; |
2.创建一个带in模式参数的存储过程
案例:创建存储过程实现 根据女神名,查询对应的男神信息
1 | CREATE PROCEDURE myp2(IN beautyName VARCHAR(20)) |
案例:创建存储过程实现:用户是否登录成功
1 | DELIMITER W |
案例:根据女神名返回对应的男神名
1 | CREATE PROCEDURE myp5(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20)) |
案例:根据女神名,返回对应的男生名和男神魅力值
1 | CREATE PROCEDURE myp6(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT userCP INT) |
4.创建带inout模式参数的存储过程
案例:传入a,b两个值,最终a和b都翻倍并返回
1 | CREATE PROCEDURE myp8(INOUT a INT,INOUT b INT) |
删除存储过程
语法:drop procedure 存储过程名
1 | DROP PROCEDURE p1; |
查看存储过程的信息
1 | SHOW CREATE PROCEDURE myp2; |
案例:
1 | #创建存储过程或函数实现传入一个日期,格式化为××年××月××日 |
函数
含义:一组预先编译好的SQL语句的集合,理解成批处理语句
好处:
1.提高代码的重用性
2.简化操作
3.减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率
区别:
存储过程:可以有0个返回值,也可以有多个返回,适合做批量插入、批量更新
函数:有且仅有一个返回值,适合做处理数据后返回一个结果
创建语法:
CREATER FUNCTION 函数(参数列表) RETURN<u>S</u> 返回类型
BEGIN
函数体
END
ps:
1.参数列表包含:函数名、函数类型
2.函数体:一定要有return语句,如果没有会报错。
3.函数体中仅有一句话,则可以省略begin end
4.使用delimiter语句设置结束标记
调用语法:
select 函数名(参数列表)
1.无参有返回值
案例:返回公司的员工个数
1 | set global log_bin_trust_function_creators=1; |
2.有参有返回
案例:根据员工名,返回它的工资
1 | CREATE FUNCTION myf2(empName VARCHAR(20)) RETURNS DOUBLE |
案例:根据部门名,返回该部门的平均工资
1 | CREATE FUNCTION myf3(deptName VARCHAR(20)) RETURNS DOUBLE |
查看函数
1 | SHOW CREATE FUNCTION myf3; |
删除函数
1 | DROP FUNCTION myf3; |
案例:创建函数,实现传入两个float,返回二者之和
1 | CREATE FUNCTION test_fun1(num1 FLOAT,num2 FLOAT) RETURNS FLOAT |
7. 流程控制结构
分类:
顺序结构:程序从上往下依次 执行
分支结构:程序从两条或多条路径中选择一条去执行
循环结构:程序在满足一定条件的基础上,重复执行一段代码
7.1 分支结构
1.if函数
功能:实现简单的双分支
语法:
IF(表达式1,表达式2,表达式3)
执行顺序:
如果表达式1成立,则if函数返回表示式2的值,否则返回表达式3的值
应用:任何地方
2.case结构
情况1:类似于java中的switch语句,一般用于实现等值判断
语法:
CASE 变量|表达式|字段
WHEN 要判断的值 THEN 返回的值1或语句2
;
WHEN 要判断的值 THEN 返回的值2或语句2;
……
ELSE 要返回的值n或语句n;
END CASE;
情况2:类似于java中的多重IF语句,一般用于实现区间判断
语法:
CASE
WHEN 要判断的条件1 THEN 返回的值1或语句1;
WHEN 要判断的条件2 THEN 返回的值2
或语句2;
……
ELSE 要返回的值n
END
CASE;
特点:
可以作为表达式,嵌套在其他语句中使用,可以 放在任何地方,BEGIN END中或BEGIN END的外面
可以作为独立的语句去使用,只能放在BEGIN END中
- 如果WHEN中的值满足或条件成立,则执行对应的THEN后面的语句,并且结束CASE
如果都不满足,则执行ELSE中的语句或值
- ELSE语句可以省略,如果省略,并且所有WHEN条件都不满足,则返回NULL
案例:
创建存储过程,根据传入的成绩,来显示等级,比如传入的成绩:90-100,显示B,60-80显示C
1 | CREATE PROCEDURE test_case(IN score INT) |
3.if结构
功能:实现多重分支
语法:
if 条件1 then 语句1;
elseif 条件2 then 语句2;
……
【else 语句n;】
end if;
应用场景:应用在begin end中
案例:
创建存储过程,根据传入的成绩,来返回等级,比如传入的成绩:90-100,显示A,80-90返回B,60-80返回C
1 | CREATE FUNCTION test_if(score INT) RETURNS CHAR |
7.2 循环结构
分类:
while、loop、repeat
循环控制:
iterate 类似于continue,继续,结束本次循环,继续下一次
leave 类似于 break,跳出,结束当前所在的循环
1.while
语法:
【标签:】while 循环条件 do
循环体;
end while 【标签:】
联想:
while(循环条件){
循环体;
}
2.loop
语法:
【标签:】loop
循环体;
end loop【标签】;
可以用来模拟简单的死循环
3.repeat
语法:
【标签:】repeat
循环体;
until 结束循环的条件
end repeat 【标签】;
案例:批量插入,根据次数插入到admin表中多条记录
1 | CREATE PROCEDURE pro_while1(IN insertCount INT) |
2.添加leave语句
案例:批量插入,根据次数插入到admin表中多条记录,如果次数>20就停止
1 | DROP PROCEDURE pro_while1; |
3.添加iterate语句
案例:批量插入,根据次数插入到admin表中多条记录,只插入偶数次
1 | TRUNCATE TABLE admin; |
总结:
名称 | 特点 | 位置 |
---|---|---|
while | 先判断后执行 | begin end中 |
repeat | 先执行后判断 | |
loop | 没有条件的死循环 |