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 姓名
FROM
employees;
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
WHERE
department_id<>90;
# 或者 department_id!=90
二、按逻辑表达式筛选
作用:用于连接条件表达式
逻辑运算符 : && || !
推荐:and or not
案例一:查询工资在10000-20000之间的员工名、工资以及奖金。
SELECT
last_name,salary,commission_pct
FROM
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
FROM
employees
WHERE
last_name LIKE '___e_a%';
案例三:查询员工名中第二个字符为下划线的员工名。
SELECT
last_name
FROM
employees
WHERE
last_name LIKE '_\_%';
between and
使用between and可以提高语句的简洁度,包含两个临界值,两个临界值不要颠倒顺序。
案例一:查询员工编号在100-120之间的员工信息。
SELECT
*
FROM
employees
WHERE
employee_id BETWEEN 100 AND 120;
in
含义:判断某字段的值是否属于in列表中的某一项。
特点:1.使用in提高语句简洁度。
2.in列表的值类型必须统一或者兼容。
案例一:查询员工的工种编号是IT_RPOG、AD_VP、AD_PRES中的一个员工名和工种编号
SELECT
last_name,job_id
FROM
employees
WHERE
job_id IN ('IT_RPOG','AD_VP','AD_PRES');
is null
案例一:查询到没有奖金的员工和奖金率。
SELECT
last_name,commission_pct
FROM
employees
WHERE
commission_pct IS NOT NULL;
<=>
安全等于:相当于是否等于
案例一:
SELECT
last_name,commission_pct
FROM
employees
WHERE
commission_pct <=>NULL;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5aFYAwpp-1614861109930)(C:\Users\刘畅\Pictures\Camera Roll\QQ图片20210227103814.png)]
前几节课总结
数据库相关概念
一、数据库的好处
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;
案例四:按姓名的长度显示员工的姓名和工资【按函数排序】。
SELECT
LENGTH(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');
实例:将姓变成大写,名变成小写
SELECT
CONCAT(UPPER(last_name),LOWER(first_name)) 姓名
FROM
employees;
SUBSTR、 SUBSTRING: 字符串裁剪
注意:索引是从1开始的
案例:截取从指定索引处后面的所有字符
SELECT SUBSTR('李莫愁爱上了路展元',7) out_put;#输出路展元
案例:截取从指定索引处指定字符长度的字符
SELECT SUBSTR('李莫愁爱上了路展元',1,3) out_put;#输出李莫愁
案例:姓名中首字符大写,其他字符小写然后用_拼接,显示出来
SELECT
CONCAT(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 要显示的值或者语句1
when 常量1 then 要显示的值或者语句2
....
else 要显示的值或者语句n;
end
2:类似于多重if
case
when 条件一 then 要显示的值或者语句
when 条件二 then 要显示的值或者语句
...
else 要显示的值或者语句
end
案例: 显示不同编号的不同工资
SELECT salary 原始工资, department_id,
case department_id
when 30 then salary*1.1
when 40 THEN salary*1.2
WHEN 50 THEN salary*1.3
ELSE salary
END 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'
END
FROM 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
employees
GROUP BY
job_id;
案例:查询每个位置上的部门个数
SELECT
COUNT(*), location_id
FROM
departments
GROUP BY
location_id;
添加筛选条件
案例1:查询邮箱中包含字符a的,每个部门的平均工资
SELECT
AVG(salary),department_id
FROM
employees
WHERE
email like '%a%'
GROUP BY
department_id;
案例2:查询有奖金的每个领导手下员工的最高工资
SELECT
MAX(salary),manager_id
FROM
employees
WHERE
commission_pct is NOT NULL
GROUP BY
manager_id;
添加复杂的筛选条件
案例1:查询哪个部门的员工个数>2
#拆分为两步:
1.查询每个部们的员工个数
2.根据1的去筛选哪个部门的员工个数>2
SELECT
count(*),department_id
FROM
employees
GROUP BY
department_id
HAVING
count(*)>2;
案例2:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
SELECT
MAX(salary),job_id
FROM
employees
WHERE
commission_pct is NOT NULL
GROUP BY
job_id
HAVING
MAX(salary)>12000;
案例3:查询领导编号大于102的每个领导手下的最低工资>5000的领导编号是哪个
SELECT
MIN(salary),manager_id
FROM
employees
WHERE
manager_id>102
GROUP BY
manager_id
HAVING
MIN(salary)>5000;
按表达式(函数)分组
案例:按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的有哪写
1.查询每个长度的员工个数
SELECT
COUNT(*),LENGTH(last_name) len_name
FROM
employees
GROUP BY
LENGTH(last_name);
2.添加筛选条件
SELECT
COUNT(*),LENGTH(last_name) len_name
FROM
employees
GROUP BY
LENGTH(last_name)
HAVING
COUNT(*)>5;
按多个字段分组
案例:查询每个部门每个工种的员工的平均工资
SELECT
AVG(salary),department_id,job_id
FROM
employees
GROUP BY
department_id,job_id;
添加排序
案例:查询每个部门每个工种的员工的平均工资 ,并且按平均工资的高低显示
SELECT
AVG(salary),department_id,job_id
FROM
employees
GROUP BY
department_id,job_id
ORDER BY
AVG(salary) DESC;
进阶六:连接查询
又称为多表查询,当查询的字段来自于多个表时,就会用到连接查询。
笛卡尔乘积现象:表1 有m行 表2有n行 ,结果有m*n行
发生原因:没有有效的连接条件
如何避免:添加有效的连接条件
分类:
按年代分类:
sq192标准:仅仅支持内连接
sq199标准:【推荐】 就不支持全外连接
按功能分类:
内连接:等值连接、非等值连接、自连接
外连接:左外连接、右外连接、全外连接、交叉连接
1.sql92标准
等值连接
1.等值连接的结果为多表的交集部分。
2.n表连接至少需要n-1个连接条件。
案例一:查询女神名和对应的男神名
SELECT
NAME,boyName
FROM
boys,beauty
WHERE
beauty.boyfriend_id =boys.id;
案例二:查询员工名和对应的部门名
SELECT
last_name, department_name
FROM
employees,departments
WHERE
employees.department_id=departments.department_id;
为表起别名
提高语句的简洁度,区别多个重名字段 (如果为表起了别名,查询时就不可以再用以前的表名了)
查询员工名,工种号,工种名
SELECT
last_name,e.job_id,job_title
FROM
employees e ,jobs j
WHERE
e.job_id =j.job_id;
可以加筛选
案例:查询有奖金的员工名和部门名
SELECT
last_name,department_name,e.commission_pct
FROM
employees e,departments d
WHERE
e.department_id=d.department_id
AND
e.commission_pct is NOT NULL;
案例2:查询城市名中第二个字符为‘o’的部门名和城市名
SELECT
department_name,city
FROM
departments d,locations l
WHERE
d.location_id=l.location_id
AND
city LIKE '_o%';
可以加分组
案例1.查询每个城市的部门个数
SELECT
COUNT(*) 个数,city
FROM
departments d,locations l
WHERE
d.location_id=l.location_id
GROUP BY
city;
案例2.查询有奖金的每个部门的部门名和部门的领导编号和该部门最低工资
SELECT
MIN(salary),d.manager_id,d.department_name
FROM
departments d ,employees e
WHERE
d.department_id=e.department_id
AND
e.commission_pct is NOT NULL
GROUP BY
department_name,d.manager_id;
可以加排序
案例:查询每个工种的工种名和员工的个数,并且按员工个数降序
SELECT
job_title,COUNT(*)
FROM
jobs j,employees e
WHERE
j.job_id=e.job_id
GROUP BY
job_title
ORDER BY
COUNT(*) DESC;
三表连接
案例:查询员工名、部门名、和所在城市名
SELECT
last_name,department_name,city
FROM
employees e,departments d,locations l
WHERE
e.department_id=d.department_id
AND
d.location_id=l.location_id
ORDER BY
department_name DESC;
非等值连接
案例1:查询员工的工资和工资级别
SELECT
salary,grade_level
FROM
employees e,job_grades j
WHERE
salary BETWEEN j.lowest_sal AND j.highest_sal;
自连接
案例:查询 员工名和上级的名称
SELECT
e.employees_id,e.last_name,m.employees_id,m.last_name
FROM
employees e,employees m
WHERE
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_name
FROM
employees e
INNER JOIN
departments d
ON
e.department_id =d.department_id;
案例2:查询名字中包含e的员工名和工种名(添加筛选)
SELECT
last_name,job_title
FROM
employees e
INNER JOIN
jobs j
ON
e.job_id=j.job_id
WHERE
e.last_name like '%e%';
案例3:查询部门个数 >3的城市名和部门个数,(添加分组和筛选)
SELECT
city,COUNT(*)
FROM
departments d
INNER JOIN
locations l
on
d.location_id= l.location_id
GROUP BY
city
HAVING
COUNT(*)> 3;
案例4:查询哪个部门的员工个数>3的部门名和员工个数,并按个数降序(添加排序)
1:查询每个部门的员工个数
SELECT
COUNT(*) ,department_name
FROM
employees e
INNER JOIN
departments d
ON
e.department_id=d.department_id
GROUP BY
department_name;
2:在1的基础上筛选个数大于三的并记录
SELECT
COUNT(*) ,department_name
FROM
employees e
INNER JOIN
departments d
ON
e.department_id=d.department_id
GROUP BY
department_name
HAVING
COUNT(*)>3
ORDER BY
COUNT(*) DESC;
案例五:查询员工名,部门名,工种名,并按部门名称降序()
SELECT
last_name,department_name,job_title
FROM
employees e
INNER JOIN
departments d on e.department_id=d.department_id
INNER JOIN
jobs j ON j.job_id=e.job_id
ORDER BY
department_name DESC;
非等值连接
查询员工的工资级别
SELECT
salary,grade_level
FROM
employees e
JOIN
job_grades g
ON
e.salary BETWEEN g.lowest_sal AND g.highest_sal;
查询公司级别个数大于20,并按工资级别降序
SELECT
COUNT(*) ,grade_level
FROM
employees e
JOIN
job_grades g
on
e.salary BETWEEN g.lowest_sal AND g.highest_sal
GROUP BY
grade_level
HAVING
COUNT(*)>20
ORDER BY
grade_level DESC
自连接
查询员工的名字,上级的名字
SELECT
e.last_name,m.last_name
FROM
employees e
JOIN
employees m
ON
e.manager_id=m.employee_id;
查询姓名中包含k的员工的名字,上级的名字
SELECT
e.last_name,m.last_name
FROM
employees e
JOIN
employees m
ON
e.manager_id=m.employee_id
WHERE
e.last_name LIKE '%k%';
外连接
应用场景:查询一个表中有,另一个表中没有的记录
特点:1.外连接的查询结果为主表中的所有记录,如果从表中有和它匹配的,则显示匹配的值。如果没有匹配的,则显示null。
外连接的查询结果=内连接结果+主表中有而从表中没有的记录
2.左外连接,left join左边的是主表。
右外连接,left join右边是主表。
3.左外和右外如果交换两表顺序,可以实现同样的效果
4.全外连接=内连接中结果+表1中没有表2中有的+表1中有表2中没有
案例引入:查询男朋友,不在男神表中的女神名
左外连接
SELECT
b.name,bo.*
FROM
beauty b
LEFT OUTER JOIN
boys bo
ON
b.boyfriend_id=bo.id
WHERE
bo.id is NULL;
右外连接
SELECT
b.name,bo.*
FROM
boys bo
RIGHT OUTER JOIN
beauty b
ON
b.boyfriend_id=bo.id
WHERE
bo.id is NULL;
案例1:哪个部门没有员工
左外
SELECT
d.* ,e.employee_id
FROM
departments d
LEFT OUTER JOIN
employees e
ON
d.department_id=e.department_id
WHERE
e.employee_id IS NULL;
右外
SELECT
d.*,e.employee_id
FROM
employees e
RIGHT OUTER JOIN
departments d
ON
d.department_id=e.department_id
WHERE
e.employee_id IS NULL;
全外
USE girls;
SELECT
b.* , bo.*
FROM
beauty b
FULL OUTER JOIN
boys bo
on
b.boyfriend_id-bo.id;
交叉连接
SELECT
b.*,bo.*
FROM
beauty b
CROSS 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的工资
SELECT
salary
FROM
employees
WHERE
last_name ='Abel';
查询员工的信息,满足条件1的结果
SELECT *
FROM
employees
WHERE salary > (
SELECT salary
FROM employees
WHERE last_name = 'Abel'
);
案例2:返回job_id与141号员工相同,salary比143号员工多 姓名,job_id和工资
查询141号的job_id
SELECT
job_id
FROM
employees
WHERE
employee_id = 141;
143号员工的salary
SELECT
salary
FROM
employees
WHERE
employee_id =143;
查询员工的姓名 job_id=1和工资>2
SELECT
last_name,job_id,salary
FROM
employees
WHERE job_id = (
SELECT job_id
FROM employees
WHERE employee_id = 141
) AND
salary >(
SELECT salary
FROM employees
WHERE employee_id =143
);
案例3:返回公司工资最少的员工last_name ,job_id和salary
查询工资最少
SELECT MIN(salary) FROM employees;
查询对应值 salary = 1.
SELECT
last_name,job_id,salary
FROM
employees
WHERE salary = (
SELECT MIN(salary)
FROM employees
);
案例4:查询最低工资 大于50号部门最低工资的部门id和其最低工资
查询50号部门的最低工资
SELECT
MIN(salary)
FROM
employees
WHERE
department_id = 50
查询每个部门的最低工资
SELECT
MIN(salary),department_id
FROM
employees
GROUP BY
department_id;
筛选2满足 min(salary)>1的结果
SELECT
MIN(salary),department_id
FROM
employees
GROUP BY
department_id
HAVING MIN(salary)> (
SELECT MIN(salary)
FROM employees
WHERE department_id = 50
);
2.列子查询(多行子查询)
案例1:返回location_id是1400或者是1700的部门中的所有员工姓名
查询location_id是1400或者1700的部门编号
SELECT
department_id
FROM
departments
WHERE
location_id in(1400,1700);
查询员工姓名,要求部门号是1列表中的某一个
SELECT
last_name
FROM
employees
WHERE department_id IN(
SELECT department_id
FROM departments
WHERE location_id in(1400,1700)
);
案例2:返回其他工种中比job_id 为‘IT_PROG’部门任一工资低的员工的员工号,姓名,job_id以及salary
查询job_id为‘IT_PROG’部门任一工资
SELECT DISTINCT
salary
FROM
employees
WHERE
job_id = 'IT_PROG';
查询员工号,姓名,job_id以及salary,salary<any(1的结果)
SELECT
last_name,employee_id,job_id,salary
FROM
employees
WHERE salary < any(
SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'
)AND job_id <>'IT_PROG';
另一种写法
SELECT
last_name,employee_id,job_id,salary
FROM
employees
WHERE salary < (
SELECT MAX(salary)
FROM employees
WHERE job_id = 'IT_PROG'
)AND job_id <>'IT_PROG';
3.行子查询(一行多列,多行多列)
案例:查询员工编号最小并且工资最高的员工编号
查询最小的员工编号
SELECT
MIN(employee_id)
FROM
employees;
查询出最高的工资
SELECT
MAX(salary)
FROM
employees;
查询员工信息
SELECT
*
FROM
employees
WHERE
employee_id = (
SELECT MIN(employee_id)
FROM employees)AND salary = (SELECT MAX(salary)
FROM employees);
另一种写法
SELECT *
FROM
employees
WHERE (employee_id,salary)=(
SELECT MIN(employee_id),MAX(salary)
FROM employees
);
放在select后面
案例:查询每个部门的员工个数
SELECT d.*,(
SELECT COUNT(*)
FROM employees e
WHERE e.department_id =d.department_id
) 个数
FROM departments d;
放在from后面
案例:查询每个部门的平均工资的工资等级
查询每个部门的平均工资
SELECT
AVG(salary) ,department_id
FROM
employees
GROUP BY
department_id;
连接1的结果集和job_grades表,筛选条件平均工资 BETWEEN lowest_sal and highest_sal
SELECT
ag_dep.*,g.grade_level
FROM (
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) ag_dep
INNER JOIN
job_grades g
ON
ag_dep.ag BETWEEN lowest_sal AND highest_sal;
进阶八:分页查询
应用场景:当要显示的数据,一页显示不全,需要分页提交sql请求
语法:
SELECT
查询列表
FROM
表
【JOIN type join 表2
ON 连接条件
WHERE 筛选条件
GROUP BY 分组字段
having 分组后筛选
ORDER BY 排序的字段】
limit offset,size;
#offset表示要显示条目的起始索引(从0开始)
#size表示显示的条目个数
特点:
1.limit语句放在查询语句的最后,并且执行也是最后执行。
2.公式:要显示的页数是page,每页显示的条目数是size
SELECT
查询列表
FROM
limit (page-1)*size ,size;
案例1:查询前五条员工信息
SELECT * FROM employees
LIMIT 0,5;
或者
SELECT * FROM employees
LIMIT 5;
案例2:查询第11-25条的信息
SELECT * FROM employees
LIMIT 10,15;
案例3:有奖金的员工信息,并且工资较高的排名前10的员工信息
SELECT *
FROM
employees
WHERE
commission_pct is NOT NULL
ORDER BY
salary DESC
LIMIT 10;
进阶九:联合查询
UNION 联合/合并 :将多条语句的查询结果合并成一个结果。
语法:
查询语句1
union
查询语句2
union
...
应用场景:要查询的结果来自于多个表,且多个表之间没有直接连接关系,但查询的信息一致时。
特点:
1.要求多条查询语句的查询列数是一致的
2.要求多条查询语句的查询的每一列的类型和顺序最好一致!
3.不想去重用 :UNION ALL,默认是去重的
引入的案例:查询部门编号>90或者邮箱包含a的员工信息
以前的方法
SELECT *
FROM
employees
WHERE
email LIKE '%a%'
OR
department_id>90;
union方法
SELECT * FROM employees WHERE email like '%a%'
UNION
SELECT * 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 beauty
SET id=19,NAME='大哥',phone='456465';
两种方式大PK
方式一有方式二无:支持插入多行(一次性加入多个数据行),支持子查询。
二、修改语句
1.修改单表的记录 ★
语法:
update
表名s
set
列=新值,列=新值,...
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 bo
INNER JOIN beauty b ON bo.id = b.boyfriend_id
SET b.phone ='156465465'
WHERE bo.boyName = '张无忌';
案例2:修改没有男朋友的女神的男朋友编号都为2号(张飞)
UPDATE boys bo
RIGHT JOIN beauty b ON bo.id = b.boyfriend_id
SET 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 b
INNER JOIN boys bo ON b.boyfriend_id=bo.id
WHERE bo.boyName ='张无忌'
案例:删除黄晓明的信息以及他女朋友的信息
DELETE b,bo
FROM beauty b
JOIN boys bo ON b.boyfriend_id=bo.id
WHERE 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 copy3
SELECT id,au_name
FROM author
WHERE nation='中国';
复制一部分,没内容
CREATE TABLE copy4
SELECT id,au_name
FROM author
WHERE 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; 回滚事务