Skip to content

Latest commit

 

History

History
1104 lines (922 loc) · 29.9 KB

02.DQL语言.md

File metadata and controls

1104 lines (922 loc) · 29.9 KB

5. DQL语言

Data Query Language

查询: select

5.1 基础查询

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

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

1. 查询表中的字段

use myemployees;

#查询表中的单个字段
select last_name from employees;

#查询表中的多个字段
select last_name, salary, email from employees;

#查询表中的所有字段
select * from employees;

select `name` from employees;

2. 查询常量值

  • 字符型和日期型的常量值必须用单引号,数值型不需要
select 100;
select 'john';

3. 查询表达式

  • 不支持++、--、*=
select 100*98;
select 100%98;

4. 查询函数

  • 函数必须有返回值
select VERSION();

5. 起别名

  • 便于理解
  • 如果查询的字段有重名的情况,使用别名可以区分开
#方式一
select 100*98 as result;
select last_name as lastName, first_name as firstName from employees;

#方式二
select last_name lastName, first_name firstName from employees;
select salary as 'out put' from employees;

6. 去重 distinct

select department_id from employees;
select distinct department_id from employees;

7. +号的作用,concat()

  • mysql中的+号只有一个功能:运算符
#两个操作数都为数值型,则做加法运算
select 100+90;

#只要一方为字符型,试图将字符型数值转换成数值型
#如果转换成功,则继续做加法运算
#如果转换失败,则将字符型数值转换为0
select '123'+90;
select 'john'+90;

#只要其中一方为null,结果肯定为null
select null+10;

#查询员工名和姓连接成一个字段,并显示为姓名
select concat(last_name, first_name) as 'name' from employees;

8. ifnull()

select 
    concat(first_name,',',last_name,',', ifnull(commission_pct,0)) as out_put 
from 
    employees;

9. isnull()

  • 判断某字段或表达式是否为null,如果是,返回1,否则返回0
select isnull(commission_pct), commission_pct from employees;

5.2 条件查询

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

执行顺序:from -> where -> select

分类:

  1. 按条件表达式筛选
    • 条件运算符:>, <, =, <>, >=, <=
  2. 按逻辑表达式筛选
    • 逻辑运算符: && || !
    • and or not
  3. 模糊查询
    • like
    • between and
    • in
    • is null

1. 按条件表达式筛选

#查询工资>12000的员工信息
select * from employees where salary > 12000;

#查询部门编号不等于90号的员工名和部门编号
select last_name, department_id from employees where department_id<>90;

2. 按逻辑表达式筛选

#查询工资在10000到20000之间的员工名、工资以及奖金
select last_name, salary, commission_pct from employees where salary>=10000 and salary<=20000;

#部门编号不是在90到110之间,或者工资高于15000的员工信息
select * from employees where department_id<90 or department_id>110 or salary>15000;
select * from employees where not(department_id>=90 and department_id<=110) or salary>15000;

3. 模糊查询

like

  • 一般和通配符搭配使用
    • % 任意多个字符,包含零个字符
    • _ 任意单个字符
#查询员工名中包含a的员工信息
select * from empolyees where last_name like '%a%';

#查询员工名中第三个字符为e,第五个字符为a的员工名和工资
select last_name, salary from employees where last_name like '__n_l%';

#查询员工名中第二个字符为_的员工名
select last_name from employess where last_name like '_\_%';
#推荐
select last_name from employess where last_name like '_$_%' escape '$';

between and

  • 提高语句简洁度
  • 包含临界值
  • 两个临界值不要调换顺序
#查询员工编号在100到120之间的员工信息
select * from employees where employee_id between 100 and 120;

in

  • 判断某字段的值是否属于in列表中的一项
  • 提高语句简洁度
  • in列表的值类型必须一致或兼容
  • 不支持通配符
#查询员工的工种编号是 IT_PROG、AD_VP、AD_PRES中的一个员工名和工种编号
select last_name, job_id from emplyees where job_id in('IT_PROG', 'AD_VP', 'AD_PRES');

