笔记来源于作者各个机构培训视频学习笔记,学一点就更新一点,如有侵权请留言。
mysql基础
- 基础查询介绍
- 查询表中的字段
- 查询时的细节注意补充
- 查询常量、表达式、函数
- 起别名
- 去重
- +号的作用
- 使用concat实现连接
- 【案例讲解】基础查询
- 条件查询介绍
- 条件运算符的使用
- 逻辑运算符的使用
- 模糊查询—like关键字
- 模糊查询—between and关键字
- 模糊查询—in关键字
- 模糊查询—is null关键字
- 【补充】安全等于的介绍
- 【案例讲解】条件查询
- 测试题1讲解
- 排序查询介绍
- 排序查询示例
- 【案例讲解】排序查询
- 常见函数介绍
- 单行函数分类
- 流程控制函数-if函数
- 流程控制函数-case结构
- 单行函数总结
- 【案例讲解】单行函数
- 分组函数的介绍
- 分组函数的使用特点
- 分组函数和distinct搭配使用
- count函数的具体介绍
- 分组函数使用的其他注意事项
- 【案例讲解】分组函数
- 分组查询的介绍
- 分组查询—简单使用
- 分组查询—添加分组前筛选
- 分组查询—添加分组后筛选
- 分组查询—添加筛选的总结
- 分组查询—按函数分组
- 分组查询—按多个字段分组
- 分组查询—添加排序
- 【案例讲解】分组查询
- 连接查询—笛卡尔乘积
- 连接查询的分类
- 等值连接的介绍
- 等值连接的示例
- 非等值连接
- 自连接
- sql99语法介绍
- sql99语法—内连接介绍
- sql99语法—等值连接
- 交叉连接
- 【案例讲解】多表连接
- 子查询介绍
- where后面的标量子查询(一行一列)使用
- where后面的列子查询(一列多行)使用
- where后面的行子查询(一行多列)使用
- select后面的子查询使用
- from后面的子查询使用
- exists后面的子查询(相关子查询)使用
- 【案例讲解】子查询
- 分页查询
- 联合查询介绍
- 联合查询的特点
- 插入语句的方式一
- 插入语句的方式二
- 两种插入方式大pk
- 修改单表的记录
- 修改多表的记录
- 删除语句的介绍
- DDL语言的介绍
- 库的管理
- 表的创建
- 表的修改
- 表的删除
- 表的复制
- 数据类型介绍
- 整型
- 浮点型
- 字符型
- 日期型
基础查询介绍
语法:
select 查询列表 from 表名;
类似于:System.out.println(打印东西);
特点:
1、查询列表可以是:表中的字段、常量值、表达式、函数
2、查询的结果是一个虚拟的表格
查询表中的字段
- 查询表中的单个字段
SELECT last_name FROM employees
- 查询表中的多个字段
SELECT last_name,salary,email FROM employees
- 查询表中的所有字段
方式一:
`employee_id`,
`first_name`,
`last_name`,
`phone_number`,
`last_name`,
`job_id`,
`phone_number`,
`job_id`,
`salary`,
`commission_pct`,
`manager_id`,
`department_id`,
`hiredate`
FROM
employees ;
方式二:字段的顺序和,原始表一样。
SELECT * FROM employees
查询时的细节注意补充
查询之前需要指定相应的库
USE myemployees;
如果字段名和数据库中的关键字一样,可以加“``”符号区分,可读性好。
select `name` from test
查询常量、表达式、函数
#4.查询常量值
SELECT 100;
SELECT 'john';
#5.查询表达式
SELECT 100*5;
#6.查询函数
SELECT VERSION();
起别名
①便于理解
②如果要查询的字段有重名的情况,使用别名可以区分开来
③如果别名中有关键字或者空格,请使用单引号,或者双引号。
#方式一:使用as
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;
去重
select department_id FROM employees;
#查询员工表中涉及到的所有的部门编号
select DISTINCT department_id FROM employees;
+号的作用
java中的+号:
①运算符,两个操作数都为数值型
②连接符,只要有一个操作数为字符串
mysql中的+号:
仅仅只有一个功能:运算符
select 100+90;
两个操作数都为数值型,则做加法运算
select '123'+90;
只要其中一方为字符型,试图将字符型数值转换成数值型,如果转换成功,则继续做加法运算。
select 'john'+90;
如果转换失败,则将字符型数值转换成0
select null+10;
只要其中一方为null,则结果肯定为null
使用concat实现连接
SELECT CONCAT('A','B','C') AS 结果;
#案例:查询员工名和姓连接成一个字段,并显示为姓名
SELECT CONCAT(last_name,first_name) AS 姓名
FROM employees;
【案例讲解】基础查询
FINULL函数只能判断null值不能判断其他值,null和任何值拼接都为null
#1. 下面的语句是否可以执行成功
SELECT last_name , job_id , salary AS sal
FROM employees;
#2.下面的语句是否可以执行成功
SELECT * FROM employees;
#3.找出下面语句中的错误 注意标点符号不能是中文
SELECT employee_id , last_name,
salary * 12 AS "ANNUAL SALARY"
FROM employees;
#4.显示表departments的结构,并查询其中的全部数据
DESC departments;
SELECT * FROM `departments`;
#5.显示出表employees中的全部job_id(不能重复)
SELECT DISTINCT job_id FROM employees;
#6.显示出表employees的全部列,各个列之间用逗号连接,列头显示成OUT_PUT
#FINULL函数只能判断null值不能判断其他值,null和任何值拼接都为null
#语法 FINULL(表达式1,表达式2)
SELECT
IFNULL(commission_pct,0) AS 奖金率,
commission_pct
FROM
employees;
#这里如果不用IFNULL处理就会出现全部的值问null,请注意!!!!!!
SELECT
CONCAT(`first_name`,',',`last_name`,',',`job_id`,',',IFNULL(commission_pct,0)) AS out_put
FROM
employees;
条件查询介绍
语法:
select
查询列表[字段/表达式/函数/常量等]
from
表名
where
筛选条件;
执行顺序:from–>where–>select
分类:
一、按条件表达式筛选,简单条件运算符:>、< 、=、<>(!=不推荐)、>= 、<=
二、按逻辑表达式筛选,逻辑运算符,作用:用于连接条件表达式
&& || !
and or not (推荐)
&&和and:两个条件都为true,结果为true,反之为false
||或or: 只要有一个条件为true,结果为true,反之为false
!或not: 如果连接的条件本身为false,结果为true,反之为false
三、模糊查询
like
between and
in
is null
条件运算符的使用
#案例1:查询工资>12000的员工信息
SELECT
*
FROM
employees
WHERE
salary>12000;
#案例2:查询部门编号不等于90号的员工名和部门编号 推荐使用:<> 而不是 !=
SELECT
last_name,
department_id
FROM
employees
WHERE
department_id<>90;
逻辑运算符的使用
#案例1:查询工资z在10000到20000之间的员工名、工资以及奖金
SELECT
last_name,
salary,
commission_pct
FROM
employees
WHERE
salary>=10000 AND salary<=20000;
#案例2:查询部门编号不是在90到110之间,或者工资高于15000的员工信息
SELECT
*
FROM
employees
WHERE
NOT(department_id>=90 AND department_id<=110) OR salary>15000;
模糊查询—like关键字
like
between and
in
is null|is not null
特点:一般和通配符搭配使用通配符:
% 任意多个字符,包含0个字符
_ 任意单个字符
#案例1:查询员工名中包含字符a的员工信息
select
*
from
employees
where
last_name like '%a%';#abc
#案例2:查询员工名中第三个字符为n,第五个字符为l的员工名和工资
select
last_name,
salary
FROM
employees
WHERE
last_name LIKE '__n_l%';
#案例3:查询员工名中第二个字符为_的员工名
SELECT
last_name
FROM
employees
WHERE
last_name LIKE '_$_%' ESCAPE '$'; #ESCAPE'任意字符' 转义符号,和java中的 /一样
模糊查询—between and关键字
①使用between and 可以提高语句的简洁度
②包含临界值
③两个临界值不要调换顺序
#案例1:查询员工编号在100到120之间的员工信息
SELECT
*
FROM
employees
WHERE
employee_id >= 100 AND employee_id<=120;
#----------------------
SELECT
*
FROM
employees
WHERE
employee_id BETWEEN 100 AND 120;
模糊查询—in关键字
含义:判断某字段的值是否属于in列表中的某一项
特点:
①使用in提高语句简洁度
②in列表的值类型必须一致或兼容
③in列表中不支持通配符 ‘AD_%’
#案例:查询员工的工种编号是 IT_PROG、AD_VP、AD_PRES中的一个员工名和工种编号
SELECT
last_name,
job_id
FROM
employees
WHERE
job_id = 'IT_PROT' OR job_id = 'AD_VP' OR JOB_ID ='AD_PRES';
#------------------
SELECT
last_name,
job_id
FROM
employees
WHERE
job_id IN( 'IT_PROT' ,'AD_VP','AD_PRES');
模糊查询—is null关键字
①=或<>不能用于判断null值
②is null或is not null 可以判断null值
#案例1:查询没有奖金的员工名和奖金率
SELECT
last_name,
commission_pct
FROM
employees
WHERE
commission_pct IS NULL;
#案例1:查询有奖金的员工名和奖金率
SELECT
last_name,
commission_pct
FROM
employees
WHERE
commission_pct IS NOT NULL;
#----------以下为×
SELECT
last_name,
commission_pct
FROM
employees
WHERE
salary IS 12000;
【补充】安全等于的介绍
is null 和 <=>对比
①IS NULL:仅仅可以判断NULL值,可读性较高,建议使用
②<=> :既可以判断NULL值,又可以判断普通的数值,可读性较低
#案例1:查询没有奖金的员工名和奖金率
SELECT
last_name,
commission_pct
FROM
employees
WHERE
commission_pct <=>NULL;
#案例2:查询工资为12000的员工信息
SELECT
last_name,
salary
FROM
employees
WHERE
salary <=> 12000;
【案例讲解】条件查询
注意:commission_pct有的值为null,需要使用IFNULL判断,如果为null,则为0
#查询员工工号为176的员工的姓名和部门号和年薪
SELECT
last_name,
department_id,
salary * 12 * (1 + IFNULL(commission_pct, 0)) 年薪
FROM
employees
WHERE
employee_id = '176'
测试题1讲解
排序查询介绍
语法:
select 查询列表③
from 表名①
【where 筛选条件】②
order by 排序的字段或表达式;④
特点:
1、asc代表的是升序可以省略,desc代表的是降序
2、order by子句可以支持 单个字段、别名、表达式、函数、多个字段
3、order by子句在查询语句的最后面,除了limit子句
4、执行顺序为上面所标注的①②③④,先有表,然后是条件,条件后显示那些列,最后是对这些列进行排序
#1、按照员工的工资降序
SELECT * FROM employees ORDER BY salary DESC;
排序查询示例
#1、按单个字段排序
SELECT * FROM employees ORDER BY salary DESC;
#2、添加筛选条件再排序
#案例:查询部门编号>=90的员工信息,并按员工编号降序
SELECT *
FROM employees
WHERE department_id>=90
ORDER BY employee_id DESC;
#3、按表达式排序
#案例:查询员工信息 按年薪降序
SELECT *,salary*12*(1+IFNULL(commission_pct,0))
FROM employees
ORDER BY salary*12*(1+IFNULL(commission_pct,0)) DESC;
#4、按别名排序
#案例:查询员工信息 按年薪升序
SELECT *,salary*12*(1+IFNULL(commission_pct,0)) 年薪
FROM employees
ORDER BY 年薪 ASC;
#5、按函数排序
#案例:查询员工名,并且按名字的长度降序
SELECT LENGTH(last_name),last_name
FROM employees
ORDER BY LENGTH(last_name) DESC;
#6、按多个字段排序
#案例:查询员工信息,要求先按工资降序,再按employee_id升序
SELECT *
FROM employees
ORDER BY salary DESC,employee_id ASC;
【案例讲解】排序查询
#1.查询员工的姓名和部门号和年薪,按年薪降序 按姓名升序
SELECT last_name,department_id,salary*12*(1+IFNULL(commission_pct,0)) 年薪
FROM employees
ORDER BY 年薪 DESC,last_name ASC;
#2.选择工资不在8000到17000的员工的姓名和工资,按工资降序
SELECT last_name,salary
FROM employees
WHERE salary NOT BETWEEN 8000 AND 17000
ORDER BY salary DESC;
#3.查询邮箱中包含e的员工信息,并先按邮箱的字节数降序,再按部门号升序
SELECT *,LENGTH(email)
FROM employees
WHERE email LIKE '%e%'
ORDER BY LENGTH(email) DESC,department_id ASC;
常见函数介绍
概念:类似于java的方法,将一组逻辑语句封装在方法体中,对外暴露方法名
好处:1、隐藏了实现细节 2、提高代码的重用性
调用:select 函数名(实参列表) 【from 表】;如果函数中用到表中的字段就加表名,否则不加,除了在oracle中要加dual(临时表)
特点:
①叫什么(函数名)
②干什么(函数功能)
分类:
1、单行函数,一个参数,返回处理后的值,有且只有一行一列
如 concat、length、ifnull等
2、分组函数,传入多行值,返回一个行一列值
功能:做统计使用,又称为统计函数、聚合函数、组函数
注意:substr、substring 索引从1开始
单行函数 | |
---|---|
数学函数 | |
日期函数 | |
其他函数 | |
控制函数 | |
字符函数 |
多行函数 | |
---|---|
最大值 | |
最小值 | |
平均值 | |
总和 |
一、单行函数
字符函数:
length:获取字节个数(utf-8一个汉字代表3个字节,gbk为2个字节)
concat:concat(s1,s2,sn)字符串拼接,将s1,s2,...sn拼接成一个字符串
substr:substr(str,start,len)返回从字符串str从start位置起的len个长度的字符串
substring:substrting(str,start,len)返回从字符串str从start位置起的len个长度的字符串
instr:instr(str,substr)从字符串str中返回substr字符串在第一次出现的索引位置。
trim:strim(str)去掉字符串头部和尾部的空格
upper:upper(str)将字符串str全部转换为大写
lower:lower(str)将字符串str全部转换为小写
lpad:lpad(str,n,pad)左填充,用字符串pad对字符串str左边进行填充,达到n个字符串长度
rpad:rpad(str,n,pad)右填充,字符串pad对字符串str右边进行填充,达到n个字符串长度
replace:replace(str,fromstr,tostr)字符串替换,将str字符串中的fromstr字符串替换成tostr字符串
数学函数:
round:rund()返回0~1内的随机数
rund(x,y):求参数x的四舍五入的值,保留y位小数
ceil(1.1):向上取整结果为2
floor(1.9):向下取整结果为1
truncate(X,D):数值截取,X:被截取的数值,D:截取超过D长度的小数位;TRUNCATE(3.1415,2)结果为3.14
mod(x/y):返回x/y的模(余数)
日期函数:
now():返回当前日期和时间, 2022-07-30 16:14:21
curdate():返回当前日期,不包含时间 2022-07-30
curtime():返回当前时间 16:14:56
year(date):获取指定date的年份 2022
month(date):获取指定date的月份 7
monthname(date):获取指定的英文月数名
day(date):获取指定date的日期
hour(date):获取自定date的小时
minute(date):获取指定date的分钟
second(date):获取指定date的秒
STR_TO_DATE('2022-07-11 10:10:10', '%Y-%m-%d %H:%i:%s'):字符串转时间
DATE_FORMAT('2022-07-11', '%Y年%c月%d日'):日期转字符串
其他函数:
version():获取系统版本:5.7.19
database():获取当前的库
user():root@localhost
控制函数
if(value,t,f):如果value为true,返回t,否则返回f
finull(value1,value2):如果value1不为空,返回value1;否则返回value2
case when val1 then res1... else default end:如果val1为tru,返回res1,否则返回default
单行函数分类
字符函数
数学函数
日期函数
其他函数
流程控制函数-if函数
#1.if函数: if else 的效果
SELECT IF(10<5,'大','小');
SELECT last_name,commission_pct,IF(commission_pct IS NULL,'没奖金,呵呵','有奖金,嘻嘻') 备注
FROM employees;
流程控制函数-case结构
case使用一
java中
switch(变量或表达式){
case 常量1:语句1;break;
...
default:语句n;break;
}
mysql中
case 要判断的字段或表达式
when 常量1 then 要显示的值1或语句1;
when 常量2 then 要显示的值2或语句2;
...
else 要显示的值n或语句n;
end
/*案例:查询员工的工资,要求
部门号=30,显示的工资为1.1倍
部门号=40,显示的工资为1.2倍
部门号=50,显示的工资为1.3倍
其他部门,显示的工资为原工资
*/
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;
case使用二
java中:
if(条件1){
语句1;
}else if(条件2){
语句2;
}
...
else{
语句n;
}
3.case 函数的使用二:类似于 多重if
mysql中:
case
when 条件1 then 要显示的值1或语句1
when 条件2 then 要显示的值2或语句2
。。。
else 要显示的值n或语句n
end
#案例:查询员工的工资的情况
如果工资>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 AS 工资级别
FROM employees;
两种case使用方式的不同点
单行函数总结
【案例讲解】单行函数
#1. 显示系统时间(注:日期+时间)
SELECT NOW();
#2. 查询员工号,姓名,工资,以及工资提高百分之20%后的结果(new salary)
SELECT employee_id,last_name,salary,salary*1.2 "new salary"
FROM employees;
#3. 将员工的姓名按首字母排序,并写出姓名的长度(length)
SELECT LENGTH(last_name) 长度,SUBSTR(last_name,1,1) 首字符,last_name
FROM employees
ORDER BY 首字符;
#4. 做一个查询,产生下面的结果
<last_name> earns <salary> monthly but wants <salary*3>
Dream Salary
King earns 24000 monthly but wants 72000
SELECT CONCAT(last_name,' earns ',salary,' monthly but wants ',salary*3) AS "Dream Salary"
FROM employees
WHERE salary=24000;
#5. 使用case-when,按照下面的条件:
job grade
AD_PRES A
ST_MAN B
IT_PROG C
SA_REP D
ST_CLERK E
产生下面的结果
Last_name Job_id Grade
king AD_PRES A
SELECT last_name,job_id AS job,
CASE job_id
WHEN 'AD_PRES' THEN 'A'
WHEN 'ST_MAN' THEN 'B'
WHEN 'IT_PROG' THEN 'C'
WHEN 'SA_PRE' THEN 'D'
WHEN 'ST_CLERK' THEN 'E'
END AS Grade
FROM employees
WHERE job_id = 'AD_PRES';
分组函数的介绍
功能:用作统计使用,又称为聚合函数或统计函数或组函数
分类:
sum 求和、avg 平均值、max 最大值 、min 最小值 、count 计算个数
特点:
1、sum、avg一般用于处理数值型 max、min、count可以处理任何类型
2、以上分组函数都忽略null值
3、可以和distinct搭配实现去重的运算
4、count函数的单独介绍一般使用count(*)用作统计行数
5、和分组函数一同查询的字段要求是group by后的字段
#1、简单 的使用
SELECT SUM(salary) FROM employees;
SELECT AVG(salary) FROM employees;
SELECT MIN(salary) FROM employees;
SELECT MAX(salary) FROM employees;
SELECT COUNT(salary) FROM employees;
SELECT SUM(salary) 和,AVG(salary) 平均,MAX(salary) 最高,MIN(salary) 最低,COUNT(salary) 个数
FROM employees;
SELECT SUM(salary) 和,ROUND(AVG(salary),2) 平均,MAX(salary) 最高,MIN(salary) 最低,COUNT(salary) 个数
FROM employees;
分组函数的使用特点
以下的分组函数都忽略null值
SELECT SUM(last_name) ,AVG(last_name) FROM employees;
SELECT SUM(hiredate) ,AVG(hiredate) FROM employees;
SELECT MAX(last_name),MIN(last_name) FROM employees;
SELECT MAX(hiredate),MIN(hiredate) FROM employees;
SELECT COUNT(commission_pct) FROM employees;
SELECT COUNT(last_name) FROM employees;
#3、是否忽略null
SELECT SUM(commission_pct) ,AVG(commission_pct),SUM(commission_pct)/35,SUM(commission_pct)/107 FROM employees;
SELECT MAX(commission_pct) ,MIN(commission_pct) FROM employees;
SELECT COUNT(commission_pct) FROM employees;
SELECT commission_pct FROM employees;
分组函数和distinct搭配使用
#distinct:去重,可以有在字段或者语句上
SELECT SUM(DISTINCT salary),SUM(salary) FROM employees;
SELECT COUNT(DISTINCT salary),COUNT(salary) FROM employees;
count函数的具体介绍
SELECT COUNT(salary) FROM employees;
SELECT COUNT(*) FROM employees;
SELECT COUNT(1) FROM employees;
效率:
MYISAM存储引擎下 ,COUNT(*)的效率高
INNODB存储引擎下,COUNT(*)和COUNT(1)的效率差不多,比COUNT(字段)要高一些
分组函数使用的其他注意事项
和分组函数一同查询的字段有限制,要求是group by 后面的字段,其他的都不行
因为 avg查出来,只有一行,而employee_id有多行
【案例讲解】分组函数
select * from employees;
#1.查询公司员工工资的最大值,最小值,平均值,总和
SELECT
max(salary) 最大值,
min(salary) 最小值,
avg(salary) 平均值,
sum(salary) 总和
FROM
employees;
#2.查询员工表中的最大入职时间和最小入职时间的相差天数 (DIFFRENCE)
SELECT
DATEDIFF(
max(hiredate),
min(hiredate)
) 相差天数
FROM
employees;
#查询结果为1
SELECT DATEDIFF('1995-2-7','1995-2-6');
#3.查询部门编号为90的员工个数
SELECT count(*),department_id from employees where department_id=90
分组查询的介绍
语法:
select 分组函数,列(要求出现在group by的后面)
from 表
【where 筛选条件】
group by 分组的字段
【order by 排序的字段】;
特点:
1、和分组函数一同查询的字段必须是group by后出现的字段
2、筛选分为两类:分组前筛选和分组后筛选
针对的表 位置 连接的关键字
分组前筛选 原始表 group by前 where
分组后筛选 group by后的结果集 group by后 having
问题1:分组函数做筛选能不能放在where后面
答:不能
问题2:where——group by——having
一般来讲,能用分组前筛选的,尽量使用分组前筛选,提高效率
3、分组可以按单个字段也可以按多个字段
4、可以搭配着排序使用
针对的表 | 位置 | 连接的关键字 | |
---|---|---|---|
分组前筛选 | 原始表 | group by前 | where |
分组后筛选 | group by后的结果集 | group by后 | having |
![]() |
说明:图中所标注的①必须出现在 group by 后面,否则没有意义
分组查询—简单使用
小技巧:一般情况下每个什么就是对它分组
#案例1:查询每个工种的员工平均工资
SELECT AVG(salary),job_id
FROM employees
GROUP BY job_id;
#案例2:查询每个位置的部门个数
SELECT COUNT(*),location_id
FROM departments
GROUP BY location_id;
分组查询—添加分组前筛选
#案例1:查询邮箱中包含a字符的 每个部门的最高工资
SELECT MAX(salary),department_id
FROM employees
WHERE email LIKE '%a%'
GROUP BY department_id;
#案例2:查询有奖金的每个领导手下员工的平均工资
SELECT AVG(salary),manager_id
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY manager_id;
分组查询—添加分组后筛选
如果删选的字段在原始表中不存在,则使用having关键进行筛选,否则使用where关键字进行筛选
#案例:查询哪个部门的员工个数>5
--------------使用子查询-------
select t.department_id,t.c from(
select department_id,count(*) c
from employees
group by
department_id
) t where t.c>5;
---------使用having------------
select department_id,count(*) c
from employees
group by
department_id
having c>5
#如果实在写不下来sql就可以用分步写
#第①步查询每个部门的员工个数
select department_id,count(*)
from employees
group by department_id;
#第②步根据第①步的结果进行筛选,查询哪个部门的员工个数>2,count(*)在原始表中不存在,所以只能用having
select department_id,count(*)
from employees
group by department_id;
having count(*)>2
#案例2:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
#①查询每个工种有奖金的员工的最高工资,奖金是原始表中的字段,所以筛选可以放在from后面用where关键字筛选
select job_id,max(salary)
from employees
where commission_pct is not null
GROUP BY job_id
#②根据①结果继续筛选,最高工资>12000
select job_id,max(salary)
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
group by manager_id
#②添加筛选条件编号大于102,编号在原始表中,所以可以放在from后面用where关键字进行筛选
select min(salary),manager_id
from employees
where manager_id>102
group by manager_id
#③在②基础上添加删选条件:最低工资>5000
select min(salary),manager_id
from employees
where manager_id>102
group by manager_id
having min(salary)>5000 #最低工资 这个字段在原始表中没有,所以用having关键字进行筛选
分组查询—添加筛选的总结
针对的表 | 位置 | 连接的关键字 | |
---|---|---|---|
分组前筛选 | 原始表 | group by前 | where |
分组后筛选 | group by后的结果集 | group by后 | having |
①分组函数做条件可定是放在having字句中,因为分组函数在原始表中可定是没有的
②为了考虑性能问题,能用分组前筛选的尽力用分组前筛选。
分组查询—按函数分组
#案例:按员工的姓名长度分组,查询每一组的员工个数,筛选员工个数>5的有哪些
--①查询每个姓名长度的员工个数
select count(*),length(last_name) last_name
from employees
group by length(last_name);
--②添加筛选条件
select count(*) c,length(last_name) lname
from employees
group by lname
having c>5;
mysql支持别名,oracle可能不支持,注意别名不要和原名表中的字段一样
select count(*) c,length(last_name) na
from employees
group by na
having c>5;
分组查询—按多个字段分组
#案例:查询每个工种每个部门的最低工资
select department_id,job_id,min(salary)
from employees
group by job_id,department_id
分组查询—添加排序
#案例:查询每个工种每个部门的最低工资,并按最低工资降序
select department_id,job_id,min(salary)
from employees
group by job_id,department_id
order by min(salary) desc
【案例讲解】分组查询
#1.查询各job_id的员工工资的最大值,最小值,平均值,总和,并按job_id升序
SELECT MAX(salary),MIN(salary),AVG(salary),SUM(salary),job_id
FROM employees
GROUP BY job_id
ORDER BY job_id;
#2.查询员工最高工资和最低工资的差距(DIFFERENCE)
SELECT MAX(salary)-MIN(salary) DIFFRENCE
FROM employees;
#3.查询各个管理者手下员工的最低工资,其中最低工资不能低于6000,没有管理者的员工不计算在内
SELECT MIN(salary),manager_id
FROM employees
WHERE manager_id IS NOT NULL
GROUP BY manager_id
HAVING MIN(salary)>=6000;
#4.查询所有部门的编号,员工数量和工资平均值,并按平均工资降序
SELECT department_id,COUNT(*),AVG(salary) a
FROM employees
GROUP BY department_id
ORDER BY a DESC;
#5.选择具有各个job_id的员工人数
SELECT COUNT(*) 个数,job_id
FROM employees
GROUP BY job_id;
连接查询—笛卡尔乘积
笛卡尔乘积现象:表1 有m行,表2有n行,结果=m*n行,因为表1和表2没有条件连接,所以表1会挨个匹配表2中的数据,所以就出现了笛卡尔乘积
发生原因:没有有效的连接条件
如何避免:添加有效的连接条件
连接查询的分类
按年代分类:
sql92标准:仅仅支持内连接
sql99标准【推荐】:mysql支持内连接+外连接(左外和右外)+交叉连接
按功能分类:
内连接:
等值连接
非等值连接
自连接
外连接:
左外连接
右外连接
全外连接
交叉连接
等值连接的介绍
- 等值连接;
- 为表起别名;
- 两个表的顺序可以调换;
- 可以加筛选;
- 可以加分组;
- 可以加排序;
- 可以实现三表连接,或者更多;
等值连接的示例
注意:
①如果多个表中有相同的字段名称,则需要表名做限定
②如果为表起了别名,则查询的字段就不能使用原来的表名去限定
③ 多表等值连接的结果为多表的交集部分
④n表连接,至少需要n-1个连接条件
⑤ 多表的顺序没有要求
⑥一般需要为表起别名
⑦可以搭配前面介绍的所有子句使用,比如排序、分组、筛选
1、等值连接
SELECT NAME,boyName FROM boys,beauty
WHERE beauty.boyfriend_id= boys.id;
#一、sql92标准
#案例1:查询女神名和对应的男神名
SELECT NAME,boyName
FROM boys,beauty
WHERE beauty.boyfriend_id= boys.id;
#案例2:查询员工名和对应的部门名
SELECT last_name,department_name
FROM employees,departments
WHERE employees.`department_id`=departments.`department_id`;
2、为表起别名
①提高语句的简洁度
②区分多个重名的字段
注意:如果为表起了别名,则查询的字段就不能使用原来的表名去限定
#查询员工名、工种号、工种名
SELECT e.last_name,e.job_id,j.job_title
FROM employees e,jobs j
WHERE e.`job_id`=j.`job_id`;
3、两个表的顺序是否可以调换
#查询员工名、工种号、工种名
SELECT e.last_name,e.job_id,j.job_title
FROM jobs j,employees e
WHERE e.`job_id`=j.`job_id`;
4、可以加筛选
#案例:查询有奖金的员工名、部门名
SELECT last_name,department_name,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%';
5、可以加分组
#案例1:查询每个城市的部门个数
SELECT COUNT(*) 个数,city
FROM departments d,locations l
WHERE d.`location_id`=l.`location_id`
GROUP BY city;
#案例2:查询有奖金的每个部门的部门名和部门的领导编号和该部门的最低工资
SELECT department_name,d.`manager_id`,MIN(salary)
FROM departments d,employees e
WHERE d.`department_id`=e.`department_id`
AND commission_pct IS NOT NULL
GROUP BY department_name,d.`manager_id`;
6、可以加排序
#案例:查询每个工种的工种名和员工的个数,并且按员工个数降序
SELECT job_title,COUNT(*)
FROM employees e,jobs j
WHERE e.`job_id`=j.`job_id`
GROUP BY job_title
ORDER BY COUNT(*) DESC;
7、可以实现三表连接
#案例:查询员工名、部门名和所在的城市
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`
AND city LIKE 's%'
ORDER BY department_name DESC;
非等值连接
不是用“=”号作为表连接条件的查询一般都可以教非等值连接
案例1:查询员工的工资和工资级别
SELECT salary,grade_level
FROM employees e,job_grades j
WHERE e.salary BETWEEN j.lowest_sal AND j.highest_sal
自连接
什么是自连接?
只涉及到一张表,且某些字段值有一级或者二级对应关系,我们把这张表当成多张表去连接使用,已达到业务需求。
场景:一下场景假设都在同一张表中
①商品小类的id和商品大类的id;
②员工的上级领导
说明:103号员工Hunold的领导是102号De Haan员工
SELECT e.last_name 员工名,e.employee_id 员工编号,m.manager_id 领导编号,m.last_name 领导名
FROM employees e,employees m
WHERE e.employee_id = m.manager_id
sql99语法介绍
sql99语法:中括号中的内容为可选或者可省略条件
select 查询列表
from 表1 别名 [连接类型]
join 表2 别名
on 连接条件
[where 筛选条件]
[group by 分组]
[having 筛选条件]
[order by 排序列表 ASC|DESC]
连接类型分为一下几种:
内连接 | 外连接 | 交叉连接 | |
---|---|---|---|
[inner] join | 左外;left [outer] 重点 | cross | |
右外:right [outer] 重点 | |||
全外:full [outer] |
sql99语法—内连接介绍
语法:inner可以省略
select 查询列表
from 表1 别名
inner join 表2 别名
on 连接条件;
分类:
内连接一等值
内连接一非等值
内连接一自连接
特点:
①添加排序、分组、筛选
②inner可以省略
③ 筛选条件放在where后面,连接条件放在on后面,提高分离性,便于阅读
④inner join连接和sql92语法中的等值连接效果是一样的,都是查询多表的交集
sql99语法—等值连接
#案例1.查询员工名、部门名
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 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的部门名和员工个数,并按个数降序(添加排序)
#①查询每个部门的员工个数
SELECT COUNT(*) 部门个数,city
FROM departments d JOIN locations l
ON d.location_id = l.location_id
GROUP BY city
#② 在①结果上筛选员工个数>3的记录,并排序
SELECT COUNT(*) 部门个数,department_name
FROM employees e
INNER JOIN departments d
ON e.department_id=d.department_id
GROUP BY department_name
HAVING 部门个数>3
ORDER BY 部门个数 DESC;
#案例5.查询员工名、部门名、工种名,并按部门名降序(添加三表连接)
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 e.job_id = j.job_id
ORDER BY department_name DESC;
sql99语法—非等值连接
非等值连接,连接条件是一个区间
#查询员工的工资级别
SELECT salary,grade_level
FROM employees e
JOIN job_grades j
ON e.salary BETWEEN j.lowest_sal AND j.highest_sal;
#查询工资级别的个数>20的个数,并且按工资级别降序
SELECT COUNT(*),grade_level
FROM employees e
JOIN job_grades j
ON e.salary BETWEEN j.lowest_sal AND j.highest_sal
GROUP BY grade_level
HAVING COUNT(*)>20
ORDER BY grade_level DESC;
sql99语法—自连接
#查询员工的名字和上级领导的名字
SELECT e.last_name,m.last_name
FROM employees e
INNER JOIN employees m
ON e.department_id=m.manager_id;
#查询员工名字中包含字符F的员工的名字和上级领导的名字
SELECT e.last_name,m.last_name
FROM employees e
INNER JOIN employees m
ON e.department_id=m.manager_id
WHERE e.last_name LIKE '%F%';
sql99语法—外连接介绍
本次用到的数据表
应用场景:用于查询一个表中有,另一个表没有的记录
特点:
1、外连接的查询结果为主表中的所有记录
如果从表中有和它匹配的,则显示匹配的值
如果从表中没有和它匹配的,则显示null
外连接查询结果=内连接结果+主表中有而从表没有的记录
2、左外连接,left join左边的是主表
右外连接,right join右边的是主表
3、左外和右外交换两个表的顺序,可以实现同样的效果
4、全外连接=内连接的结果+表1中有但表2没有的+表2中有但表1没有的
sql99语法—左外连接
下面的sql中 boys是主表,beauty表时从表,红色圈代表主表,白色圈是从表
#查询没有男朋友的女神
SELECT be.*,b.*
FROM beauty be
LEFT OUTER JOIN boys b
ON be.boyfriend_id = b.id
查询结果如下,,其中红框的是主表beauty,绿框的是从表boys,我们要的数据就是蓝色框中的数据则只需要加 WHERE b.id IS NULL就是我们要的数据了
添加WHERE b.id IS NULL之后
#查询没有男朋友的女神
SELECT be.*,b.*
FROM beauty be
LEFT OUTER JOIN boys b
ON be.boyfriend_id = b.id
查询结果:外连接查询结果=内连接结果+主表中有而从表没有的记录
sql99语法—右外连接
右边外连接和左外连接一样只要主表和从表交换一下位置,同样也能达到这个效果
#查询没有男朋友的女神
SELECT be.*,b.*
FROM boys b
RIGHT OUTER JOIN beauty be
ON be.boyfriend_id = b.id
WHERE b.id IS NULL;
sql99语法—全外连接
MYSQL不支持全外连接,所以通过union 将右连接和左连接的结果合并去重。最终两表的全部记录都保留,连接条件元素相同的发生连接,不同的相互用null补全。
SELECT be.*,b.*
FROM boys b
LEFT OUTER JOIN beauty be
ON be.boyfriend_id = b.id
UNION
SELECT be.*,b.*
FROM boys b
RIGHT OUTER JOIN beauty be
ON be.boyfriend_id = b.id
查询结果:全外连接=左连接+右连接 , union 会把结果合并去重
标准的全外连接使用关键字 full outer join,该语法oracle是支持的;mysql会报错
SELECT b.*,bo.*
FROM beauty b
FULL OUTER JOIN boys bo
ON b.`boyfriend_id` = bo.id;
sql99总结
功能:sql99支持的较多
可读性:sql99实现连接条件和筛选条件的分离,可读性较高
交叉连接
交叉连接就是92语法中的笛卡尔乘积;关键字 cross join
SELECT b.*,bo.*
FROM beauty b
CROSS JOIN boys bo;
【案例讲解】多表连接
#查询编号>3的女神的男朋友信息,如果有则列出详细,如果没有,用null填充
SELECT be.id,be.name,b.id,b.boyName
FROM beauty be
LEFT JOIN boys b
ON be.boyfriend_id = b.id;
WHERE be.id>3
#二、查询哪个城市没有部门
SELECT d.department_id,d.department_name,l.city
FROM departments d
RIGHT JOIN locations l
ON d.location_id = l.location_id
#三、查询部门名为SAL或IT的员工信息
SELECT d.department_id,d.department_name,e.last_name
FROM departments d
LEFT JOIN employees e
ON d.manager_id = e.employee_id
WHERE d.department_name IN('SAL','IT');
#细节:不一定所有的部门都有员工,所以部门为主表
子查询介绍
概念:
子查询:出现在其他语句内部的select语句,称为子查询或内查询 ;
主查询:内部嵌套其他select语句的查询,称为外查询或主查询 ;
示例:
select first_name from employees where
department_id in(
select department_id from departments
where location_id=1700
)
子查询分类:
1.按照子查询出现的位置分类:
出现的位置 | 支持 |
---|---|
select后面 | 仅仅支持标量子查询(一行一列) |
from后面 | 支持表子查询(多行多列) |
where或having后面 | ①标量子查询(单行);②列子查询 (多行);③行子查询(一列多行) |
exists后面(相关子查询) | 表子查询(多行多列) |
2.按结果集的行列数不同:
结果集 | 说明 |
---|---|
标量子查询 | 结果集只有一行一列(单行) |
列子查询 | 结果集只有一列多行 |
行子查询 | 一列多行(或多行多列,但是比较少) |
表子查询 | 结果集一般为多行多列 |
特点:
①子查询放在小括号内
②子查询一般放在条件的右侧
③标量子查询,一般搭配着单行操作符使用< >= <= = <>
④列子查询,一般搭配着多行操作符使用in、any/some、all
⑤子查询的执行优先于主查询执行,主查询的条件用到了子查询的结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iwGjHivP-1662285999190)(F:\专业知识整理笔记\mysql数据库\基础\assets\1660576506029.png)]
where后面的标量子查询(一行一列)使用
案例1:谁的工资比 Abel 高?
#①查询Abel的工资
SELECT salary
FROM employees
WHERE last_name = 'Abel'
#②查询员工的信息,满足 salary>①结果
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 和工资,要求job_id=①并且salary>②
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
#②查询last_name,job_id和salary,要求salary=①
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
#③ 在②基础上筛选,满足min(salary)>①
SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
SELECT MIN(salary)
FROM employees
WHERE department_id = 50
);
where后面的列子查询(一列多行)使用
案例1:返回location_id是1400或1700的部门中的所有员工姓名
#①查询location_id是1400或1700的部门编号
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN(1400,1700)
#②查询员工姓名,要求部门号是①列表中的某一个
SELECT last_name
FROM employees
WHERE department_id IN(
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN(1400,1700)
)
any/all关键字必须与一个比较操作符一起使用。
any关键词可以理解为“对于子查询返回的列中的任一数值。
all的意思是“对于子查询返回的列中的所有值。
上面的例子用any实现
SELECT last_name
FROM employees
WHERE department_id =ANY(
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN(1400,1700)
)
#<>ALL表示不包含所有
SELECT last_name
FROM employees
WHERE department_id <>ALL(
SELECT DISTINCT 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<(①)的任意一个
SELECT last_name,employee_id,job_id,salary
FROM employees
#any关键词可以理解为“对于子查询返回的列中的任一数值。
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:返回其它部门中比job_id为‘IT_PROG’部门所有工资都低的员工 的员工号、姓名、job_id 以及salary
SELECT last_name,employee_id,job_id,salary
FROM employees
#all的意思是“对于子查询返回的列中的所有值
WHERE salary<ALL(
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 MIN( salary)
FROM employees
WHERE job_id = 'IT_PROG'
) AND job_id<>'IT_PROG';
where后面的行子查询(一行多列)使用
案例:查询员工编号最小并且工资最高的员工信息
--①查询最小的员工编号
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
--employee_id,salary 条件都是=,所以可以合并写
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 department_id,AVG(salary) av_sa
FROM employees
GROUP BY department_id
--②连接1的结果集合 job_grades表,筛选条件平均工资 between lowest_sal and highest_sal
SELECT ave.*,j.grade_level
FROM(
SELECT department_id,AVG(salary) av_sa
FROM employees
GROUP BY department_id
) ave
INNER JOIN job_grades j
ON ave.av_sa BETWEEN j.lowest_sal AND j.highest_sal
执行结果:
exists后面的子查询(相关子查询)使用
语法:exists(完整的查询语句)
结果:1或0
执行顺序:先执行主查询,再执行子查询
案例1:查询有员工的部门名
-- 使用exists
SELECT department_name
FROM departments d
WHERE EXISTS(
SELECT e.department_id
FROM employees e
WHERE e.department_id = d.department_id
)
-- 使用in
SELECT department_name
FROM departments d
WHERE d.department_id IN(
SELECT e.department_id
FROM employees e
)
案例2:查询没有女朋友的男神信息
-- 使用in
SELECT bo.*
FROM boys bo
WHERE bo.id NOT IN(
SELECT boyfriend_id
FROM beauty
)
-- 使用exists
SELECT bo.*
FROM boys bo
WHERE NOT EXISTS(
SELECT boyfriend_id
FROM beauty b
WHERE bo.`id`=b.`boyfriend_id`
);
【案例讲解】子查询
案例 1.查询和Zlotkey相同部门的员工姓名和工资
-- ①查询员工名字为Zlotkey的部门
SELECT department_id
FROM employees
WHERE last_name='Zlotkey'
-- ②查询部门号=①的姓名和工资
SELECT last_name,salary,department_id
FROM employees WHERE department_id=(
SELECT department_id
FROM employees
WHERE last_name='Zlotkey'
);
案例 2.查询工资比公司平均工资高的员工的员工号,姓名和工资。
-- ①查询公司的平均工资
SELECT AVG(salary)
FROM employees
-- ②查询工资>①的员工的工号,姓名和工资。
SELECT employee_id,last_name,salary
FROM employees
WHERE salary>(
SELECT AVG(salary)
FROM employees
);
案例 3.查询各部门中工资比本部门平均工资高的员工的员工号, 姓名和工资
-- ①查询部门的平均工资
SELECT department_id,AVG(salary)
FROM employees
GROUP BY department_id
-- ②通过部门号连接①且工资>①的员工的工号,姓名和工资
SELECT employee_id,last_name,salary,e.department_id
FROM employees e
INNER JOIN(
SELECT department_id,AVG(salary) d_a
FROM employees
GROUP BY department_id
) d
ON e.department_id=d.department_id
WHERE e.salary>d.d_a
案例4.查询和姓名中包含字母u的员工在相同部门的员工的员工号和姓名
-- ①查询名字中包含字母u的员工的部门
SELECT DISTINCT department_id
FROM employees
WHERE last_name LIKE "%u%"
-- ②查询工号和姓名且部门号包含①的员工
SELECT employee_id,last_name,department_id
FROM employees
WHERE department_id IN(
SELECT DISTINCT department_id
FROM employees
WHERE last_name LIKE "%u%"
);
案例5.查询在部门的location_id为1700的部门工作的员工的员工号
-- ①查询location_id为1700的部门号
SELECT DISTINCT department_id
FROM departments
WHERE location_id=1700
-- ②查询部门包含①中的员工的工号
SELECT employee_id,department_id
FROM employees
WHERE department_id IN (
SELECT DISTINCT department_id
FROM departments
WHERE location_id=1700
);
-- 或者用any(任意一个)
SELECT employee_id,department_id
FROM employees
WHERE department_id =ANY (
SELECT DISTINCT department_id
FROM departments
WHERE location_id=1700
);
案例6.查询管理者是K_ing的员工姓名和工资
-- ①查询名字为K_ing的员工编号
SELECT employee_id
FROM employees
WHERE last_name="K_ing"
-- ②查询包含manager_id为①的员工的姓名和工资
SELECT last_name,salary,manager_id
FROM employees
WHERE manager_id IN(
SELECT employee_id
FROM employees
WHERE last_name="K_ing"
);
案例7.查询工资最高的员工的姓名,要求first_name和last_name显示为一列,列名为 姓.名
-- ①查询工资为最高的员工
SELECT MAX(salary)
FROM employees
-- ②查询姓.名且工资=①
SELECT CONCAT(first_name,last_name) '姓.名',salary
FROM employees
WHERE salary=(
SELECT MAX(salary)
FROM employees
);
分页查询
应用场景:当要显示的数据,一页显示不全,需要分页提交sql请求。
语法:
select 查询列表⑦
from 表①
【join type join 表2②
on 连接条件③
where 筛选条件④
group by 分组字段⑤
having 分组后的筛选⑥
order by 排序的字段】⑧
limit 【offset,】size;⑨
执行顺序:1,2,3,4,5,6,7,8,9
offset要显示条目的起始索引(起始索引从0开始)
size 要显示的条目个数
特点:
①limit语句放在查询语句的最后
②公式
要显示的页数 page,每页的条目数size
select 查询列表
from 表
limit (page-1)*size,size;
案例1:查询前五条员工信息
前面的page如果是从0开始可以省略
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关键字默认去重,如果使用union all 可以包含重复项;
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;
案例:查询中国用户中男性的信息以及外国用户中年男性的用户信息
SELECT id,cname FROM t_ca WHERE csex='男'
UNION ALL
SELECT t_id,tname FROM t_ua WHERE tGender='male';
注意查询的列数和相同数据类型顺序最好一致,否则查询出来的数据会错位,不易理解。
联合查询的特点
特点:
1、要求多条查询语句的查询列数是一致的;
2、要求多条查询语句的查询的每一列的类型和顺序最好一致;
3、union关键字默认去重,如果使用union all 可以包含重复项;
插入语句的方式一
语法:
①insert into 表名(列名,…) values(值1,…);②insert into 表名(列名,…) values(值1,…),values(值2,…),values(值3,…);
③insert into 表名 values(值1,…);
④insert into 表名 set 列名=值,列名=值,…
1.插入的值的类型要与列的类型一致或兼容;
INSERT INTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id)
VALUES(13,'周冬雨','女','1990-4-23','1898888888',NULL,2);
2.不可以为null的列必须插入值。可以为null的列值用null,或者列名和值同时不写;
--方式一:
INSERT INTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id)
VALUES(13,'马冬梅','女','1990-4-23','1898888888',NULL,2);
--方式二:
INSERT INTO beauty(id,NAME,sex,phone)
VALUES(15,'赵敏','女','1388888888');
3.列的顺序可以调换,但相应的值类型也要相对应的调换;
INSERT INTO beauty(NAME,sex,id,phone)
VALUES('赵丽颖','女',16,'1588888888');
4.列数和值的个数必须一致
INSERT INTO beauty(NAME,sex,id,phone)
VALUES('泰西丝','女',17,'110');
5.可以省略列名,默认所有列,而且列的顺序和表中列的顺序一致;
INSERT INTO beauty
VALUES(18,'伊童','男',NULL,'119',NULL,NULL);
插入语句的方式二
语法:insert into 表名 set 列名=值,列名=值,…;
INSERT beauty SET id=14,NAME='昙花仙子',phone='199';
两种插入方式大pk
①insert into 表名(列名,…) values(值1,…);
②insert into 表名 set 列名=值,列名=值,…;
1、方式一支持插入多行,方式二不支持
INSERT INTO beauty
VALUES(15,'邓紫棋','女','1990-4-23','1898888888',NULL,2)
,(16,'高圆圆','女','1990-4-23','1898888888',NULL,2)
,(17,'汤唯','女','1990-4-23','1898888888',NULL,2);
2、方式一支持子查询,方式二不支持
INSERT INTO beauty(id,NAME,phone)
SELECT id,c_name,c_phone FROM bearty2 WHERE id>3;
修改单表的记录
语法:
update 表名
set 列=新值,列=新值,…
where 筛选条件;
案例1:修改beauty表中姓高的女神的电话为13999999999
UPDATE beauty SET phone = '13999999999'
WHERE NAME LIKE '高%';
修改多表的记录
语法:
sql92语法:
update 表1 别名,表2 别名
set 列=值,...
where 连接条件
and 筛选条件;
sql99语法:
update 表1 别名
inner|left|right join 表2 别名
on 连接条件
set 列=值,...
where 筛选条件;
案例 1:修改张无忌的女朋友的手机号为114
UPDATE boys bo
INNER JOIN beauty be
ON bo.id = be.boyfriend_id
SET be.phone='114',bo.userCP='1000'
WHERE bo.boyName='张无忌'
案例2:修改没有男朋友的女神的男朋友编号都为2号
“修改beauty表的boyfriend_id不在boys表中的id的值为2”
UPDATE beauty be
LEFT JOIN boys bo
ON be.boyfriend_id = bo.id
SET be.boyfriend_id=2
WHERE bo.id IS NULL;
删除语句的介绍
sql92语法:
delete 表1的别名,表2的别名
from 表1 别名,表2 别名
where 连接条件
and 筛选条件;
delete后面的表别名,删除一个表就加一个表,如果两个表中的数据都删除则都加
sql99语法:重点
delete 表1的别名,表2的别名
from 表1 别名
inner|left|right join 表2 别名 on 连接条件
where 筛选条件;
delete后面的表别名,删除一个表就加一个表,如果两个表中的数据都删除则都加
方式二:truncate
语法:truncate table 表名;
删除方式一(DELETE)
案例1:删除手机号以9结尾的女神信息
DELETE FROM beauty WHERE phone LIKE '%8';
案例2:删除张无忌的女朋友的信息
DELETE b -- 只加一个则只删除一个表中的数据
FROM beauty b
INNER JOIN boys bo
ON b.boyfriend_id = bo.id
WHERE bo.boyName='张无忌'
案例3:删除黄晓明的信息以及他女朋友的信息
DELETE bo,be-- 两个表的别名,则删两个表
FROM boys bo
INNER JOIN beauty be
ON bo.id = be.boyfriend_id
WHERE bo.boyName='黄晓明'
删除方式二(truncate)
truncate不能加删除条件,所有只能用于清空表数,而且使用truncate清空表数据比delete清空表数据效率高。
TRUNCATE TABLE boys ;
delete 和 truncate的区别
1.delete 可以加where 条件,truncate不能加
2.truncate删除,效率比delete高一点,因为sql解析器不用考虑条件;
3.假如要删除的表中有自增长列,如果用delete删除后,再插入数据,自增长列的值从断点开始;而truncate删除 后,再插入数据,自增长列的值从1开始。
4.truncate删除没有返回值,不会告诉你几行受影响,delete删除有返回值,会告诉你几行受影响。
5.truncate删除不能回滚,delete删除可以回滚;
案例讲解】数据的增删改
1.运行以下脚本创建表my_employees
USE myemployees;
CREATE TABLE my_employees(
Id INT(10),
First_name VARCHAR(10),
Last_name VARCHAR(10),
Userid VARCHAR(10),
Salary DOUBLE(10,2)
);
CREATE TABLE users(
id INT,
userid VARCHAR(10),
department_id INT
);
2.显示表my_employees的结构
DESC my_employees;
3.向my_employees表中插入下列数据
Id | First_name | Last_name | Userid | Salary |
---|---|---|---|---|
1 | patel | Ralph | Rpatel | 895 |
2 | Dancs | Betty | Bdancs | 860 |
3 | Biri | Ben | Bbiri | 1100 |
4 | Newman | Chad | Cnewman | 750 |
5 | Ropeburn | Audrey | Aropebur | 1550 |
#方式一:
INSERT INTO my_employees
VALUES(1,'patel','Ralph','Rpatel',895),
(2,'Dancs','Betty','Bdancs',860),
(3,'Biri','Ben','Bbiri',1100),
(4,'Newman','Chad','Cnewman',750),
(5,'Ropeburn','Audrey','Aropebur',1550);
DELETE FROM my_employees;
#方式二:
INSERT INTO my_employees
SELECT 1,'patel','Ralph','Rpatel',895 UNION
SELECT 2,'Dancs','Betty','Bdancs',860 UNION
SELECT 3,'Biri','Ben','Bbiri',1100 UNION
SELECT 4,'Newman','Chad','Cnewman',750 UNION
SELECT 5,'Ropeburn','Audrey','Aropebur',1550;
4.向users表中插入数据
1 | Rpatel | 10 |
---|---|---|
2 | Bdancs | 10 |
3 | Bbiri | 20 |
4 | Cnewman | 30 |
5 | Aropebur | 40 |
INSERT INTO users
VALUES(1,'Rpatel',10),
(2,'Bdancs',10),
(3,'Bbiri',20),
(4,'Cnewman',30),
(5,'Aropebur',40);
5.将3号员工的last_name修改为“drelxer”
UPDATE my_employees SET last_name='drelxer' WHERE id = 3;
6.将所有工资少于900的员工的工资修改为1000
UPDATE my_employees SET salary=1000 WHERE salary<900;
7.将userid 为Bbiri的user表和my_employees表的记录全部删除
DELETE u,e
FROM users u
JOIN my_employees e ON u.`userid`=e.`Userid`
WHERE u.`userid`='Bbiri';
8.删除所有数据
DELETE FROM my_employees;
DELETE FROM users;
9.检查所作的修正
SELECT * FROM my_employees;
SELECT * FROM users;
10.清空表my_employees
TRUNCATE TABLE my_employees;
DDL语言的介绍
DDL(Data Definition Language):数据定义语言
操作 | 表的管理 | 库的管理 |
---|---|---|
创建 | create | create |
修改 | alter | alter |
删除 | drop | drop |
库的管理
案例1:创建库Books,并设置字符集为utf8,如果存在则不创建,否则创建。
CREATE DATABASE IF NOT EXISTS books CHARACTER SET utf8;
案例2:库的修改-现在已经不能使用了
RENAME DATABASE books TO 新库名;
案例3:更改库的字符集
ALTER DATABASE books CHARACTER SET gbk;
案例4:库的删除,如果存在就删除数据库
DROP DATABASE IF EXISTS books;
表的创建
语法:
CREATE TABLE 表名(
列名 列的类型(长度) 约束 COMMENT '注释',
列名 列的类型(长度) 约束 COMMENT '注释',
列名 列的类型(长度) 约束 COMMENT '注释',
...
列名 列的类型(长度) 约束 COMMENT '注释'
) COMMENT='表注释';
COMMENT '学号'
是表的注释
CREATE TABLE student(
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '学号',
name VARCHAR(200) COMMENT '姓名',
age int COMMENT '年龄'
) COMMENT='学生信息'
表的修改
①修改列名
②修改列的类型或约束
③添加新列
④删除列
⑤修改表名
语法:
ALTER TABLE 表名 add|drop|modify|change column 列明 【列类型 约束】
一、修改列名
ALTER TABLE 表名 CHANGE column 原始列名 想要修改的列名 列类型;
ALTER TABLE book CHANGE COLUMN publishdate pubDate DATETIME;
二、修改列的类型或约束
ALTER TABLE 表名 modify column 列名 修改的类型;
ALTER TABLE book MODIFY COLUMN pubdate TIMESTAMP;
三、添加新列
ALTER TABLE 表名 add column 列名 列类型;
ALTER TABLE author ADD COLUMN annual DOUBLE;
四、删除列
ALTER TABLE 表名 drop column 要删除的列名;
ALTER TABLE book_author DROP COLUMN annual;
五、修改表名
ALTER TABLE 原始表名 RENAME TO 要修改成的表名;
ALTER TABLE author RENAME TO t_author;
表的删除
DROP TABLE IF EXISTS 旧表名;
CREATE TABLE 表名(
id INT,
au_name VARCHAR(20),
nation VARCHAR(10)
);
表的复制
创建表
CREATE TABLE author(
id INT,
au_name VARCHAR(20),
nation VARCHAR(10)
);
传入数据
INSERT INTO author(id,au_name,nation) VALUES
(1,'李白','中国'),
(2,'赵子龙','中国'),
(3,'liy','英国'),
(4,'mar','德国');
SELECT * FROM author;
1.仅仅复制表的结构
CREATE TABLE copy_author LIKE author;
2.复制表的结构+全部数据
CREATE TABLE copy_author2
SELECT * FROM author;
SELECT * FROM copy_author2;
3.复制表的结构+部分数据
CREATE TABLE copy_author3
SELECT id,au_name FROM author
WHERE nation='中国'
4.仅仅只复制表的某些结构字段不复制数据
CREATE TABLE copy_author4
SELECT id,au_name
FROM author
WHERE 1=2;#条件不成立,不加数据
数据类型介绍
数据类型这么多不知道怎么选
原则:所选择的类型越简单越好,能保存数值的类型越小越好
-
数值型:
- 整型
- 小数:
- 定点数
- 浮点数
- 小数:
- 整型
-
字符型:
- 较短的文本:char、varchar
- 较长的文本:text、blob(较长的二进制数据)
-
日期型:
整型
特点:
① 如果不设置无符号还是有符号,默认是有符号,如果想设置无符号,需要添加unsigned关键字
② 如果插入的数值超出了整型的范围,会报out of range异常,并且插入临界值
③ 如果不设置长度,会有默认的长度
长度代表了显示的最大宽度,如果不够会用0在左边填充,但必须搭配zerofill使用!
1.如何设置无符号和有符号
DROP TABLE IF EXISTS tab_int;
CREATE TABLE tab_int(
t1 INT(7) UNSIGNED,-- 设置为无符号,只能插入整数
t2 INT(7) -- int类型的数据(7)只表示最大宽度,不决定存储的范围
);
DESC tab_int
长度代表了显示的最大宽度,如果不够会用0在左边填充,但必须搭配zerofill使用!
DROP TABLE IF EXISTS tab_int;
CREATE TABLE tab_int(
t1 INT(7) ZEROFILL,-- 失效符号,只能存无符号了
t2 INT(7) ZEROFILL
);
DESC tab_int
INSERT INTO tab_int VALUES(-2147483648,2147483647);
INSERT INTO tab_int VALUES(123,456);
SELECT * FROM tab_int
浮点型
分类:
1.浮点型
float(M,D) M:整数部位+小数部位,D:小数部位,如果超过范围,则插入临界值
double(M,D)
2.定点型
dec(M,D) decimal的简写方式
decimal(M,D)
特点:
①
M:整数部位+小数部位
D:小数部位
如果超过范围,则插入临界值
②
M和D都可以省略
如果是decimal,则M默认为10,D默认为0
如果是float和double,则会根据插入的数值的精度来决定精度
③定点型的精确度较高,如果要求插入数值的精度较高如货币运算等则考虑使用
字符型
较短的文本:
char
varchar
其他:
binary和varbinary用于保存较短的二进制
enum用于保存枚举
set用于保存集合
较长的文本:
text
blob(较大的二进制)
char和varchar的特点
写法 | M的意思 | 特点 | 空间的耗费 | 效率 |
---|---|---|---|---|
char或char(M) | 最大的字符数,可以省略,默认为1 | 固定长度的字符 | 比较耗费 | 高 |
varchar(M) | 最大的字符数,不可以省略 | 可变长度的字符 | 比较节省(用多少给你开辟多少) | 低 |
什么时候用char,什么时候用varchar
空间不会变的用char,如性别用char,否则用varchar
日期型
分类:
date | 只保存日期 |
---|---|
time | 只保存时间 |
year | 只保存年 |
datetime | 保存日期+时间 |
timestamp | 保存日期+时间 ,受时区影响 |
timestamp:受时区影响,如果服务器跨时区比如在美国,请使用timestamp.
特点:
字节 | 范围 | 时区等的影响 | |
---|---|---|---|
datetime | 8 | 1000——9999 | 不受 |
timestamp | 8 | 1970-2038 | 受 |
timestamp受时区影响测试:
设置时区为东9区后在查看
-- 查看系统时区
SHOW VARIABLES LIKE 'time_zone';
-- 设置时区为东9区
SET time_zone='+9:00';