【MySQL】2.DQL语言(select)一堆查询~

SQL的语言分类

  • DQL(Data Query Language):数据查询语言 select

  • DML(Data Manipulate Language):数据操作语言
    insert 、update、delete

  • DDL(Data Define Languge):数据定义语言
    create、drop、alter

  • TCL(Transaction Control Language):事务控制语言
    commit、rollback


DQL语言

一、基础查询

进阶1:基础查询

语法:

select 查询列表 from 表名;
类似于:System.out.println(打印东西);

执行顺序:

① from 子句
② select 子句

特点:

1、查询列表可以是:表中的字段、常量值、表达式、函数
2、查询的结果是一个虚拟的表格


#1.查询表中的单个字段
SELECT last_name FROM employees;

#2.查询表中的多个字段
SELECT last_name,salary,email FROM employees;

#3.查询表中的所有字段

#方式一: F12对齐
SELECT 
    `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;
 
#4.查询常量值
 SELECT 100;
 SELECT 'john';
 
#5.查询表达式
 SELECT 100%98;
 
#6.查询函数(调用函数,获取返回值)
 SELECT DATABASE();
 SELECT VERSION();
 
#7.起别名
 /*
 ①便于理解
 ②如果要查询的字段有重名的情况,使用别名可以区分开来
 */
 
 #方式一:使用 as
SELECT 100%98 AS 结果;
SELECT last_name AS,first_name ASFROM employees;

#方式二:使用空格
SELECT last_name 姓,first_name 名 FROM employees;

#案例:查询salary,显示结果为 out put
SELECT salary AS "out put" FROM employees;

#8.DISTINCT 去重
#案例:查询员工表中涉及到的所有的部门编号
SELECT DISTINCT department_id FROM employees;

#9.+号的作用
/*
作用:做加法运算
select 数值+数值; 直接运算
select 字符+数值;先试图将字符转换成数值,如果转换成功,则继续运算;否则转换成0,再做运算
select null+值;结果都为null

java中的+号:
①运算符,两个操作数都为数值型
②连接符,只要有一个操作数为字符串

mysql中的+号:
仅仅只有一个功能:运算符

select 100+90; 两个操作数都为数值型,则做加法运算
select '123'+90;只要其中一方为字符型,试图将字符型数据转换成数值型
			如果转换成功,则继续做加法运算
select 'john'+90;--->90	如果转换失败,则将字符型数值转换成0
select null+10;---->null 只要其中一方为null,则结果肯定为null

*/

#10.查看表的结构
DESC employees;
SHOW COLUMNS FROM employees;

#案例:查询员工名和姓连接成一个字段,并显示为 姓名
SELECT CONCAT('a','b','c') AS 结果;

SELECT CONCAT(last_name,first_name) AS "姓 名" 
FROM employees;
10、【补充】concat函数
功能:拼接字符
select concat(字符1,字符2,字符3,...);

11、【补充】ifnull(表达式1,表达式2)
表达式1:可能为null的字段或表达式
表达式2:如果表达式1null,则最终结果显示的值
功能:如果表达式1null,则显示表达式2,否则显示表达式1
#案例 查询员工表中
select ifnull(commission_pct,0) from employees;


12、【补充】isnull函数
功能:判断某字段或表达式是否为null,如果是,则返回1,否则返回0

二、条件查询

进阶2:条件查询

语法:
select 查询列表
from 表名
where 筛选条件;
执行顺序:

① from子句
② where子句
③ select子句

分类:
一、按条件表达式筛选

简单条件运算符:> < = != <> >= <=

#案例1:查询工资>12000的员工信息

SELECT *
FROM employees
WHERE salary>12000;
	
	
#案例2:查询部门编号不等于90号的员工名和部门编号
SELECT 
	last_name,
	department_id
FROM employees
WHERE department_id<>90;
二、按逻辑表达式筛选

逻辑运算符:and or not
作用:用于连接条件表达式
可以用:&& || ! 但不建议使用

  • &&和and:两个条件都为true,结果为true,反之为false
  • ||或or: 只要有一个条件为true,结果为true,反之为false
  • !或not: 如果连接的条件本身为false,结果为true,反之为false
#案例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
between and
in
is null | is not null

1.like

特点: 一般和通配符搭配使用
通配符:

  • % 任意多个字符,包含0个字符,支持0-多个
  • _ 任意单个字符
#案例1:查询员工姓名中包含字符a的员工信息

SELECT *
FROM employees
WHERE last_name LIKE '%a%';   #abc

#案例2:查询员工名中第三个字符为e,第五个字符为a的员工名和工资
SELECT
	last_name,
	salary
FROM
	employees
WHERE
	last_name LIKE '_ _e_a%';


#案例3:查询员工名中第二个字符为_的员工名

SELECT
	last_name
FROM
	employees
WHERE
	last_name LIKE '_$_%' ESCAPE '$'; # "_\_%"
	
	
#案例4:查询员工名中最后一个字符为e员工信息
SELECT *
FROM employees
WHERE last_name LIKE '%e';

#案例5:查询员工名中第一个字符为e员工信息
SELECT *
FROM employees
WHERE last_name LIKE 'e%';

#案例6:查询员工名中第三个字符为e员工信息
SELECT *
FROM employees
WHERE last_name LIKE '_ _ _ e%';
2.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 200;

#案例2:查询年薪不是10000-20000之间的员工姓名、工资、年薪
SELECT `last_name`,`salary`,`salary`*12*(1+IFNULL(`commission_pct`,0)) 年薪
FROM ``employees``
WHERE `salary`*12*(1+IFNULL(`commission_pct`,0)) < 10000 OR `salary`*12*(1+IFNULL(`commission_pct`,0)) > 20000;

SELECT `last_name`,`salary`,`salary`*12*(1+IFNULL(`commission_pct`,0)) 年薪
FROM `employees`
WHERE `salary`*12*(1+IFNULL(`commission_pct`,0)) NOT BETWEEN 100000 AND 200000;
3.in

含义: 判断(查询)某字段的值是否属于in(指定)列表中的某一项

  • a in(常量值1,常量值2,常量值3,…)
  • a not in(常量值1,常量值2,常量值3,…)

特点:
①使用in提高语句简洁度
②in列表的值类型必须一致或兼容
③in列表中不支持通配符

#案例:查询员工的工种编号是 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');
4、is null /is not null
  • =或<>不能用于判断null值

  • is null或is not null 可以判断null值

#案例1:查询没有奖金的员工名和奖金率
SELECT last_name,commission_pct
FROM employees
WHERE commission_pct IS NULL;


#案例2:查询有奖金的员工名和奖金率
SELECT last_name,commission_pct
FROM employees
WHERE commission_pct IS NOT NULL;

#----------以下为×
SELECT last_name,commission_pct
FROM employees
WHERE salary IS 12000;
	
	
#安全等于 ----- <=>

#案例1:查询没有奖金的员工名和奖金率
SELECT last_name,commission_pct
FROM employees
WHERE commission_pct <=>NULL;
	
#案例2:查询工资为12000的员工信息
SELECT last_name,salary
FROM employees
WHERE salary <=> 12000;
is null pk <=>

IS NULL:仅仅可以判断NULL值,可读性较高,建议使用
<=> :既可以判断NULL值,又可以判断普通的数值,可读性较低

在这里插入图片描述
在这里插入图片描述

三、排序查询

进阶3:排序查询

语法:

select 查询列表
from 表名
【where 筛选条件】
order by 排序的字段或表达式(排序列表);

执行顺序:

① from
② where
③ select
④ order by

特点:
  • asc代表的是升序,可以省略;desc代表的是降序
  • order by子句可以支持 单个字段、别名、表达式、函数、多个字段
  • order by子句在查询语句的最后面,除了limit子句
1、按单个字段排序
#案例1 将员工编号>120的员工信息进行工资的升序
SELECT * 
FROM employees
WHERE `employee_id` > 120 
ORDER BY salary ASC;

#案例2 将员工编号>120的员工信息进行工资的降序
SELECT * 
FROM employees
WHERE `employee_id` > 120 
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
WHERE commission_pct IS NOT NULL
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;

SELECT last_name 
FROM employees
ORDER BY LENGTH(last_name) DESC;
6、按多个字段排序
#案例:查询员工信息,要求先按工资降序,再按employee_id升序
SELECT *
FROM employees
ORDER BY salary DESC,employee_id ASC;
7.按列数排序(用的比较少)
SELECT *
FROM `employees`
ORDER BY 2 DESC;

SELECT *
FROM `employees`
ORDER BY `first_name` DESC;

四、常见函数

1、概述

概念: 类似于java的方法,将一组逻辑语句封装在方法体中,对外暴露方法名
好处:
1、隐藏了实现细节 2、提高代码的重用性
调用:
select 函数名(实参列表) 【from 表】;
特点:
①叫什么(函数名)
②干什么(函数功能)

分类:

  • 单行函数::如 concat、length、ifnull等
  • 分组函数:做统计使用,又称为统计函数、聚合函数、组函数

2、 常见函数

单行函数
  • 字符函数:
length:获取字节个数(utf-8一个汉字代表3个字节,gbk为2个字节)
concat:连接
substr:截取子串
upper:变大写
lower:变小写
replace:替换
length:获取字节长度
trim:去前后空格
lpad:左填充
rpad:右填充
instr:获取子串第一次出现的索引
strcmp:比较两个字符的大小

举例:

#1.LENGTH 获取参数值的字节个数(长度)
SELECT LENGTH('john');
SELECT LENGTH('hello,丸子'); #12 一个汉字识别为3个字节

#获取字符长度
SELECT CHAR_LENGTH('hello,丸子'); # 8

SHOW VARIABLES LIKE '%char%'

#2.concat 拼接字符串 可以指定多个参数
SELECT CONCAT(last_name,'_',first_name)  姓名  FROM  `employees`;

#3.upper、lower 大小写
SELECT UPPER('john');
SELECT LOWER('joHn');

#示例:将姓变大写,名变小写,然后拼接
SELECT CONCAT(UPPER(last_name),LOWER(first_name))  姓名 FROM employees;

#4.substr、substring 截取子串
/*注意:索引从1开始
substr(str,起始索引,截取的字符长度)
substr(str,起始索引)
*/

#截取从指定索引处指定字符长度的字符
SELECT SUBSTR('李莫愁爱上了陆展元',1,3) out_put; # 李莫愁

#截取从指定索引处后面所有字符
SELECT SUBSTR('李莫愁爱上了陆展元',6)  out_put; # 了陆展元

LEFT/RIGHT # 截取子串
SELECT LEFT('王六六啊',2); # 王六
SELECT RIGHT('王六六啊',1); # 啊

#案例:查询员工表中的姓名,要求:姓首字符大写,其他字符小写,名所有字符小写,然后用_拼接,最后起名为“out_put”显示出来
SELECT UPPER(SUBSTR(`first_name`,1,1)),`first_name` FROM `employees`;
SELECT LOWER(SUBSTR(`first_name`,2)),`first_name` FROM `employees`;
SELECT LOWER(`last_name`) FROM `employees`;

SELECT CONCAT( UPPER(SUBSTR(`first_name`,1,1)),LOWER(SUBSTR(`first_name`,2)),'_', LOWER( last_name) )  AS out_put
FROM `employees`;

#5.instr 返回子串第一次出现的索引,如果找不到返回0
SELECT INSTR('杨不殷六侠悔爱上了殷六侠','殷六') AS out_put;

#6.trim 去前后空格
SELECT TRIM('   丸xx子  ') AS lala;

SELECT TRIM('aa' FROM 'aaaaaaaaa张aaaaaaaaaaaa翠山aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')  AS out_put;

#7.lpad 用指定的字符实现左填充指定长度
SELECT LPAD('殷素素',5,'*') AS out_put;

#8.rpad 用指定的字符实现右填充指定长度
SELECT RPAD('殷素素',6,'ab') AS out_put;

# strcmp 比较两个字符的大小
SELECT STRCMP('abc','bbc'); #-1
SELECT STRCMP('abc','aaa'); # 1
SELECT STRCMP('abc','abc'); # 0
SELECT STRCMP('a','b'); # -1
SELECT STRCMP('b','a'); # 1

#9.replace 替换
SELECT REPLACE('周芷若周芷若周芷若周芷若张无忌爱上了周芷若','周芷若','赵敏') 
AS out_put;
  • 数学函数:
ceil:向上取整
round:四舍五入
mod:取模
floor:向下取整
truncate:截断
rand:获取随机数,返回0-1之间的小数

举例:

1、ABS 绝对值
SELECT ABS(-2); # 2


2、ROUND 四舍五入
SELECT ROUND(-1.55,0); # -2
SELECT ROUND(-1.55,1); # -1.6
SELECT ROUND(1.567,2); # 1.57
SELECT ROUND(1.76345,3); # 1.763


3、CEIL 向上取整,返回>=该参数的最小整数
SELECT CEIL(-1.02); # -1
SELECT CEIL(0.09); # 1

4、FLOOR 向下取整,返回<=该参数的最大整数
SELECT FLOOR(-9.99); #-10
SELECT FLOOR(9.99); # 9
SELECT FLOOR(0.09); # 0

5TRUNCATE 截断
SELECT TRUNCATE(1.69999,0); # 1

SELECT TRUNCATE(1.69999,1); # 1.6

SELECT TRUNCATE(1.69999,2); # 1.69

6、MOD取余
/*
mod(a,b) :  a-a/b*b

mod(-10,-3):-10- (-10)/(-3)*(-3)=-1
*/
SELECT MOD(10,-3); #1
SELECT 10%3; #1
SELECT 10%6; #4
  • 日期函数:
now:返回当前日期+时间
year:返回年
month:返回月
day:返回日
date_format:将日期转换成字符
curdate:返回当前日期
str_to_date:将字符转换成日期
curtime:返回当前时间
hour:小时
minute:分钟
second:秒
datediff:返回两个日期相差的天数
monthname:以英文形式返回月份

举例:

1、NOW 返回当前系统时间
SELECT NOW();

2、CURDATE 返回当前系统日期,不包含时间
SELECT CURDATE();

3、CURTIME 返回当前时间,不包含日期
SELECT CURTIME();

4、DATEDIFF 获取日期之差
SELECT DATEDIFF('1996-7-30','2021-9-30'); # -9193天

#可以获取指定的部分,年、月、日、小时、分钟、秒
SELECT YEAR(NOW()); #2021
SELECT YEAR('1998-1-1'); #1998

SELECT  YEAR(hiredate)FROM employees;

SELECT MONTH(NOW());
SELECT MONTHNAME(NOW());


#str_to_date 将字符串通过指定的格式转换成日期类型
SELECT STR_TO_DATE('1998-3-2','%Y-%c-%d') AS out_put;

#查询入职日期为1992--4-3的员工信息
SELECT * FROM employees WHERE hiredate = '1992-4-3';
SELECT * FROM employees WHERE hiredate = STR_TO_DATE('4-3 1992','%c-%d %Y');


#date_format 将日期转换成字符
SELECT DATE_FORMAT(NOW(),'%Y年%m月%d日') AS out_put; # 2021年09月30日

#查询有奖金的员工名和入职日期(xx月/xx日 xx年)
SELECT last_name,DATE_FORMAT(hiredate,'%m月/%d日 %Y年') 入职日期
FROM employees
WHERE commission_pct IS NOT NULL;

在这里插入图片描述

  • 其他函数:
version 当前数据库服务器的版本
database 当前打开的数据库
user 当前用户
password('字符'):返回该字符的密码形式
md5('字符'):返回该字符的md5加密形式

举例:

SELECT VERSION();
SELECT DATABASE();
SELECT USER();
  • 流程控制函数
if(条件表达式,表达式1,表达式2):如果条件表达式成立,返回表达式1,否则返回表达式2case情况1
case 变量或表达式或字段
when 常量1 then1
when 常量2 then2
...
else 值n
end
1IF函数: IF ELSE 的效果

SELECT IF(10<5,'大','小');

SELECT last_name,commission_pct,
IF(commission_pct IS NULL , '没奖金,呵呵' , '有奖金,嘻嘻') 备注
FROM employees;

2CASE函数的使用一: switch CASE 的效果
情况1CASE 表达式
WHEN1 THEN 结果1
WHEN2 THEN 结果2
...
ELSE 结果n
END

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 `department_id`,`salary` 原始工资,
CASE `department_id`
WHEN 30 THEN `salary`*1.1
WHEN 40 THEN `salary`*1.2
WHEN 50 THEN `salary`*1.3
ELSE `salary` 
END  新工资
FROM `employees`;

在这里插入图片描述

3CASE 函数的使用二:类似于多重IF, 实现区间判断
CASE 
WHEN 条件1 THEN 结果1
WHEN 条件2 THEN 结果2
...
ELSE 结果n
END
java中---------------
if(条件1){
	语句1;
}else if(条件2){
	语句2;
}
...
else{
	语句n;
}

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;

在这里插入图片描述

五、分组查询 “每XX”

语法:

select 查询列表
fromwhere 筛选条件
group by 分组的字段
having 分组后筛选
order by 排序的字段;

执行顺序:

from子句 - where子句 - group by子句 - having子句 - select子句 - order by子句

特点:

1、和分组函数一同查询的字段必须是group by后出现的字段
查询列表往往是 分组函数和被分组的字段

2、筛选分为两类:分组前筛选和分组后筛选

筛选的基表位置连接的关键字
分组前筛选原始表group by前where
分组后筛选group by后的结果集group by后having

where——group by——having

分组函数做条件只能放在having后面!!!!

一般来讲,尽量使用分组前筛选,提高效率

3、分组可以按单个字段也可以按多个字段
4、可以搭配着排序使用


#引入:查询每个部门的员工个数
SELECT COUNT(*) FROM employees WHERE department_id=90;
1、简单的分组
#案例1:查询每个工种的员工平均工资
SELECT AVG(salary),job_id
FROM employees
GROUP BY job_id;

#案例2:查询每个位置的部门个数
SELECT COUNT(*),location_id
FROM departments
GROUP BY location_id;
2、在GROUP BY前面,可以实现分组前的筛选 WHERE
#案例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;
3、在GROUP BY后面,分组后筛选 HAVING
#案例1:查询哪个部门的员工个数>5

#①查询每个部门的员工个数
SELECT COUNT(*) 员工个数,department_id
FROM employees
GROUP BY department_id;

#② 在刚才结果的基础上筛选哪个部门的员工个数>5

SELECT COUNT(*) 员工个数,department_id
FROM employees
GROUP BY department_id
HAVING COUNT(*)>5;



#案例2:每个工种 有奖金的 员工的 最高工资>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 manager_id,MIN(salary) 最低工资
FROM employees
WHERE manager_id>102
GROUP BY manager_id
HAVING MIN(salary)>5000;

案例1:
在这里插入图片描述
案例2:
在这里插入图片描述
案例3:
在这里插入图片描述

4、添加排序
#案例:每个工种没有奖金的员工的最高工资>6000的工种编号和最高工资,按最高工资升序
SELECT job_id,MAX(salary) 最高工资
FROM employees
WHERE commission_pct IS NULL
GROUP BY job_id
HAVING 最高工资 > 6000
ORDER BY 最高工资 ASC;
5、按多个字段分组
#案例:查询每个工种每个部门的最低工资,并按最低工资降序
SELECT MIN(salary) 最低工资,job_id,department_id
FROM employees
GROUP BY department_id,job_id
ORDER BY MIN(salary) DESC;

连接查询

含义:

又称多表查询,当查询的字段来自于多个表时,就会用到连接查询
当查询中涉及到了多个表的字段,需要使用多表连接

select 字段1,字段2
from1,表2,...;

笛卡尔乘积现象:表1 有m行,表2有n行,结果 = m*n行

发生原因:没有有效的连接条件
如何避免:添加有效的连接条件

分类:

按年代分类:
  • sql92标准:仅仅支持内连接
  • sql99标准【推荐】:
    支持内连接 + 外连接(左外和右外-很少用)+ 交叉连接
按功能分类:
  • 内连接:
    等值连接
    非等值连接
    自连接

  • 外连接:
    左外连接
    右外连接
    全外连接

  • 交叉连接

SELECT * FROM beauty;

SELECT * FROM boys;

SELECT `name`,`boyName` 
FROM boys o,beauty b
WHERE b.boyfriend_id= o.id;

SQL92标准

  • 内连接:
    等值连接
    非等值连接
    自连接
1、等值连接

语法:

select 查询列表
from 表名1 别名1,表名2 别名2...
where 等值连接的连接条件

特点:
1.为了解决多表中的字段名重名问题,往往为表起别名,提高语义性

① 多表等值连接的结果为多表的交集部分
② n表连接,至少需要n-1个连接条件
③ 多表的顺序没有要求
④一般需要为表起别名
⑤可以搭配前面介绍的所有子句使用,比如排序、分组、筛选

① 简单的两表连接:
#案例1:查询女神名和对应的男神名
SELECT NAME,boyName 
FROM boys,beauty
WHERE beauty.boyfriend_id= boys.id;


#案例2:查询员工名和对应的部门名
SELECT `last_name`,`department_name`
FROM `employees` e,`departments` d
WHERE e.`department_id` = d.`department_id`;

案例1:
在这里插入图片描述
案例2:等值连接的连接条件
在这里插入图片描述

② 添加筛选条件
#案例1:查询部门编号>100的部门名和所在的城市名

SELECT `department_id`,`department_name`,`city`
FROM `departments` d ,`locations` l
WHERE  d.`location_id` = l.`location_id` # 找两个表中一样的
AND d.`department_id` > 100;

#案例2:查询有奖金的员工名、部门名

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;

#案例3:查询城市名中第二个字符为o的部门名和城市名

SELECT department_name,city
FROM departments d,locations l
WHERE d.`location_id` = l.`location_id`
AND city LIKE '_o%';

案例3:等值连接的连接条件
在这里插入图片描述

在这里插入图片描述

③ 添加分组+筛选
#案例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`;