is null

  • = 或 <> 不能用于判断null值
  • is null 或 is not null 可以
#查询没有奖金的员工名和奖金率
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;

安全等于 <=>

  • 可读性较差
#查询没有奖金的员工名和奖金率
select last_name, commission_pct from employees where commission_pct <=> null;

#查询工资为12000的员工信息
select last_name, commission_pct from employees where salary <=> 12000;

5.3 排序查询

语法:select 查询列表 from 表名 where 筛选条件 order by 排序列表 asc|desc;

  • 执行顺序:from -> where -> select -> order by
  • 默认升序
  • asc 升序
  • desc 降序
  • order by子句 中可以支持单个字段,多个字段,表达式,函数,别名
  • order by子句 一般放在查询语句的最后面,但 limit子句 除外
#查询员工信息,要求工资从高到低排序
select * from employees order by salary desc;

#查询部门编号>=90的员工信息,按入职时间的先后进行排序
select * from employees where department_id >= 90 order by hiredate asc;

#按表达式排序:按年薪的高低显示员工信息和年薪
select *, salary*12*(1+ifnull(commission_pct, 0)) annualPay from employees order by salary*12*(1+ifnull(commission_pct, 0)) desc;

#按别名排序:按年薪的高低显示员工信息和年薪
select *, salary*12*(1+ifnull(commission_pct, 0)) annualPay from employees order by annualPay desc;

#按函数排序:按姓名的长度显示员工的姓名和工资
select length(last_name), last_name, salary from emoloyees order by length(last_name) desc;

#查询员工信息,要求先按工资排序,再按员工编号排序
select * from employees order by salary asc, employee_id desc;

5.4 常见函数

  • 将一组逻辑语句封装在方法体中,对外暴露方法名
  • 隐藏实现细节
  • 提高代码的重用性

语法:select 函数名(实参列表) from 表名;

  1. 函数名
  2. 函数功能

1. 单行函数

concat、length、ifnull

  • 字符函数
#length 获取参数值的字节数
select length('john');
show variables like '%char%'

#concat 拼接字符串
select concat(last_name, '_', first_name) from employees;

#upper、lower
select upper('john');
select lower('joHn');
#将姓变大写,名变小写,然后拼接
select concat(upper(last_name), lower(first_name)) 'name' from employees;

#substr、substring
#索引从1开始
#截取从指定索引处后面的所有字符
select substr('hello_world', 7) out_put;
#截取从指定索引处指定字符长度的字符
select substr('hello_world', 1, 5) out_put;
#将姓名中首字符大写,其他字符小写,用_拼接
select concat(upper(substr(last_name, 1, 1)), '_', lower(substr(last_name, 2))) out_put
from employees;

#instr 返回子串第一次出现的索引,如果找不到返回0
select instr('hello_word_word', 'word') as out_put;

#trim 去前后
select length(trim('    hello    ')) as out_put;
select trim('a' from 'aaaheaaalloaaa') as out_put;

#lpad 用指定字符实现左填充指定长度
select lpad('hello', 10, '*') as out_put;

#rpad 用指定字符实现右填充指定长度
select rpad('hello', 10, '*') as out_put;

#replace 替换
select replace('hello_world', 'world', 'mysql') as out_put;
  • 数学函数
#round 四舍五入
select round(1.65);
select round(1.567, 2);

#ceil 向上取整,返回>=该参数的最小整数
select ceil(1.52);

#floor 向下取整
select floor(-9.99);

#truncate 截断
select truncate(1.65, 1);

#mod 取余 a-a/b*b
select mod(10, 3);
  • 日期函数
#now 返回当前系统日期+时间
select now();

#curdate
select curdate();

#curtime
select curtime();

#获取指定的部分
select year(now());
select year('1998-1-1');
select year(hiredate) from employees;

select month(now());
select monthname(now());

