2.1 普通查询

语法:select 查询列表 from 表名;

2.1.1 查询表中的单个字段

SELECT last_name FROM employees;

2.1.2 查询表中多个字段

SELECT last_name,salary,email FROM employees;

2.1.3 查询表中的所有字段

SELECT * FROM employees;

2.1.4 查询常量

select 常量值;

注意:字符型和日期型的常量值必须用单引号引起来,数值型不需要
SELECT 100;
SELECT ‘join’;

2.1.5 查询函数

select 函数名(实参列表);
SELECT VERSION();

2.1.6 查询表达式

SELECT 100%98;

2.1.7 起别名

方式一:使用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;

2.1.8 去重( distinct)

select distinct 字段名 from 表名;
案例:查询员工表中涉及的所有部门编号
SELECT DISTINCT department_id FROM employees;

2.1.9 +号的作用

案例:查询员工的名和姓,并显示为姓名

java中的+号:
1.运算符:两个操作数都为数据型
2.连接符:只要有一个操作数为字符串
mysql中的+号:
只能作为运算符
select 100+90; 两个操作数都为数值型,做加法运算
select ‘123+90’;其中一方为字符型,试图将字符型数值转换为数值型
如果转换成功,则继续做加法运算
select ‘john’+90; 如果转换失败,则将字符型数值转换成0
select null+0; 只要其中一方为null,则结果肯定为null.

SELECT last_name+first_name AS 姓名 FROM employees;

2.1.11 ifnull函数

功能:判断某字段或表达式是否为null,如果为null 返回指定的值,否则返回原本的值
SELECT IFNULL(commission_pct,20) FROM employees;
当commission_pct为null时赋值该字段为20:
image.png

2.1.12 isnull函数

功能:判断某字段或表达式是否为null,如果是,则返回1,否则返回0
image.png

2.2 条件查询

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

2.2.1 按条件表达式筛选

条件运算符: >(大于) <(小于) =(等于) !=(不等于) <> (不等于)
>=(大于或等于) <= (小于或等于) <=>(安全等于)

<=>(安全等于):拥有=一样的功能同时还能判断是否为NULL

  1. #案例1:查询工资>12000的员工信息
  2. SELECT * FROM employees WHERE salary>12000;
  3. #案例2:查询部门编号不等于90号的员工名和部门编号
  4. SELECT last_name,department_id FROM employees WHERE department_id <> 90;

2.2.2 按逻辑表达式筛选

逻辑运算符: &&、 || 、 ! 、 and 、 or 、 not

&& 和 and:两个条件都为true,结果为true,反之为false<br />    || 和 or:只要有一个条件为true,结果为true,反之为false<br />    ! 或 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 department_id <90 OR department_id>110 OR salary>15000;

2.2.3 模糊查询

like:一般搭配通配符使用,可以判断字符型或数值型
通配符:%表示任意多个字符(包含0个),_表示任意单个字符 (不包含0个)
like、between and、in、is null

1、like

#案例1:查询员工名中包含字符a的员工信息
SELECT * FROM employees WHERE last_name LIKE '%a%';

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

#案例3:查询员工名种第二个字符为_的员工名
SELECT last_name FROM employees WHERE last_name LIKE '_\_%';

_2、_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;

注意事项:
1.提高语句简洁度
2.包含临界值
3.两个临界值不能调换顺序

3、in

含义:判断某字段的值是否属于in列表中的某一项
特点:
1.使用in提高语句简洁度
2.in列表的值类型必须一致或兼容

#案例1:查询员工的工种编号是IT_PROG、AD_VP、AD_PRES中的一个员工名和工种编号
SELECT last_name,job_id FROM employees WHERE job_id='IT_PROG' OR job_id='AD_PRES' OR job_id='AD_VP';
SELECT last_name,job_id FROM employees WHERE job_id IN('IT_PROG','AD_PRES','AD_VP');

4、escape(转义字符)

image.png
表示$为转义字符,把 _ 从关键字转成普通字符

5、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;
SELECT last_name,commission_pct FROM employees WHERE commission_pct IS NOT NULL;