在这里插入图片描述

在这里插入图片描述

为表起别名

①提高语句的简洁度
②区分多个重名的字段

注意: 如果为表起了别名,则查询的字段就不能使用原来的表名去限定

#查询员工名、工种号、工种名
SELECT e.last_name,e.job_id,j.job_title
FROM employees  e,jobs j
WHERE e.`job_id`=j.`job_id`;
两个表的顺序可以调换
#查询员工名、工种号、工种名

SELECT e.last_name,e.job_id,j.job_title
FROM jobs j,employees e
WHERE e.`job_id`=j.`job_id`;
可以加排序
#案例:查询每个工种的工种名和员工的个数,并且按员工个数降序

SELECT job_title,COUNT(*)
FROM employees e,jobs j
WHERE e.`job_id`=j.`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`
AND city LIKE 's%'

ORDER BY department_name DESC;

箭头所指是三个表的等值连接条件:
在这里插入图片描述

2、非等值连接
#案例1:查询员工的工资和工资级别

SELECT salary,grade_level
FROM employees e,job_grades g
WHERE salary BETWEEN g.`lowest_sal` AND g.`highest_sal`

AND g.`grade_level`='A';
select salary,employee_id from employees;
select * from job_grades;
CREATE TABLE job_grades
(grade_level VARCHAR(3),
 lowest_sal  int,
 highest_sal int);