#str_to_date 将日期格式的字符转换成指定格式的日期
/*
%Y  四位的年份
%y  两位的年份
%m  月份(01,02...11,12)
%c  月份(1,2,...11,12)
%d  日(01,02,...)
%H  小时(24小时制)
%h  小时(12小时制)
%i  分钟(00,01...59)
%s  秒(00,01...59)
*/
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');
#查询有奖金的员工名和入职日期(x月/x日 x年)
select last_name, date_format(hiredate, '%m/%d %Y') from employees;

#天数
select datediff(now(), '1997-5-14');
  • 其他函数
select version();
select database();
select user();
#返回MD5加密形式
select md5('字符');
  • 流程控制函数
#if函数
select if(10 > 5, 'yes', 'no');

SELECT 
    last_name,
    commission_pct,
    IF(commission_pct IS NULL, 'no', 'yes') AS result
FROM
    employees;

#case函数: switch case
/*
case 要判断的字段或表达式
when 常量1 then 要显示的值1或语句1
when 常量2 then 要显示的值2或语句2
else 要显示的值n或语句n;
end
*/
#查询员工的工资,要求
#部门号=30,显示的工资为1.1倍
#部门号=40,显示的工资为1.2倍
#部门号=50,显示的工资为1.3倍
#其他部门,显示的工资为原工资
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 'new'
FROM
    employees;