2.3 排序查询

  • 语法:select 查询列表 from 表 【where 筛选条件】 order by
  • 特点:
    • 1.asc代表的是升序(从小到大),desc代表降序(从大到小),不写默认为升序
    • 2.order by子句中可以支持单个字段、多个字段、表达式、函数、别名
    • 3.order by子句一般是放在查询语句的最后面,limit子句除外 ```sql

      案例1:查询员工信息,要求工资从高到低排序

      SELECT FROM employees ORDER BY salary DESC; SELECT FROM employees ORDER BY salary;

案例2:查询部门编号是>=90,按入职时间的先后进行排序

SELECT * FROM employees WHERE department_id>=90 ORDER BY hiredate ASC;

案例3:按年薪的高低显示员工的信息和年薪【按表达式排序】

SELECT ,salary12(1+IFNULL(commission_pct,0)) 年薪 FROM employees ORDER BY salary12*(1+IFNULL(commission_pct,0)) DESC;

案例4:按年薪的高低显示员工的信息和年薪【按别名排序】

SELECT ,salary12(1+IFNULL(commission_pct,0)) 年薪 FROM employees ORDER BY salary12*(1+IFNULL(commission_pct,0)) 年薪 DESC;

案例5:按姓名的长度显示员工的姓名和工资【按函数排序】

SELECT LENGTH(last_name) 字节长度,last_name,salary FROM employees ORDER BY LENGTH(last_name) DESC;

案例6:查询员工共信息,要求按工资排序,再按员工编号排序【按多个字段排序】

SELECT * FROM employees ORDER BY salary ASC,employee_id DESC;

<a name="ki6p2"></a>
## 2.4 单行函数
<a name="rsHnY"></a>
### 2.4.1 字符函数
<a name="Mrkij"></a>
#### 1、length 
功能:获取参数值的字节值
```sql
SELECT LENGTH('subei');
SELECT LENGTH('鬼谷子qwe');

2、concat

功能:拼接字符串
语法:select concat(字符1,字符2,字符3,…);
image.png
image.png

SELECT CONCAT(last_name,'_',first_name) 姓名 FROM employees;

3、upper、lower

功能:

  • upper:变大写
  • lower:变小写 ```sql SELECT UPPER(‘ton’); SELECT LOWER(‘TON’);

示例:将姓变大写,名变小写,然后拼接

SELECT CONCAT(UPPER(last_name),LOWER(first_name)) 姓名 FROM employees;

<a name="3OOfv"></a>
#### 4、substr 
注意:索引从1开始

功能一:截取指定索引位置后面的所有字符<br />截取第4个字符开始的所有字符串:<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/2963105/1629250219890-93256db2-98ea-4aea-bfa9-e4781c8333ed.png#height=157&id=w7gpy&margin=%5Bobject%20Object%5D&name=image.png&originHeight=157&originWidth=437&originalType=binary&ratio=1&size=12948&status=done&style=none&width=437)<br />功能二:截取从指定索引处指定字符长度的字符<br />截取第2个字符开始长度为3的字符串:<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/2963105/1629250265934-d91bf3b0-601b-44c7-aa78-71496463d919.png#height=158&id=m84Ga&margin=%5Bobject%20Object%5D&name=image.png&originHeight=158&originWidth=455&originalType=binary&ratio=1&size=13534&status=done&style=none&width=455)

<a name="zDtgj"></a>
#### 5、instr
功能:获取子串第一次出现的索引,找不到返回0<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/2963105/1629250767573-35903dd9-3c73-427e-8886-ca241133237d.png#height=173&id=tRF2D&margin=%5Bobject%20Object%5D&name=image.png&originHeight=173&originWidth=542&originalType=binary&ratio=1&size=17238&status=done&style=none&width=542)

<a name="tPYZt"></a>
#### 6、trim
功能:去除前后空格或去除其他指定字符
```sql
SELECT LENGTH(TRIM('    霍山    ')) AS out_put;

SELECT TRIM('+' FROM '++++李刚+++刘邦+++') AS out_put;

image.png

7、lpad

功能:用指定的字符实现左填充指定长度
image.png

8、rpad

功能:用指定的字符实现右填充指定长度
image.png

9、replace

功能:替换指定字符
image.png

2.4.2 数学函数

1、round

功能:按四舍五入保留指定的位数

SELECT ROUND(1.45);
SELECT ROUND(1.567,2);

image.png

2、truncate

功能:截取到指定位数(不按照四舍五入)
image.png

3、ceil

功能:向上取整,返回>=该参数的最小整数
image.png
image.png

4、floor

功能:向下取整,返回<=该参数的最大整数
image.png

5、mod

功能:取余

SELECT MOD(10,3);

6、rand

功能:获取随机数,返回0-1之间的小数

SELECT RAND();

image.png

2.4.3 日期函数

1、now

功能:返回当前系统时间+日期
image.png

2、curdate

功能:返回当前日期
image.png

3、curtime

功能:返回当前时间
image.png

4、year

功能:返回年
image.png

5、month,monthname

功能:返回月
image.png
MONTHNAME:以英文形式返回月
image.png

6、day,datediff

功能:返回日
image.png
DATEDIFF:返回两个日期相差的天数
image.png

7、str_to_date