INSERT INTO job_grades
VALUES ('A', 1000, 2999);

INSERT INTO job_grades
VALUES ('B', 3000, 5999);

INSERT INTO job_grades
VALUES('C', 6000, 9999);

INSERT INTO job_grades
VALUES('D', 10000, 14999);

INSERT INTO job_grades
VALUES('E', 15000, 24999);

INSERT INTO job_grades
VALUES('F', 25000, 40000);
3、自连接
#案例:查询 员工名和上级的名称  员工表-领导表

SELECT e.employee_id,e.last_name,m.employee_id,m.last_name
FROM employees e,employees m
WHERE e.`manager_id` = m.`employee_id`;

sql99语法

语法:
    select 查询列表
	from1 别名 【连接类型】
	【innerjoin2 别名 
	on 连接条件
	【where 筛选条件】
	【group by 分组】
	【having 筛选条件】
	【order by 排序列表】
分类:

在这里插入图片描述

内连接(★):inner
外连接
左外(★):left 【outer】
右外(★):right 【outer】一般很少用
全外:full【outer】
交叉连接:cross

一)内连接
语法:
SELECT 查询列表
FROM1 别名
INNER JOIN2 别名
ON 连接条件;
分类:

等值
非等值
自连接

特点:

①添加排序、分组、筛选
②INNER可以省略
③ 筛选条件放在WHERE后面,连接条件放在ON后面,提高分离性,便于阅读
④INNER JOIN连接和sql92语法中的等值连接效果是一样的,都是查询多表的交集

