一、DML增删改语句
概念:数据操作语⾔ Data Mainpulation Language 【数据可表中的数据的增删改操作】
1、insert增加
格式:
单插:insert into 表名(列名,列名……) values (值1,值2……)
INSERT INTO ss(`name`,age) VALUES('cc',34);
多插:insert into 表名(列名,列名……) values (值1,值2……),(值1,值2……),(值1,值2……)
INSERT INTO ss(`name`,age) VALUES('ff',34),('bb',33),('aa',35);
注意:
① 插⼊值为整型或者浮点型 不⽤加引号 如果是 字符型 或者 ⽇期类型需要加引号(单双都可以)
② 如果所有列的值都要插⼊ 表名后的列名可以省略 否则不能省略
③ 列名的顺序可以颠倒 但是values的值需要和列名⼀⼀对应
④ 如果列的约束是 可以为空或者有默认值 可以不⽤添加值
⑤ 插⼊的值⼀定要符合列的类型和约束
2、delete 删除数据
格式:
delete from 表名 where 条件;
DELETE FROM ss WHERE age = 34
delete from 表名;全部删除
DELETE FROM ss
truncate table 表名;全部删除 推荐使用
TRUNCATE TABLE ss
3、update 更新数据
格式:
update 表名 set 列名=新值,列名=新值,………where条件;
UPDATE ss SET `name`='chen' WHERE age = 33
注意:
1、where 条件一定要加 否则所有数据都会被修改
2、一般主键作为条件 效率高
4、delete全删和truncate全删的区别?
1、delete删除后面可以加where条件 truncate 不可以,但是删除效率高
2、delete支持回滚、可以退回,truncate 不支持回滚
3、delete 不会删除自增的记录,truncate 会自增的
5、MySQL中常⻅的类型
【整型】:tinyint/smallint/int/bigint
【浮点型】:float(n,m) double(n,m) decimal(n,m) 准确的浮点型
n: 代表 整数位和⼩数位总和
m: 代表⼩数位的个数
【字符型】
varchar(n) 变⻓字符串 效率相对低 n保存字符的最⼤个数 必写
char(n) 定⻓字符串 效率相对⾼ n保存字符的最⼤个数 可选 默认1
【⽇期类型】
date ⽇期
time 时间
datetime ⽇期+时间 8字节 不受时区和服务器的版本影响
取值范围:1900-1-1~ 9999-12-31
timestamp ⽇期+时间 4字节 受时区和服务器的版本影响
取值范围:1970-1-1~2038-12-31
二、DQL
数据查询语⾔:提供了各种情况的数据库表数据的查询 关键字:select
分类:
基本查询
条件查询
排序查询
分组查询
分⻚查询
多表查询
⼦查询
1、基本查询
- 基本查询
格式:
select 查询列表 from 表名;
特点:
1. 查询的结果是虚拟表
2. 查询列表可以是 常量、变量、函数、表达式、字段或组合
-- ========================= 1. 基本查询 ======================
-- 选中库
use myemployees;
-- 查询常量
select 100;
-- 查询表达式
select 100+99;
-- 函数
select version();
select user();
-- 字段
select * from employees;
select first_name,last_name,salary from employees;
-- 组合
select first_name, last_name, user(), 100+200 from employees;
2、条件查询
格式:
select 查询列表 from 表名 where 条件;特点:
1. 条件:关系表达式(> < >= <= <> !=)
2. 条件:逻辑表达式 (and or !)【&& || !】
3. 模糊:like / between…and… / in / is null
-- 1、条件:关系表达式【> < >= <= != <>】
-- 案例1:查询薪资大于5000的员工 姓、名、薪资
select first_name,last_name,salary
from employees
where salary > 5000;
-- 案例2:查询薪资不等于9000 的员工信息
select *
from employees
where salary <>9000;
-- 2、条件:逻辑表达式【and 、or、not】
-- 案例3:查询员工薪资大于5000 并且小于12000 的员工名和薪资
select last_name,salary
from employees
where salary > 5000 and salary < 12000;
-- 案例4:查询员工薪资等于6000 或者 9000的员工信息
select *
from employees
where salary =6000 or salary=9000;
-- 案例5:查询薪资不在 5000 到 12000之间的员工信息
select *
from employees
where not (salary > 5000 and salary < 9000);
-- 3、模糊:like \ between...and... \ in \ is null
/*
% 代表任意个数任意字符
_ 代表任意⼀个字符
\ 可以转移特殊字符
*/
-- %任意多个字符
-- 案例6:查询员工名中包含a字符的员工信息
select *
from employees
where last_name like '%a%';
-- _ 任意一个字符
-- 案例7:查询员工名中第三个字符是e字符的员工信息
select *
from employees
where last_name like '__e%';
-- 案例8:查询员工名中第二个字符是_字符的员工信息
select *
from employees
where last_name like '_\_%';
-- 【between... and.....】
/*
1. 等价于 逻辑表达式的结果
2. between后接⼩值 and后接⼤值
3. 既包含between后的值 也包含and后的值
*/
--案例9:查询员工薪资在6000 和 9000之间的员工信息
select *
from employees
where salary between 6000 and 9000;
--【in】
-- 案例10:查询员工编号为 102,103,104,105 的员工信息
select *
from employees
where employee_id in (102,103,104,105);
3、排序查询
语法:
select 查询列表
from 表名
where 条件
order by 排序列表 asc | desc特点:
1、排序列表:单字段、多字段、表达式、函数、别名或组合
2、asc 升序(默认) desc 降序
3、排序字段可以是数值 也可以是 字符
-- 案例1:查询员工信息 并按照薪资降序
select *
from employees
order by salary desc;
-- 案例2:查询薪资大于5000的员工信息 并按照薪资升序
select *
from employees
where salary > 5000
order by salary asc;
-- 多字段
-- 案例3:查询薪资大于5000的员工信息 并按照薪资降序,如果薪资相同按照名升序
select *
from employees
where salary > 5000
order by salary desc,last_name asc;
-- 表达式
-- 案例4:查询薪资大于10000员工的名,薪资和年薪,奖金 并按照年薪降序
-- ifnull(不为null取值, 为null取值)
select last_name,salary,(salary*12*(IFNULL(commission_pct,0)+1)),commission_pct
from employees
where salary > 10000
order by (salary*12*(IFNULL(commission_pct,0)+1)) desc;
-- 【别名】
-- 案例4:查询薪资大于10000员工的名,薪资和年薪,奖金 并按照年薪降序
select last_name,salary,(salary*12*(IFNULL(commission_pct,0)+1)) as 年薪,commission_pct
from employees
where salary > 10000
order by 年薪 desc ;
-- 【函数】
-- 案例5:查询薪资大于10000的员工名和名的长度,并按照名长度降序
select last_name,length(last_name)
from employees
where salary > 10000
order by length(last_name) desc ;
4、常见函数
字符函数
length() 【获取字符长度】
upper() 【将字符转为大写】
lower() 【将字符转为小写】
substr() 【截取字符】
trim() 【去除字符两侧空格】
lpad() 【左填充】
rpad() 【右填充】
concat() 【拼接字符串】
select length('abcdefghigklmn');
select length('中文');
select upper("ashGHJfhGHb");
select lower("GHJGJVgfgVHG");
-- substr (要截取的字符,起始索引,截取个数)
select substr("absdKJH",1,3);
select length(trim(" abc dss "));
select lpad("好好",10,"*");
select rpad("哈哈",10,"#");
select "abc"+"def";
select concat("abc","des","哈哈哈");
-- 案例1:查询员工的姓名,并且将姓开头第一个字符大写,其他字符小写,然后与名拼接,并且名开头第一个字符大写,其他字符小写
select concat(upper(substr(first_name,1,1)),lower(substr(first_name,2)),
'-',
upper(substr(last_name,1,1)),lower(substr(last_name,2))) 姓名
from employees;
数学函数
ceil(); 向上取整
floor(); 向下取整
rand(); 随机数
abs(); 取绝对值
mod(); 取余
round(); 四舍五⼊
truncate(); 截断
-- 案例1:23条数据 一次查五次 查几次可以查完
select ceil(23/5);
select floor(23/5);
-- 案例2:随机1-4之间的整数
select floor(rand()*4+1);
select abs(-10);
SELECT mod(-11,-3);
SELECT round(4.4);
SELECT round(4.5);
-- 参数一:截断谁 参数二:保留几位
SELECT truncate(10/3,4);
日期函数
now(); 获取当前的日期+时间
curdate(); 获取当前日期
curtime(); 获取当前的时间
date_format (要格式化的日期,格式化规则); 格式化日期和时间【%Y 年】 【%m 月】 【%d 天】
【%H 时】 【%i 分】 【%s 秒】
SELECT now();
SELECT curtime();
use myemployees;
SELECT * from employees;
-- 查询员工入职时间,显示为 xxxx年xx月xx日 xx时xx分xx秒
SELECT hiredate ,date_format(hiredate,'%Y年%m月%d日 %H时%i分%s秒') as 入职时间
from employees;
流程控制函数
① if();
② case
when 条件 then 取值
when 条件 then 取值
…
else 取值
end
-- 查询员工的名,薪资,昵称,如果薪资大于五千为白领,否则为蓝领
SELECT last_name,salary,if(salary>5000,'白领','蓝领') as 昵称
from employees;
-- 查询员工的名,老薪资,部门号、新薪资
-- (如果部门编号大于100 薪资涨到五倍。如果部门编号大于五十,薪资涨三倍,如果本门编号大于三十,薪资涨两倍,否则薪资减半)
SELECT last_name,salary,department_id,
case
when department_id>=100 then salary*5
when department_id>=50 then salary*3
when department_id>=30 then salary*2
else salary/2
end as 新薪资
from employees;
分组函数
字符相关函数、数值函数、日期函数、流程控制函数都属于单行函数
1、单行函数:传递一个数据,返回一个结果
2、多行函数(聚合函数/分组函数):传递一组数据,返回一个结果
sum() 求和
avg() 求平均值
max() 求最大值
min() 求最小值
count() 求个数
特点:
1、sum中只能传递数值类型
2、max、min、count可以传递审核类型的数据
3、sum、avg、max、min、count自动忽略null值
-- 案例1:求所有员工的薪资总和,平均薪资、最大薪资,最小薪资,员工个数
SELECT sum(salary) as 薪资总和,avg(salary) as 平均薪资, max(salary) as 最大薪资, min(salary) as 最小薪资, count(*) as 员工个数
from employees;
-- 特点1、传值类型
SELECT sum(last_name) as 薪资总和,avg(last_name) as 平均薪资, max(last_name) as 最大薪资, min(last_name) as 最小薪资, count(last_name) as 员工个数
from employees;
/*
特点2、是否忽略null
查询所有员工的奖金率总和
*/
SELECT sum(commission_pct),avg(commission_pct),sum(commission_pct)/107,sum(commission_pct)/35
from employees;
SELECT *
FROM employees
where commission_pct is not null;
5、分组查询
【其别名:as可以省略】
格式【顺序不能乱】:
select 查询列表 ---------4
from 表名 ---------1
where 分组前的条件 ---------2
group by 分组字段 ---------3
having 分组之后筛选 ---------5
order by 排序字段 asc | desc -----6
特点:
1、where 、group by 、having、order by、顺序严格
2、如果分组查询的话,查询列表中的内容只能是分组字段、分组函数(sum、avg、max、min、count)
-- 案例1:查询每个部门的平均薪资
SELECT department_id as 部门id, avg(salary) as 平均薪资
FROM employees
group by department_id;
-- 添加where条件
-- 案例2:查询没有奖金的员工对应的每个部门的平均薪资
SELECT department_id as 部门id, avg(salary) as 平均薪资
FROM employees
where commission_pct is null
group by department_id;
-- having
-- 案例3:查询没有奖金的员工对应的每个部门的平均薪资,并且找出平均薪资大于6000的部门号
SELECT department_id as 部门id, avg(salary) as 平均薪资
FROM employees
where commission_pct is null
group by department_id
having 平均薪资 > 6000;
-- 案例4:查询【没有奖金】的员工【对应的每个部门】(分组)的平均薪资,并且找出【平均薪资大于6000】的部门号,并且按照【平均薪资降序】
SELECT department_id as 部门id, avg(salary) 平均薪资
FROM employees
where commission_pct is null
group by department_id
having 平均薪资 > 6000
order by 平均薪资 desc;
-- 多字段分组 先按照第一个字段分组,然后再分别在每一组中 按照第二个字段分组
SELECT department_id as 部门id,job_id, avg(salary) 平均薪资
FROM employees
where commission_pct is null
group by department_id,job_id
having 平均薪资 > 6000
order by 平均薪资 desc;
6、分页查询
格式:
selct 查询列表
from 表名
where 分组前条件
group by 分组字段
having 分组后筛选
order by 排序 asc | desc
limit 偏移量,查询个数
特点:
1、偏移量:前面跳过几条数据,如果偏移量为0,可以省略不写
2、偏移量和页码的关系 (页码-1)诚意一页显示的数据
-- 查询前十条数据员工信息【第一页】
SELECT *
FROM employees
LIMIT 10;
-- 查询11-20数据【第二页】
SELECT *
FROM employees
LIMIT 10,10;
-- 查询21-30条数据【第三页】
SELECT *
FROM employees
LIMIT 20,10;
-- 查询 第n页数据
SELECT *
FROM employees
LIMIT (n-1)*size,size;
7、多表查询
概念:查询的数据来源于多个表,此时需要多表查询
内连接、自连接、外连接(左、右、全)、交叉连接 。
内连接(inner join/join):只有两个元素表相匹配的才能在结果集中显示。
外连接outer join:可进一步分为左外连接left outer join和右外连接right outer join,(简称左连接left join,右连接 right join)。
左外连接:左边为驱动表,驱动表的数据全部显示,匹配表的不匹配的不会显示。
右外连接:右边为驱动表,驱动表的数据全部显示,匹配表的不匹配的不会显示。
全外连接(full join/full outer join):连接的表中不匹配的数据全部会显示出来。
交叉连接(cross join): 笛卡尔效应,即不加任何条件,达到 M*N 的结果集。
- 【⼀对⼀ 】如:丈夫与妻⼦ ⽤户和身份证
特点: ⼀个表中的数据 只能对应⼀次 另⼀个表的⼀条数据
建⽴:⼀个表的主键字段与另⼀个表的主键字段建⽴外键关系
- 【⼀对多 和 多对⼀ 】:员⼯与部⻔ 、学⽣与班级
特点:⼀个表的列对应的数据 可以 对应另⼀个的字段的多个数据
建⽴:⼀个表的普通字段 与另⼀个表的主键字段建⽴外键关系
- 【多对多】:如:学⽣和所选科⽬
特点:⼀个表的字段多个值 对应 另⼀个表的字段的多个数据
建⽴:通过建⽴中间表 中间表中建⽴两个字段分别与两个表建⽴外键关系
【多对多的理解:】
-- 一对一
create table if not exists wife(
wid int PRIMARY key auto_increment comment '妻子编号',
wname varchar(32) comment '妻子名'
) comment '妻子表';
insert into wife(wname) values('翠花'),('小翠');
create table if not exists husband(
hid int primary key comment '丈夫编号',
hname varchar(32) comment '丈夫名'
)comment '丈夫表';
alter table husband add constraint fk_w_h foreign key(hid) references wife(wid);
insert into husband(hid, hname) values(2,'zhang3'),(1,'li4');
-- 一对多 和 多对一
-- 多对多
create table if not exists stu(
sid int primary key auto_increment comment '学号',
sname varchar(32) comment '姓名'
)comment '学生表';
create table if not exists sub(
sub_id int primary key comment '科目编号',
sub_name varchar(32) comment '科目名称'
) comment '科目表';
create table if not exists middle(
id int primary key comment '中间表id',
s_id int comment '学生编号',
sub_id int comment '科目编号'
)comment '中间表';
alter table middle add CONSTRAINT fk_m_s foreign key(s_id) references stu(sid);
alter table middle add CONSTRAINT fk_m_sub foreign key(sub_id) references sub(sub_id);
7.1、隐式查询
sql92语法:隐式内连接查询
格式:
select 查询列表
from 表1 别名1,表二 别名2
where 连接条件 and …
and 分组前条件
group by 分组后字段
having 分组后筛选
order by 排序
limit 偏移量,查询个数
特点:
1、连接查询时 一定要加连接条件 否则会造成笛卡尔成绩现象
2、表的顺序没有要求
3、连接条件的形式:
等值内连接:连接条件使用 = 号
非等值内连接:连接条件使用不是 = 号
自连接:自己连接自己
4、n张表 连接条件至少 n-1个
-- 案例1:查询员工的名 和 其他对应部门的名字
SELECT e.last_name,d.department_name
from employees e, departments d
WHERE e.department_id = d.department_id;
-- 添加分组前的筛选条件
-- 案例2:查询没有奖金的员工的名 和 对应部门的名字
SELECT e.last_name,d.department_name,e.commission_pct
from employees e,departments d
WHERE e.department_id = d.department_id
and e.commission_pct is null;
-- 添加分组
-- 案例3:查询每个员工部门的员工个数 和 部门名
SELECT COUNT(*),d.department_name
from employees e, departments d
WHERE e.department_id = d.department_id
GROUP BY d.department_name;
-- 案例4:查询每个员工部门的员工个数 和 部门名,并且筛选出员工数大于3的部门
SELECT COUNT(*),d.department_name
from employees e, departments d
WHERE e.department_id = d.department_id
GROUP BY d.department_name
HAVING COUNT(*) > 3;
-- 案例5:查询每个员工部门的员工个数 和 部门名,并且筛选出员工数大于3的部门,按照员工个数降序
SELECT COUNT(*),d.department_name
from employees e, departments d
WHERE e.department_id = d.department_id
GROUP BY d.department_name
HAVING COUNT(*) > 3
ORDER BY COUNT(*) DESC;
-- 非等值连接
USE myemployees;
DROP TABLE if EXISTS sal_grade;
CREATE TABLE sal_grade (
id INT PRIMARY KEY AUTO_INCREMENT,
min_salary DOUBLE,
max_salary DOUBLE,
grade char
);
INSERT INTO sal_grade VALUES(NULL,2000,3999,'A');
INSERT INTO sal_grade VALUES(NULL,4000,5999,'B');
INSERT INTO sal_grade VALUES(NULL,6000,9999,'C');
INSERT INTO sal_grade VALUES(NULL,10000,12999,'D');
INSERT INTO sal_grade VALUES(NULL,13000,14999,'E');
INSERT INTO sal_grade VALUES(NULL,15000,99999,'F');
-- 案例6:查询每个员工的薪资和其对应的薪资等级
SELECT e.salary,s.grade
FROM employees e,sal_grade s
WHERE e.salary BETWEEN s.min_salary AND s.max_salary;
-- 自连接
-- 案例7:查询员工的编号和名字以及对应 领导的编号 和 名字
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;
-- 多表
-- 案例8:查询员工的名 对应部门的名 以及对应工种的名
SELECT e.employee_id,d.department_name,j.job_title
from employees e,departments d ,jobs j
WHERE e.department_id=d.department_id
and e.job_id = j.job_id;
7.2、inner join
sql99语法:
显示内连接:
select 查询列表
from 表1 别名
inner join 表2 别名2
on 连接条件
inner join 表3 别名3
on 连接条件
…
where 分组前的条件
group by 分组字段
having 分组后筛选
order by 排序列表 asc | desc
limit 偏移量,个数
特点:
1、结果和 sql92 隐式内连查询 一样
2、将连接条件和 where添加 分离,提高了可读性
3、表顺序可以调换 不影响结果
4、连接条件的形式
① 等值内连接
② 非等值内连接
③ 自连接
5、n各表连接 至少n-1 个连接条件
-- inner join
-- 案例1: 查询员工的名字 和对应部门的名字
SELECT e.first_name,d.department_name
from employees e
INNER JOIN departments d
on e.department_id = d.department_id;
-- 案例2: 查询有奖金的员工的名字 和对应部门的名字
SELECT e.first_name,d.department_name,commission_pct
from employees e
INNER JOIN departments d
on e.department_id = d.department_id
WHERE e.commission_pct is not null;
-- 添加分组
-- 案例3 :查询每个部门的平均薪资,对应的部门
SELECT AVG(e.salary),d.department_name
FROM employees e
INNER JOIN departments d
on e.department_id = d.department_id
GROUP BY d.department_name
-- 添加分组之后筛选
-- 案例4:查询每个部门的平均薪资,对应的部门,筛选中平均工资大于5000的部门
SELECT AVG(e.salary),d.department_name
FROM employees e
INNER JOIN departments d
on e.department_id = d.department_id
GROUP BY d.department_name
HAVING AVG(e.salary)>5000;
-- 增加排序
-- 案例5:查询每个部门的平均薪资,对应的部门,筛选中平均工资大于5000的部门,并按照平均薪资降序
SELECT AVG(e.salary),d.department_name
FROM employees e
INNER JOIN departments d
on e.department_id = d.department_id
GROUP BY d.department_name
HAVING AVG(e.salary)>5000
ORDER BY AVG(e.salary) DESC;
-- 非等值连接
-- 案例6:查询每个员工的薪资,名和其对应的薪资等级
SELECT e.last_name,e.salary,s.grade
from employees e
INNER JOIN sal_grade s
on e.salary BETWEEN s.min_salary AND s.max_salary;
-- 自连接
-- 案例7: 查询员工的名 和其对应的领导的编号和名
SELECT e.last_name,e.manager_id,m.employee_id,m.last_name
FROM employees e
INNER JOIN employees m
on e.manager_id = m.employee_id;
-- 案例8:查询员工的名 和其对应的领导名,和工种的名(连接两张表)
SELECT e.last_name,d.department_name,j.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;
7.3、left | right join
sql99外连接
格式:
selct 查询列表
from 表1 别名1
left | right outer join 表2 别名2
on 连接条件
left | right outer join 表3 别名3
on 连接条件
where 分组前条件
group by 分组字段
having 分组后筛选
order by 排序列表 asc | desc
limit 偏移量,个数
-- 查询没有员工的部门
SELECT e.*,d.*
from employees e
RIGHT JOIN departments d
on e.department_id = d.department_id
WHERE e.employee_id is null;
-- 查询没有部门的员工
SELECT e.*,d.*
FROM employees e
LEFT JOIN departments d
on e.department_id = d.department_id
WHERE d.department_id is null;
和其对应的领导名,和工种的名(连接两张表)
SELECT e.last_name,d.department_name,j.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;
##### 7.3、left | right join
> sql99外连接
> 格式:
> selct 查询列表
> from 表1 别名1
> left | right outer join 表2 别名2
> on 连接条件
> left | right outer join 表3 别名3
> on 连接条件
> where 分组前条件
> group by 分组字段
> having 分组后筛选
> order by 排序列表 asc | desc
> limit 偏移量,个数
```sql
-- 查询没有员工的部门
SELECT e.*,d.*
from employees e
RIGHT JOIN departments d
on e.department_id = d.department_id
WHERE e.employee_id is null;
-- 查询没有部门的员工
SELECT e.*,d.*
FROM employees e
LEFT JOIN departments d
on e.department_id = d.department_id
WHERE d.department_id is null;
8、子查询
1、理解
⼀个查询语句中嵌套了另⼀个完整的查询语句,被嵌套在⾥⾯的查询语句 称为⼦查询或内查询,外⾯的查询语句称为主查询或外查询。
2、作⽤:主要为主查询提供条件的,主查询需要⽤到另个查询语句的结果
3、分类
select 后⾯
from 后⾯
where 后⾯ *
4、特点:
① ⼦查询写在⼩括号中
② ⼦查询优先于主查询执⾏,主查询会⽤到⼦查询的结果
③ ⼀般⼦查询放在where之后 搭配操作符使⽤
单⾏⼦查询:⼦查询结果只有⼀个 搭配的操作符:> < = >= <= <>
多⾏⼦查询:⼦查询的结果有多个 搭配的操作符:in / all任意 / any 任⼀
-- 单行子查询
-- 案例1:查询薪资和hunold员工薪资相同的员工信息
SELECT *
FROM employees
WHERE salary = (
SELECT salary
from employees
where last_name = 'Hunold'
);
-- 多行子查询
-- 案例2:查询薪资和员工编号101或102的薪资相同的员工信息
SELECT *
FROM employees
WHERE salary in (
SELECT salary
from employees
WHERE employee_id=102 OR employee_id = 103
)
-- 【all关键字】
-- 案例3:查询工种为IT_PROG所有员工薪资都低的员工信息
-- 1、查询工种为IT_PROG的薪资
SELECT DISTINCT MIN(salary)
from employees
WHERE job_id = 'IT_PROG'
SELECT *
from employees
WHERE salary < (
SELECT DISTINCT MIN(salary)
from employees
WHERE job_id = 'IT_PROG'
)
-- 等价于
SELECT *
from employees
WHERE salary < ALL(
SELECT DISTINCT salary
from employees
WHERE job_id = 'IT_PROG'
)
-- 【any关键字】
-- 案例4:查询比 工种为IT_PROG的 【任一】员工薪资都低的员工信息(比最大薪资低)
SELECT *
from employees
WHERE salary < (
SELECT DISTINCT MAX(salary)
from employees
WHERE job_id = 'IT_PROG'
)
-- 等价于
SELECT *
from employees
WHERE salary < ANY(
SELECT DISTINCT salary
from employees
WHERE job_id = 'IT_PROG'
)