#case: 多重if
/*
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 'order'
FROM
    employees;

2. 分组函数

  • 做统计使用,又称为统计函数、聚合函数、组函数
  • sum, avg 一般处理数值型
  • max, min, count 可以处理任何类型
  • 所有分组函数都忽略 null
  • 可以和 distinct 搭配
  • 一般使用 count(*) 统计行数
  • 和分组函数一同查询的字段要求是 group by 后的字段
#sum
select sum(salary) from employees;
#avg
select avg(salary) from employees;
#max
select max(salary) from employees;
#min
select min(salary) from employees;
#count
select count(salary) from employees;

select sum(salary) 'sum', round(avg(salary), 2) 'avg' from employees;

#参数支持哪些类型
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(last_name) from employees;
select count(commission_pct) from employees;

#是否忽略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;

#和 distinct 搭配
select sum(distinct salary), sum(salary) from employees;
select count(distinct salary), count(salary) from employees;

#count函数的详细介绍
select count(salary) from employess;
#统计行数
select count(*) from employess;

select count(1) from employess;

#效率
#MYISAM存储引擎下,cout(*)的效率高
#INNODB存储引擎下,cout(*)和count(1)的效率差不多,比count(字段)要高一些

#和分组函数一同查询的字段有限制
#select avg(salary), employee_id from employees;

5.5 分组查询

语法: select 分组函数, 分组后的字段(要求出现在 group by 的后面) from 表名 where 筛选条件 group by 分组的字段 having 分组后的筛选 order by 排序列表;

  • 查询列表要求是分组函数和 group by 后出现的字段
  • 分组查询中的筛选条件分为两类
    • 分组前筛选:原始表 | group by子句的前面 | where
    • 分组后筛选:分组后的结果集 | group by子句的后面 | having
  • 分组函数做条件肯定放在 having 子句中
  • 能用分组前筛选,优先考虑分组前筛选
  • group by子句支持单个字段分组,多个字段分组(多个字段之间用逗号隔开,没有顺序要求)
  • 排序放在整个分组查询的最后

  • 简单筛选
#查询每个部门的平均工资

#查询每个工种的最高工资
select max(salary), job_id from employees group by job_id;

#查询每个位置上的部门个数
select count(*), location_id from departments group by location_id;

#添加筛选条件
#查询邮箱中包含a字符的,每个部门的平均工资
select avg(salary), department_id from employees where email like '%a%' group by department_id;

#查询有奖金的每个领导手下员工的最高工资
select max(salary), manager_id from employees where commission_pct is not null group by manager_id;
  • 复杂筛选
#查询哪个部门的员工个数 > 2
#1. 查询每个部门的员工个数
select count(*), department_id from employees group by department_id;
#2. 筛选哪个部门的员工个数>2
select count(*), department_id from employees group by department_id having count(*)>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;

#查询领导编号>102的每个领导手下的最低工资>5000的领导编号是哪个,以及其最低工资
#查询每个领导手下的最低工资
select min(salary), manager_id from employees group by manager_id;
#编号>120
select min(salary), manager_id where manager_id > 102 from employees group by manager_id;
#最低工资>5000
select min(salary), manager_id where manager_id > 102 from employees group by manager_id having min(salary)>5000;
  • 按表达式或函数筛选
#按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的有哪些
select count(*), length(last_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
WHERE
    department_id IS NOT NULL
GROUP BY department_id , job_id
HAVING AVG(salary) > 10000
ORDER BY AVG(salary) DESC;

5.6 连接查询

多表查询:当要查询的字段来自多个表

select 字段1, 字段2 from 表1, 表2;

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

发生原因:没有有效的连接条件

1. 分类

  • 按年代
    • sql92:仅支持内连接
    • sql99(推荐):支持内连接+外连接(左外+右外)+ 交叉连接
  • 按功能
    • 内连接:等值连接、非等值连接、自连接
    • 外连接:左外连接、右外连接、全外连接(mysql不支持)
    • 交叉连接

2. sql92标准

  • 等值连接

select 查询列表 from 表1 别名, 表2 别名 where 表1.key = 表2.key and 筛选条件 group by 分组字段 having 分组后的筛选 order by 排序字段;

  1. 多表等值连接的结果为多表的交集部分
  2. n表连接,至少需要n-1个连接条件
  3. 多表的顺序没有要求
  4. 一般需要为表起别名
  5. 可以搭配前面介绍的所有子句使用,比如排序,分组,筛选
#查询女神名对应的男神名
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, e.job_id, job_title
FROM
    jobs j,
    employees e
WHERE
    e.job_id = j.job_id;

#可以加筛选
#查询有奖金的员工名、部门名
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;
#查询城市名中第二个字符为o的部门名和城市名
SELECT 
    department_name, city
FROM
    departments d,
    locations l
WHERE
    d.location_id = l.location_id
        AND city LIKE '_o%';

#加分组
#查询每个城市的部门个数
SELECT 
    COUNT(*), city
FROM
    departments d,
    locations l
WHERE
    d.location_id = l.location_id
GROUP BY city;
#查询有奖金的每个部门的部门名和部门的领导编号和该部门的最低工资
SELECT 
    department_name, d.manager_id, MIN(salary)
FROM
    employees e,
    departments d
WHERE
    e.department_id = d.department_id
        AND commission_pct IS NOT NULL
GROUP BY department_name , d.manager_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;
  • 非等值连接

select 查询列表 from 表1 别名, 表2 别名 where 非等值的连接条件 and 筛选条件 group by 分组字段 having 分组后的筛选 order by 排序字段;

#查询员工的工资和工资级别
SELECT 
    salary, grade_level
FROM
    employees e,
    job_grades j
WHERE
    salary BETWEEN j.lowest_sal AND j.highest_sal;
  • 自连接

select 查询列表 from 表 别名1, 表 别名2 where 等值的连接条件 and 筛选条件 group by 分组字段 having 分组后的筛选 order by 排序字段;

#查询员工名和上级的名称
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;

3. sql99标准

select 查询列表 from 表1 别名 连接类型 join 表2 别名 on 连接条件 where 筛选条件;

内连接: inner

  • 等值连接
  • 非等值连接
  • 自连接

语法: select 查询列表 from 表1 别名 inner join 表2 别名 on 连接条件;

特点:

  • 表的顺序可以调换
  • 内连接的结果 = 多表的交集
  • n表连接至少需要 n-1 个连接条件

  • 等值连接
#1. 添加排序、分组、筛选
#2. inner 可以省略
#3. 筛选条件放在where后面,连接条件放在on后面,提高分离性,便于阅读
#4. inner join 连接 和 sql92语法中的等值连接效果是一样的,都是查询交集

#查询员工名、部门名
select last_name, depart_name from employees e inner join department d on e.department_id = d.department_id;

#添加筛选:查询名字中包含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的城市名和部门个数
select city, count(*) from locations l inner join departments d on d.location_id = l.location_id group by city having count(*) > 3;

#添加排序
#查询哪个部门的员工个数>3的部门名和员工个数,并按个数降序
select department_name, count(*) 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.depaetment_id inner join jobs on e.job_id = j.job_id order by department_name desc;
  • 非等值连接
#查询员工工资级别
SELECT 
    salary, grade_level
FROM
    employees e
        JOIN
    job_grades j ON e.salary BETWEEN j.lowest_sal AND j.highest_sal;  
#查询工资基别的个数>2的个数,并且按工资级别降序
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;  
  • 自连接
#查询员工的名字和上级的名字
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%';

外连接

  • 左外: leftouter
  • 右外: rightouter
  • 全外: fullouter

语法: select 查询列表 from 表1 别名 left|right|full outer join 表2 别名 on 连接条件;

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

特点:

  1. 外连接的查询结果为主表中的所有记录,如果从表中有匹配的,则显示匹配的值;如果没有,则显示null
  2. 左外连接:left 左边的是主表
  3. 右外连接:right 右边的是主表
  4. 全外连接:full join 两边都是主表
  5. 左外和右外交换两个表的顺序可以实现同样的效果
  6. 一般用于查询除了交集部分的剩余的不匹配的行
#查询男朋友不在男神表的女神名
#左外连接
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;

#查询哪个部门没有员工
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;

#全外连接 = 内连接的结果 + 表1中有但表2中没有的 + 表2中有但表1中没有的
select b.*, bo.* from beauty b full outer join bo on b.boyfriend_id = bo.id;

交叉连接(mysql不支持): cross

语法: select 查询列表 from 表1 别名 cross join 表2 别名;

特点:类似于笛卡尔乘积

select b.*, bo.* from beauty b cross join boys bo;

5.7 子查询

含义:

  • 出现在其他语句中的select语句,成为子查询或内查询
  • 外部的查询语句,称为主查询或外查询
  • 主查询可以是 insert, update, delete, select,一般是select

分类:

  • 按子查询出现的位置
    • select 后面:仅支持标量子查询
    • from 后面:表子查询
    • ⭐where / having 后面:⭐标量子查询,⭐列子查询,行子查询
    • exists 后面(相关子查询):表子查询
  • 按结果集的行列数
    • 标量子查询(结果集只有一行一列)
    • 列子查询(一列多行)
    • 行子查询(一行多列)
    • 表子查询(一般为多行多列)

1. where / having 后面

  1. 子查询在小括号内
  2. 子查询一般放在条件的右侧
  3. 标量子查询,一般配合单行操作符使用 >、<、<=、>=、<>
  4. 列子查询,一般搭配多行操作符使用 ⭐in、any/some、all
  5. 子查询的执行优先于主查询的执行
#标量子查询(单行子查询)
#谁的工资比Abel高
select * from employees where salary > (select salary from emoloyees where last_name = 'Abel');
#返回job_id与141号员工相同,salary比143号多的员工 姓名、job_id 和工资
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
);
#返回公司工资最少的员工的last_name, job_id 和 salary
select last_name, job_id, salary from employees where salary = (
    select min(salary) from employees
); 
#查询最低工资大于50号部门最低工资的部门id和其最低工资
select department_id, min(salary) from employees group by department_id having min(salary) >(
    select min(salary) from employees where department_id = 50
);
#非法使用标量子查询
select department_id, min(salary) from employees group by department_id having salary >(
    select min(salary) from employees where department_id = 50
);


#列子查询(多行子查询)
#返回lacation_id是1400或1700的部门中的所有员工姓名
#1.查询location_id是1400或1700的部门编号
select distinct department_id from departments where location_id in(1400, 1700);
#2.查询员工姓名
select last_name from employees where department_id in(
    select distinct department_id from departments where location_id in(1400, 1700);
);
#返回其他部门中比job_id为'IT_PROG'部门任一工资低的员工的工号、姓名、job_id以及salary
#1. 查询job_id为'IT_PROG'部门任一工资
select distinct salary from employees where job_id = 'IT_PROG';
#2. 查询员工的工号、姓名、job_id以及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 * from employees where (employee_id, salary) = (
    select min(employee_id), max(salary) from employees;
);

#1. 查询最小的员工编号
select min(employee_id) from employees;
#2. 查询最高工资
select max(salary) from employees;
#3. 查询员工信息
select * from employees where employee_id = (
    select min(employee_id) from employees
) and salary = (
    select max(salary) from employees
);

2. select 后面(仅支持标量子查询)

#查询每个部门的员工个数
SELECT 
    d.*,
    (SELECT 
            COUNT(*)
        FROM
            employees e
        WHERE
            e.department_id = d.department_id)
FROM
    departments d;
#查询员工号=102的部门名
SELECT 
    (SELECT 
            department_name
        FROM
            departments d
                INNER JOIN
            employees e ON d.department_id = e.department_id
        WHERE
            e.employee_id = 102);

3. from 后面

#查询每个部门的平均工资的工资等级
#1.每个部门的平均工资
select avg(salary), department_id from employees group by department_id;
#2.
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;

4. exists 后面(相关子查询)

语法:exists(完整的查询语句)

结果:1或0

select exists(select employee_id from employees where salary = 30000);
#查询有员工名的部门名
SELECT 
    department_name
FROM
    departments d
WHERE
    EXISTS( SELECT 
            *
        FROM
            employees e
        WHERE
            e.department_id = d.department_id);
#查询没有女朋友的男生信息
select bo.* from boys bo where bo.id not in(
    select boyfrined_id from beauty
);
select bo.* from boys bo where not exists(
    select boyfrined_id from beauty b where bo.id = b.boyfrined_id
);

5.8 分页查询

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

语法:select 查询列表 from 表名 jointype join 表2 on 连接条件 where 筛选条件 group by 分组字段 having 分组后的筛选 order by 排序的字段 limit offset,size;

  • offset:要显示条目的起始索引(从0开始)
  • size:要显示的条目个数
  • from -> join on -> where -> group by -> having -> select -> order by -> limit

特点:

  • limit语句放在查询语句的最后
  • 公式:要显示的页数page, 每页的条目数size
    • select 查询列表 from 表 limit (page - 1)*size, size;
#查询前5条员工信息
SELECT 
    *
FROM
    employees
LIMIT 0 , 5;
SELECT 
    *
FROM
    employees
LIMIT 5;
#查询第11条到第25条
SELECT 
    *
FROM
    employees
LIMIT 10, 15;
#有奖金的员工信息,并且工资较高的前10名显示
SELECT 
    *
FROM
    employees
WHERE
    commission_pct IS NOT NULL
ORDER BY salary DESC
LIMIT 0 , 10;

5.9 联合查询

union:合并,将多条查询语句的结果合并成一个结果

应用场景:要查询的结果来自于多个表,且多个表没有直接的连接关系,但查询的信息一致

特点:

  1. 要求多条查询语句的查询列数是一致的
  2. 要求多条查询语句的查询的每一列的类型和顺序最好一致
  3. 默认去重,使用 union all 查询所有数据项
#查询部门编号>90或邮箱包含a的员工信息
select * from employees where email like '%a%'
union #all
select * from employees where department_id > 90;

5.10 查询总结

语法:

select 查询列表
from1 别名
连接类型 join2
on 连接条件
where 诗选
group by 分组列表
having 筛选
order by 排序列表
limit 起始条目索引, 条目数;

执行顺序:

from -> join -> on -> where -> group by -> having -> select -> order by -> limit

实际生产过程:

select * from 表名;
#实际写全各个列名(可读性,效率高)