1、等值连接
#案例1.查询员工名、部门名

SELECT last_name,department_name
FROM departments d
INNER JOIN  employees e
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的部门名和员工个数,并按个数降序(添加排序)

#①查询每个部门的员工个数
SELECT COUNT(*),department_name
FROM employees e
INNER JOIN departments d
ON e.`department_id`=d.`department_id`
GROUP BY department_name

#② 在①结果上筛选员工个数>3的记录,并排序

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;

(添加分组+筛选+添加排序+三表连接)

#案例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;

二)非等值连接

#查询员工的工资级别

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左边的是主表
右外连接,right join右边的是主表

3、左外和右外交换两个表的顺序,可以实现同样的效果
4、全外连接=内连接的结果+表1中有 但表2没有的+表2中有 但表1没有的
*/

 #引入:查询男朋友 不在男神表的的女神名
USE `girls`;
SELECT * FROM beauty;
SELECT * FROM boys;
 #左外连接
 SELECT b.*,bo.*
 FROM boys bo
 LEFT OUTER JOIN beauty b
 ON b.`boyfriend_id` = bo.`id`
 WHERE b.`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;

sql92 vs sql99

功能:sql99支持的较多
可读性:sql99实现连接条件和筛选条件的分离,可读性较高


七、子查询

含义:

嵌套在其他语句内部的select语句称为子查询或内查询,
外面的语句可以是insert、update、delete、select等,一般select作为外面语句较多
外面如果为select语句,则此语句称为外查询或主查询

分类:

按子查询出现的位置:

  • select后面:
    要求:子查询的结果为单行单列(仅仅支持标量子查询)

  • from后面:
    要求:子查询的结果可以为多行多列,支持表子查询

  • where或having后面:★
    要求:子查询的结果为单列

    • 标量子查询(单行) √

    • 列子查询 (多行) √

    • 行子查询

  • exists后面(相关子查询)
    要求:子查询的结果为单列

    • 表子查询
    • 标量子查询
    • 列子查询
    • 行子查询
    • 表子查询
  • 按结果集的行列数不同:
    标量子查询(结果集只有一行一列)
    列子查询(结果集只有一列多行)
    行子查询(结果集有一行多列)
    表子查询(结果集一般为多行多列)

where或having后面----------

1、标量子查询(单行子查询)

2、列子查询(多行子查询)

3、行子查询(多列多行)

特点:

①子查询放在小括号内
②子查询一般放在条件的右侧
③标量子查询,一般搭配着单行操作符使用:> < >= <= = <>

列子查询,一般搭配着多行操作符使用:

in 判断某字段是否在指定列表内
not in ---- <>any
in ----- =any
any/some 判断某字段的值是否满足其中任意一个
all 判断某字段的值是否满足里面所有的

④子查询的执行优先于主查询执行,主查询的条件用到了子查询的结果

1.标量子查询★
#案例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


);
#非法使用标量子查询

SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
	SELECT  salary
	FROM employees
	WHERE department_id = 250


);
2.列子查询(多行子查询)★
#案例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)

);

#或
SELECT last_name
FROM employees
WHERE department_id  = ANY(
	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
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
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';
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;
 #案例2:查询员工号=102的部门名
 
SELECT (
	SELECT department_name,e.department_id
	FROM departments d
	INNER JOIN employees e
	ON d.department_id=e.department_id
	WHERE e.employee_id=102
	
) 部门名;

FROM后面------------------------------

将子查询结果充当一张表,要求必须起别名!!!!

#案例:查询每个部门的平均工资的工资等级
#①查询每个部门的平均工资
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id


SELECT * FROM job_grades;


#②连接①的结果集和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;

EXISTS后面(相关子查询)--------------

语法:
布尔类型

exists(完整的查询语句)

结果:1或0

SELECT EXISTS(SELECT employee_id FROM employees WHERE salary=300000);
#案例1:查询有员工的部门名

#in
SELECT department_name
FROM departments d
WHERE d.`department_id` IN(
	SELECT department_id
	FROM employees

)

#exists

SELECT department_name
FROM departments d
WHERE EXISTS(
	SELECT *
	FROM employees e
	WHERE d.`department_id`=e.`department_id`
);
#案例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`

);

八、分页查询 ★

应用场景:当要显示的数据,一页显示不全,需要分页提交sql请求
语法:

select 查询列表
	from 表
	
	【join type join2
	on 连接条件
	where 筛选条件
	group by 分组字段
	having 分组后的筛选
	order by 排序的字段】
	
	limitoffset,】size;
	
	offset要显示条目的起始索引(起始索引从0开始)
	size 要显示的条目个数

特点:
①limit语句放在查询语句的最后 执行顺序也是最后
②公式
要显示的页数 page,每页的条目数size

select 查询列表
fromlimit (page-1)*size,size;

size=10
page  
1	0
2  	10
3	20
#案例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关键字默认去重,如果使用union all 可以包含重复项

#引入的案例:查询部门编号>90或邮箱包含a的员工信息

SELECT * FROM employees WHERE email LIKE '%a%' OR department_id>90;;

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';

查询总结

语法:
select 查询列表 ⑦
from 表1 别名 ①
连接类型 join 表2 ②
on 连接条件 ③
where 筛选 ④
group by 分组列表 ⑤
having 筛选 ⑥
order by排序列表 ⑧
limit 起始条目索引,条目数; ⑨

查询终于结束了~~~~~~~~
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值