功能:将字符串通过指定格式转换成日期
image.png

8、date_format

功能:将日期格式化成字符串
image.png
image.png

2.4.4 其他函数

1、version

功能:当前数据库服务器的版本
image.png

2、database

功能:当前打开的数据库
image.png

3、user

功能:当前用户
image.png

4、password

功能:返回该字符的密码形式
image.png

5、md5

功能:返回该字符的md5加密形式
image.png

2.4.5 流程控制函数

1、if函数

image.png
image.png

2、case函数

使用一:switch 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;

使用二:类似于多重if else

/*
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;

2.5 分组函数(聚合函数)

  • sum 求和
  • max 最大值
  • min 最小值
  • avg 平均值
  • count 计数


    特点:
    1、以上五个分组函数都忽略null值,count()是需要所有字段都为null才会忽略
    2、sum和avg一般用于处理数值型
    max、min、count可以处理任何数据类型
    3、都可以搭配distinct使用,用于统计去重后的结果
    4、count的参数可以支持:
    字段、
    、常量值,一般放1(count(1))
    以上参数查询结果相同
    建议使用 count(*)

    注意:①聚合函数不能在where后面使用
    ②聚合函数不要相互套娃
    ③实现聚合的效果不一定要写到select后面,只需要写到having后面即可

2.6 分组查询

语法:
select 分组函数,分组后的字段
from 表
【where 筛选条件】
group by 分组的字段
【having 分组后的筛选条件】
【order by 排序列表】

特点:
1、可以按单个字段分组
2、和分组函数一同查询的字段最好是分组后的字段
3、分组筛选:
数据源 位置 关键字
分组前筛选: 原始表 group by的前面 where
分组后筛选: 分组后的结果集 group by的后面 having

4、可以按多个字段分组,字段之间用逗号隔开
5、可以支持排序
6、having后可以支持别名
7、能用分组前筛选的,就优先考虑使用分组前筛选

#引入:查询每个部门的平均工资
SELECT AVG(salary) FROM employees;

#案例1:查询每个工种的最高工资
SELECT MAX(salary),job_id FROM employees 
GROUP BY job_id;


#案例2:查询每个位置上的部门个数
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.查询每个部门的员工个数
SELECT COUNT(*),department_id FROM employees
GROUP BY department_id;

#2.根据1的结果进行筛选,查询哪个部门的员工个数大于2
SELECT COUNT(*),department_id FROM employees
GROUP BY department_id HAVING COUNT(*)>2;


#案例2:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资 
#1.查询每个工种有奖金的员工的最高工资 
SELECT MAX(salary),job_id FROM employees 
WHERE commission_pct IS NOT NULL GROUP BY job_id; 

#2.根据结果继续筛选,最高工资>12000 

SELECT MAX(salary), job_id FROM employees 
WHERE commission_pct IS NOT NULL GROUP BY job_id 
HAVING MAX(salary)>12000; 







#按表达式或函数分组

#案例:按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5

#1.查询每个长度的员工个数 
SELECT COUNT(*),LENGTH(last_name) len_name 
FROM employees GROUP BY LENGTH(last_name); 

#2.添加筛选条件
SELECT COUNT(*) c,LENGTH(last_name) len_name 
FROM employees GROUP BY len_name HAVING c>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;

2.7 连接查询

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

2.7.1 sql92标准

  • 仅仅支持内连接 ```sql

    1、等值连接

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

案例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、为表起别名

/* 1.提高语句的简洁度 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;

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

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;

<a name="2Xc0z"></a>
### 2.7.2 sql99标准

语法:<br />    select 字段,...<br />    from 表1<br />    【inner|left outer|right outer|cross】join 表2 on  连接条件<br />    【inner|left outer|right outer|cross】join 表3 on  连接条件<br />    【where 筛选条件】<br />    【group by 分组字段】<br />    【having 分组后的筛选条件】<br />    【order by 排序的字段或表达式】<br /> <br />    好处:语句上,连接条件和筛选条件实现了分离,简洁明了

分类:<br />内连接(★):inner(可以省略)<br />外连接     <br />左外(★):left 【outer】     <br />右外(★)right 【outer】     <br />全外:full【outer】 <br />交叉连接:cross

<a name="rvXlw"></a>
#### 1、内连接
![image.png](https://cdn.nlark.com/yuque/0/2021/png/2963105/1629382351490-a0541d61-090e-4f3c-97d9-b950837fb60a.png#height=120&id=L4aPT&margin=%5Bobject%20Object%5D&name=image.png&originHeight=120&originWidth=207&originalType=binary&ratio=1&size=11610&status=done&style=none&width=207)<br />语法:<br />select 查询列表<br />from 表1 别名<br />inner join 表2 别名<br />on 连接条件;<br />分类:<br />等值连接<br />非等值连接<br />自连接<br />特点:<br />①添加排序、分组、筛选<br />②inner可以省略<br />③ 筛选条件放在where后面,连接条件放在on后面,提高分离性,便于阅读<br />④inner join连接和sql92语法中的等值连接效果是一样的,都是查询多表的交集
```sql
#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的城市名和部门个数,(添加分组+筛选)

#1.查询每个城市的部门个数
#2.在1结果上筛选满足条件的
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结果上筛选员工个数>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%';

2、外连接

应用场景:用于查询一个表中有,另一个表没有的记录

语法:
select 查询列表
from 表1 别名
left 【outer】 join 表2 别名/right 【outer】 join 表2 别名/full 【outer】 join 表2 别名
on 连接条件;
分类:
左外连接
右外连接
全外连接

特点:
1、外连接的查询结果为主表中的所有记录
如果从表中有和它匹配的,则显示匹配的值
如果从表中没有和它匹配的,则显示null
外连接查询结果=内连接结果+主表中有而从表没有的记录
2、 左外连接,left join左边的是主表
image.pngimage.png
右外连接,right join右边的是主表
image.pngimage.png
3、左外和右外交换两个表的顺序,可以实现同样的效果
4、全外连接=内连接的结果+表1中有但表2没有的+表2中有但表1没有的
image.pngimage.png

#左外连接
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;

3、交叉连接

  • 查询效果为笛卡尔乘积
    SELECT b.*,bo.* FROM beauty b
    CROSS JOIN boys bo;
    

    2.8 子查询

    含义:
    一条查询语句中又嵌套了另一条完整的select语句,其中被嵌套的select语句,称为子查询或内查询
    在外面的查询语句,称为主查询或外查询。

分类:
image.png
特点:
①子查询放在小括号内
②子查询一般放在条件的右侧
③标量子查询,一般搭配着单行操作符使用 > < >= <= = <> 列子查询,一般搭配着多行操作符使用 in、any/some、all
④子查询的执行优先于主查询执行,主查询的条件用到了子查询的结果

2.8.1 多行操作符

①in:在范围内的值,只要有就true
②any/some:与子查询返回的任何值比较为true 则返回true
③all:与子查询返回的所有值比较为true 则返回true

2.8.2 标量子查询

  • 结果集只有一行一列 ```sql

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

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

) 部门名;

<a name="rIw0Y"></a>
### 2.8.3 列子查询

- 结果集只有一列多行
```sql
#案例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  <>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
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';

2.8.4 行子查询

  • 结果集只有一行多列 ```sql

    案例:查询员工编号最小并且工资最高的员工信息

SELECT * FROM employees WHERE (employee_id,salary)=( SELECT MIN(employee_id),MAX(salary) FROM employees );

①查询最小的员工编号

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

<a name="nkdrT"></a>
### 2.8.5 表子查询

- 结果集一般为多行多列
```sql
#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;

2.8.6 exists后面(相关子查询)

  • 语法: exists(完整的查询语句)
  • 结果: 1或0 ```sql 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 );

<a name="puNDN"></a>
## 2.9 分页查询
应用场景:当要显示的数据,一页显示不全,需要分页提交sql请求。<br />语法:<br />select 字段|表达式,...<br />    from 表<br />    【where 条件】<br />    【group by 分组字段】<br />    【having 条件】<br />    【order by 排序的字段】<br />    limit 【offset,】size;<br />注意:offset不写默认值为0,从offset开始查询size条数据<br />特点:<br />    1.起始条目索引从0开始<br />    2.limit子句放在查询语句的最后 <br />    3.公式:select * from  表 limit (page-1)*sizePerPage,sizePerPage<br />    假如:<br />    每页显示条目数sizePerPage<br />    要显示的页数 page

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

2.10 联合查询

  • 含义:union (联合、合并):将多条查询语句的数据合并成一个结果。两个查询语句查询出来的数据字段数量和类型相同才能将它们合并成一个大数据。

  • 语法:

查询语句1 union 【all】
查询语句2 union 【all】

  • 意义:

1、将一条比较复杂的查询语句拆分成多条语句
2、适用于查询多个表的时候,查询的列基本是一致。

  • 特点:

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,csex FROM t_ca WHERE csex='男'
UNION
SELECT t_id,tName,tGender FROM t_ua WHERE tGender='male';

2.11 查询顺序

  1. FROM
    2. ON
    3. JOIN
    4.WHERE
    5. GROUP BY
    6. HAVING
    7. SELECT
    8. DISTINCT
    9. ORDER BY
    10. LIMIT