1. 查询
1.1 基础查询
语法:
select 查询列表 from 表名;
特点:
- 查询列表可以是:表中的字段、常量值、表达式、函数。
- 查询的结果是一个虚拟表格。
举例:
- 查询表中的单个字段
SELECT last_name FROM employees;
- 查询表中的多个字段
`SELECT last_name,salary,email FROM employees; - 查询表中的所有字段
SELECT * FROM employees;
- 查询常量值
SELECT 100;
SELECT 'John';
- 查询表达式
SELECT 100%90;
- 查询函数
SELECT VERSION();
- 起别名
方式一:使用AS
SELECT 100%98 AS 结果;
SELECT last_name AS 姓,first_name AS 名 FROM employees;
方式二:使用空格
SELECT last_name 姓, first_name 名 FROM employees;
起别名好处:- 便于理解
- 如果要查询的字段有重名,适合用别名可以区分开来
- 去重(DISTINCT)
案例:查询员工表中的所有部门编号
SELECT DISTINCT department_id FROM employees;
- +号的作用
MySQL中的+为运算符,并没有连接符的功能。
SELECT 100+90;
两个操作数都为数值型,则做加法运算。
SELECT '123'+90;
,结果为213。其中一方为字符型,试图将字符型数值转化成数值型
如果转换成功,则继续做加法运算
SELECT 'John'+90;
,结果为90。 如果转化失败,则将字符型数值转化为0
SELECT null+90;
,结果为null。 如果其中一方为null,则结果肯定为null
所以,因为在MySQL中+没有拼接功能,如果要解决下面问题,要使用CONCAT(a, b,c)函数。
如:SELECT CONCAT(a,b,c) AS result;
案例:查询员工名和姓连接成一个字段,并显示为姓名
SELECT CONCAT(last_name,first_name) AS 姓名 FROM employees;
- IFNULL(表中字段,初始值)
SELECT IFNULL(commission_pct,0) AS 奖金率, commission_pct FROM employees;
1.2 条件查询
语法:SELECT 查询列表 FROM 表名 WHERE 筛选条件;
分类:
- 按条件表达式筛选,条件运算符:>, <, =, !=, <>, >=, <=
- 按逻辑表达式筛选,逻辑运算符:&&, ||, !, and, or, not。后三个是MySQL中建议使用的。
- 模糊查询 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:查询工资在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;
三、模糊查询
- like
案例1:查询员工名中包含字符a的员工信息
SELECT * FROM employees WHERE last_name LIKE '%a%';
,其中%为通配符。
案例2:查询员工名中第三个字符为c,第五个字符为h的员工信息。
SELECT * FROM employees WHERE last_name LIKE '__c_h%';
,其中_
为通配符。
案例3:查询员工名中第二个字符为_
的员工名
SELECT * FROM employees WHERE last_name LIKE '_\_%';
,其中\
为转义字符,另外,可以通过ESCAPE
关键字来自定义转义字符,如:
SELECT * FROM employees WHERE last_name LIKE '_$_%' ESCAPE '$';
like特点:
- 一般和通配符搭配使用。
通配符:
%
表示任意多个字符(包含0个字符)
_
表示任意单个字符。
-
between and (包含临界值)
案例1:查询员工编号在100到120之间的员工信息
SELECT employee_id FROM employees BETWEEN 100 AND 120;
-
in
含义:判断某字段的值是否属于in列表的某一项。
案例:查询员工的工种编号是IT_PROG,AD_VP,AD_PRES中的一个员工名和工种编号
SELECT last_name,job_id FROM employees WHERE job_id IN('IT_PROG', 'AD_VP', 'AD_PRES');
特点:- 使用in提高语句简洁度
- in列表的值类型必须一致或兼容
-
is null
案例:查询没有奖金的员工名和奖金率
SELECT * FROM employees WHERE commission_pct IS NULL;
案例:查询有奖金的员工名和奖金率
SELECT * FROM employees WHERE commission_pct IS NOT NULL;
-
安全等于
<=>
案例:查询没有奖金的员工名和奖金率
SELECT * FROM employees WHERE commission_pct <=>null;
案例:查询工资为12000的员工信息
SELECT * FROM employees WHERE salary<=>12000;
IS NULL
pk<=>
IS NULL
:仅仅可以判断NULL值,可读性较高,建议使用
<=>
:既可以判读NULL值,又可以判断普通的数值,可读性较低。
1.3 排序查询
语法:
SELECT 查询列表 FROM 表 [WHERE 筛选条件] ORDER BY 排序列表 [asc|desc];
案例1:查询员工信息,要求工资从高到低进行排序
SELECT * FROM employees ORDER BY salary DESC;
特点:
- ASC代表升序,DESC代表降序,默认是升序。
- ORDER BY子句中可以支持单个字段、多个字段、表达式、函数、别名。
- ORDER BY 子句一般是放在查询语句的最后面,limit子句除外
案例2:查询部门编号>=90的员工信息,按入职时间的先后进行排序
SELECT * FROM employees WHERE department_id>=90 ORDER BY hiredate ASC;
案例3:按年薪的高低显示是员工的信息和年薪【按表达式排序】
SELECT *, salary*12*(1+ IFNULL(commission_pct,0)) AS 年薪 FROM employees ORDER BY 年薪 DESC;
案例4:按姓名的长度显示员工的姓名和工资【按函数排序】
SELECT last_name, salary FROM employees ORDER BY length(last_name);
案例5:查询员工信息,要求先按工资升序,再按员工编号降序【按多个字段排序】
SELECT * FROM employees ORDER BY salary ASC, employee_id DESC;
1.4 常见函数
概念:类似于Java的方法,将一组逻辑语句封装再方法体中,对外暴露方法名的好处:1、隐藏了实现细节 2、提高代码的重用性
调用:select 函数名(参数列表)【from 表】
特点:
- 叫什么(函数名)
- 干什么(函数功能)
分类:
- 单行函数,如concat、length、ifnull等
- 分组函数,功能:做统计使用,又称为统计函数、聚合函数、组函数
1.4.1 单行函数
一、字符函数
-
length
:返回参数的字节个数
SELECT LENGTH('JOHN');
-
conccat
:拼接字符串
SELECT CONCAT(last_name,'_',first_name) AS 姓名 FROM employees;
-
upper
、lowwer
SELECT UPPER('John');
SELECT LOWWER('John');
-
substr
、substring
注意:SQL语言中索引从1开始
截取从指定索引处后面所有字符:SELECT SUBSTR('李莫愁’爱上了陆展元',7);
截取从指定索引处指定字符长度的字符:SELECT SUBSTR('李莫愁爱上了陆展元',1,3);
案例:姓名中首字符大写,其他字符小写然后用_
拼接,显示出来
SELECT CONCAT(UPPER(SUBSTR(last_name,1,1)),LOWWER(SUBSTR(last_name,2)),'_',LOWWER(first_name)) FROM employees;
-
instr
:返回子串第一次出现的索引,如果找不到返回0。
SELECT INSTR('杨不悔爱上了殷六侠','殷六侠');
-
trim
去除前后的空格
SELECT TRIM(' 张翠山 ’) AS out_put;
SELECT TRIM('a' FROM 'aaaaaaa张aaaa翠aaaa山aaaaa') AS out_put;
,结果张aaaa翠aaaa山
。 -
lpad
用指定的字符实现左填充以达到指定长度。
SELECT LPAD('殷素素',10,'*') AS out_put;
,结果*******殷素素
; -
rpad
用指定的字符实现右填充以达到指定长度。 -
replace
替换
SELECT REPLACE('周芷若周芷若张无忌爱上了周芷若','周芷若','赵敏') AS out_put;
二、数学函数
round
:四舍五入
SELECT ROUND(-1.65)
.
SELECT ROUND(-1.65,2)
,小数点后保留两位ceil
:向上取整floor
:向下取整truncate
截断
SELECT TRUNCATE(1.6999,1);
,小数点后保留一位(不四舍五入)mod
:取余
SELECT MOD(10, -3);
,结果为1.
记住公式mod(a,b)=a-a/b*b
三、日期函数
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
:将日期格式的字符转化成指定格式的日期
SELECT STR_TO_DATE('1998-3-2','%Y-%c-%d');
举例:查询入职日期为1992-4-3的员工信息
SELECT * FROM employees WHERE hiredate=STR_TO_DATE('1992-4-3','%Y-%c-%d');
date_format
:将日期转换成字符
SELECT DATE_FORMAT(NOW(),'%Y年%m月%d日');
举例:查询有奖金的员工名和入职日期(xx月/xx日 xx年)
SELECT last_name,DATE_FORMAT(hiredate,'%c月/%d日 %Y年') FROM employees WHERE commission_pct IS NOT NULL;
四、其他函数
SELECT VERSION();
:查看DBMS版本号
SELECT DATABASE();
:查看当前使用的数据库
SELECT USER();
:查看当前用户
五、流程控制函数
- if函数:if else的效果
SELECT IF(10>5,'大','小');
SELECT last_name,commission_pct,IF(commission_pct IS NULL,'没奖金,呵呵','有奖金,哈哈') AS 备注 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 40THEN salary*1.2
WHEN 50THEN salary*1.3
ELSE salary
END AS 新工资 FROM employees;
(当THEN后面是一个值时,最后不要带分号)
3. 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 等级
FROM employees;
1.4.2 分组函数(统计函数)
功能:用作统计使用,又称为聚合函数或统计函数或组函数。
分类:
sum 求和、avg 平均值、max 最大值、min 最小值、count 计算个数
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;
2. 参数支持哪些类型
- sum、avg一般用于处理数值型,max、min、count可以处理任何类型
- sum、avg、max、min、count都忽略null
- 可以和distinct搭配实现去重运算,如:
SELECT COUNT(DISTINCT salary) FROM employees;
- count函数单独介绍。
1)SELECT COUNT(*) FROM employees;
统计表中数据的个数
2)SELECT COUNT(1) FROM employees;
统计表中数据的个数
效率:MYISAM中,COUNT(*)
的效率高,INNODB中,COUNT(*)
和COUNT(1)
效率差不多。 - 和分组函数一同查询的字段有限制,要求是group by后的字段。
1.5 分组查询
语法:
select 分组函数,列(要求出现在group by的后面)
from 表
[where 筛选条件]
group by 分组的列表
[order by 子句]
注意:查询列表必须特殊,要求是分组函数和group by后出现的字段
特点:
分组查询中的筛选条件分为两类:
数据源 | 位置 | 关键字 | |
---|---|---|---|
分组前筛选 | 原始表 | group by子句前 | where |
分组后筛选 | 分组后的结果表 | group by子句后 | having |
- 分组函数做条件肯定是放在HAVING子句中
- 能用分组前筛选的,就优先考虑使用分组前筛选
引入:查询每个部门的平均工资
SELECT department_id, AVG(salary) FROM employees GROUP BY department_id;
案例1:查询每个工种的最高工资
SELECT MAX(salary), job_id FROM employees GROUP BY job_id;
案例2:查询每个位置上的部门个数
SELECT COUNT(*) FROM departments GROUP BY location_id;
添加筛选条件
案例1:查询邮箱中包含a字符的,每个部门的平均工资
SELECT department_id,AVG(salary) FROM employees WHERE email like '%a%' GROUP BY department_id;
案例2:查询有奖金的每个领导手下员工的最高工资。
SELECT manager_id,MAX(salary) FROM employees WHERE commission_pct IS NOT NULL GROUP BY manager_id;
添加复杂的筛选条件
案例1:查询哪个部门的员工个数>2。(HAVING
关键字的使用)
可分为两步:
① 查询每个部门的员工个数
SELECT department_id, COUNT(*) FROM employees GROUP BY department_id;
② 根据①的结果进行筛选,查询哪个部门的员工个数>2。
SELECT department_id, COUNT(*) FROM employees GROUP BY department_id HAVING COUNT(*)>2;
案例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;
按表达式或函数分组
案例:按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的有哪些
SELECT LENGTH(last_name), COUNT(*) FROM employees GROUP BY LENGTH(last_name) HAVING COUNT(*)>5;
按多个字段分组
案例:查询每个部门每个工种的员工的平均工资
SELECT department_id, job_id, AVG(salary) FROM employees GROUP BY department_id, job_id;
添加排序
案例:查询每个部门每个工种员工的平均工资,并按平均工资的高低显示
SELECT department_id, job_id, AVG(salary) FROM employees GROUP BY department_id, job_id ORDER BY AVG(salary) DESC;
1.6 连接查询
含义:又称多表查询,当查询的字段来自于多个表时,就会用到连接查询。
笛卡尔乘积现象:表1有m行,表2有n行,结果=m*n行
发生原因:没有有效的连接条件
如何避免:添加有效的连接条件
分类:
按年代分类:
sql92标准:在MySQL中,仅仅支持内连接
sql99标准【推荐】:支持内连接、外连接(左连+右连)、交叉连接
按功能分类:
内连接:
等值连接
非等值连接
自连接
外连接:
左外连接
右外连接
全外连接
交叉连接
一、sql92标准
1. 等值连接
案例1:查询女神名和对应的男神名
SELECT name,boyName FROM beauty, boys WHERE beauty.boyfriend_id=boys.id;
案例2:查询员工名和对应的部门名
SELECT last_name, department_name FROM employees,departments WHERE employees.department_id=departments.department_id;
1. 为表起别名
好处:
- 提高语句的简洁度
- 区分多个重名的字段
注意:如果为表起了别名,则查询的字段就不能使用原来的表名去限定
#案例:查询员工名、工种号、工种名
SELECT last_name,j.job_id,job_title FROM employees e, jobs j WHERE e.job_id = j.job_id;
2. 两个表名的顺序可以调换
3. 加筛选
案例1:查询有奖金的员工名、部门名
SELECT last_name, department_name FROM employees e, departments d WHERE e.department_id = d.department_id AND 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%";
4. 加分组
案例1:查询每个城市的部门个数
SELECT city, COUNT(*) FROM departments d, locations l WHERE d.location_id = l.location_id GROUP BY city;
案例2:查询有奖金的每个部门的部门名和部门的领导编号以及该部门的最低工资
SELECT d.department_name, d.manager_id, MIN(e.salary) FROM departments d, employees e WHERE d.department_id=e.department_id AND e.commission_pct IS NOT NULL GROUP BY d.department_name, d.manager_id;
5. 加排序
案例:查询每个工种的工种名和员工的个数,并且按员工个数降序
SELECT job_title,COUNT(*) FROM jobs j, employees e WHERE j.job_id = e.job_id GROUP BY job_title ORDER BY COUNT(*) DESC;
6.可以实现三表连接吗
案例:查询员工名、部门名和所在的城市
SELECT e.last_name, d.department_name, l.city FROM employees e, departments d, locations l WHERE e.department_id = d.department_id AND d.location_id = l.location_id;
7. 等值连接特点
- 多表等值来凝结的结果为多表的交集部分
- n表连接,至少需要n-1个连接条件
- 多表的顺序没有要求
- 一般需要为表起别名
- 可以搭配前面介绍的所有查询子句使用,比如分组、排序
2. 非等值连接
案例:查询员工的工资和工资级别
SELECT salary, grade_level FROM employees e, job_grades g WHERE salary BETWEEN g.lowest_sal AND g.highest_sal;
3. 自连接
案例:查询员工名和上级领导的名字
SELECT e1.last_name, e2.last_name FROM employees e1, employees e2 WHERE e1.manager_id = e2.employee_id;
二、sql99标准
语法:
select 查询列表
from 表1 别名 【连接类型】
join 表2 别名
on 连接条件
【where 筛选条件】
【group by 分组】
【having 筛选条件】
【order by 排序类型】
分类:
内连接:(inner)
外连接
左外:left【outer】
右外:right 【outer】
全外:full 【outer】
交叉连接:cross
1. 内连接
分类:
等值连接,非等值连接,自连接
特点:
- 可以添加排序、分组、筛选
- inner可以省略
- 筛选条件放在where后面,连接条件放在on后面,调高分离性,便于阅读
- inner join连接和sql92语法中的等值连接效果是一样的,都是查询多表的交集。
等值连接
案例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 INNER JOIN jobs j ON e.job_id =j.job_id WHERE 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 d.department_name, count(*) n FROM departments d inner join employees e on d.department_id = e.department_id GROUP BY d.department_name HAVING n>3 ORDER BY n 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;
非等值连接
案例1:查询员工的工资级别
SELECT last_name, grade_level FROM employees e INNER JOIN job_grades g ON salary BETWEEN lowest_sal AND highest_sal;
案例2:查询每个工资级别的个数且个数大于20,并且按工资级别降序
SELECT grade_level, count(*) FROM employees e INNER JOIN job_grades g ON salary BETWEEN lowest_sal AND highest_sal GROUP BY grade_level HAVING count(*) > 20 ORDER BY grade_level DESC;
自连接
案例1:查询员工的名字、上级的名字
SELECT e1.last_name, e2.last_name FROM employees e1 INNER JOIN employees e2 ON e1.manager_id=e2.employee_id;
2. 外连接
应用场景:用于查询一个表中有,另一个表中没有的记录
特点:
- 外连接的查询结果为主表中的所有记录,如果从表中有和它匹配的,则显示匹配的值;如果从表中没有和它匹配的,则显示null;外连接的查询结果=内连接的结果+主表中有而从表中没有的记录。
- 左外连接,left join 左边的是主表;右外连接,right join右边的是主表
- 左外和右外交换两个表的顺序,可以实现同样的效果
- 全外连接=内连接的结果+表1中但表2中没有的+表2中有但表1中没有的,就是两个表分别做主表的结果的并集。MySQL不支持全外连接
引入:查询男朋友不在男生表的女神名
左外连接:
SELECT b.name FROM beauty b LEFT OUTER JOIN boys bo ON b.boyfriend_id=bo.id WHERE bo.id IS NULL;
右外连接:
SELECT b.name FROM boys bo RIGHT OUTER JOIN beauty b ON b.boyfriend_id=bo.id WHERE bo.id IS NULL;
案例1:查询哪个部门没有员工
SELECT d.department_name FROM departments d LEFT JOIN employees e ON d.department_id=e.department_id WHERE e.employee_id IS NULL;
3. 交叉连接
SELECT b.*, bo.* FROM beauty b CROSS JOIN boys bo;
全外连接就是两个表笛卡尔乘积的结果
总结
sql92和sql99 pk:
功能:sql99支持的较多
可读性:sql99实现连接条件和筛选条件的分离,可读性较高
1.7 子查询
含义:出现在其他语句中的select语句,称之为子查询或内查询。
外部的查询语句称为主查询和外查询。
分类:
按子查询出现的位置:
- select 后面:仅仅支持标量子查询
- from 后面:支持表子查询
- where或having 后面(★):标量子查询(✔),列查询(✔),行子查询
- exists后面:表子查询
按结果集的行列数不同:
- 标量子查询(结果集只有一行一列)
- 列子查询(结果集只有一列多行)
- 行子查询(结果集有一行多列)
- 表子查询(结果集一般为多行多列)
一、where 或having后面
特点:
- 子查询放在小括号内
- 子查询一般放在条件的右侧
- 标量子查询,一般搭配着单行操作符使用,如<, >, >=, <=, =, <>
- 列子查询,一般搭配着多行操作符使用in、any/some、all
- 子查询的执行由于主查询的执行,子查询的条件用到了子查询的结果
1. 标量子查询(单行单列)
案例1:谁的工资比Abel高?
①查询Abel的工资
SELECT salary FROM employee WHERE last_name = 'Abel';
②查询员工的信息,满足salary>①结果
SELECT * FROM employees WHERE salary>(SELECT salary FROM employee WHERE last_name = 'Abel');
案例2:返回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);
案例3:返回公司工资最少的员工的last_name,job_id和salary.
SELECT last_name, job_id, salary FROM employees WHERE salary=(SELECT MIN(salary) FROM employees);
案例4:查询最低工资大于50号部门的最低工资的部门id和其最低工资
SELECT department_id, MIN(salary) m
FROM employees
GROUP BY department_id
HAVING m > (SELECT MIN(salary)
FROM employees
WHERE department_id = 50
);
2. 列子查询(多行单列)
搭配的多行比较操作符:
操作符 | 含义 |
---|---|
IN/NOT IN | 等于列表中的任意一个 |
ANY/SOME | 和子查询返回的某一个值比较 |
ALL | 和子查询返回的所有值比较 |
案例1:返回location_id是1400或1700的部门中的所有员工姓名
SELECT last_name
FROM employees
WHERE department_id IN (
SELECT department_id
FROM locations
WHERE location_id IN (1400,1700)
);
案例2:返回其他工种中比job_id为’IT_PROG’的工种任意工资低的员工的员工号、姓名、job_id以及salary.
SELECT employee_id, job_id,salary
FROM employees
WHERE job_id <> 'IT_PROG' AND salary < (
SELECT MAX(salary)
FROM employees
WHERE job_id = 'IT_PROG'
);
案例3:返回其他工种中比job_id为’IT_PROG’的工种所有工资低的员工的员工号、姓名、job_id以及salary.
SELECT employee_id, job_id,salary
FROM employees
WHERE job_id <> 'IT_PROG' AND salary < (
SELECT MAX(salary)
FROM employees
WHERE job_id = 'IT_PROG'
);
3. 行子查询(单行多列)
案例:查询员工编号并且工资最高的员工信息
SELECT *
FROM employees
WHERE (employee_id, salary)=(
SELECT MIN(employee_id),MAX(salary)
FROM employees)
二、select 后面子查询(标量子查询)
案例1:查询每个部门的员工个数
SELECT d.*, (SELECT COUNT(*) FROM employees e WHERE e.department_id=d.department_id)
FROM departments d;
三、from后面的子查询(表子查询)
案例:查询每个部门的平均工资的工资等级
SELECT d.department_id, grade_level
FROM (
SELECT department_id, AVG(salary) s
FROM employees
GROUP BY department_id
) d
INNER JOIN job_grades g ON d.s BETWEEN g.lowest_sal AND g.highest_sal;
四、exists后面的子查询(相关子查询)
语法:
exists(完整的查询语句)
结果为1或0
例如:
SELECT EXISTS(SELECT employee_id FROM employees);
案例1:查询有员工的部门名
SELECT department_name
FROM departments d
WHERE EXISTS(
SELECT *
FROM employees e
WHERE d.department_id=e.department_id
);
可以用in代替
SELECT department_name
FROM departments d
WHERE d.department_id IN (
SELECT DISTINCT e.department_id
FROM employees e
);
1.8 分页查询
应用场景:当要显示的数据,一页显示不全,需要分页提交sql请求。
语法:
select 查询表达式
from 表
【join type join 表2
on 连接条件
where 筛选条件
group by 分组字段
having 分组后的筛选
order by 排序的字段】
limit offset,size;
offset:要显示的条目的起始索引(起始索引从0开始)
size 要显示的条目个数
特点:
- limit 语句要放在查询语句的最后
- 公式
- 要显示的页数 page,每页的条目数size.
limit (page-1)*size,size
案例1:查询前五条员工信息
SELECT * FROM employees LIMIT 0, 5;
或SELECT * FROM employees LIMIT 5;
(如果是0可省略)
案例2: 查询低11条到第25条
SELECT * FROM employee LIMIT 10, 15;
案例3:有奖金的员工信息,并且工资较高的前10名显示出来。
SELECT *
FROM employees
WHERE commission_pct IS NOT NULL
ORDER BY salary DESC
LIMIT 10;
1.9 联合查询
union 联合 :将多条查询语句的结果合并为一个结果
语法
查询语句1
UNION
查询语句2
UNION
…
应用场景:
要查询的结果来自于多个表,且多个表没有直接的连接关系,单查询的信息一致时
特点:
- 要求多条查询语句的查询列数是一致的
- 要求多条查询语句查询的每一列的类型和顺序一致
- UNION 关键字默认去重,如果无需去重,可以使用union all 保留重复项
引入案例:查询部门编号>90或邮箱包含a的员工信息
之前的条件查询:
SELECT * from employees WHERE department_id>90 OR email LIKE '%a%';
联合查询:
SELECT * FROM employees WHERE departement_id > 90
UNION
SELECT * FROM employees WHERE email LIKE '%a%';
案例:查询中国用户中的男性新学年以及外国用户中男性的信息
SELECT * FROM t_ca WHERE csex='男‘
UNION
SELECT * FROM t_ua WHERE tGender='male';
2. 插入语句 insert
方式一语法:
insert into 表名(列名,…)values(值1,…)
- 插入的值的类型要与列的类型一致或兼容
INSERT INTO beauty(id,name,sex,borndate,phone,photo,boyfriend_id) VALUES(13,'唐艺昕','女','1990-4-23','18988888888', NULL,2);
- 不可以为null的列必须插入值,可以为null的列要么写列名但插入值为null,要么列名插入值都省略。
- 列的顺序可以调换,但列名和值必须一一对应。
- 列数和值的个数必须一致。
- 可以省略列名,默认是所有列,而且列的顺序和表中列的顺序一致
方式二语法:
insert into 表名 set 列名=值,列名=值,...
如:INSERT INTO beauty SET id=19,NAME='刘涛',phone='999';
两种方式大pk
- 方式一支持插入多行,方式二不支持
INSERT INTO beauty
VALUES(23,'唐艺昕','女','1990-4-23','18988888888',NULL,2),
(24,'唐艺昕2','女','1990-4-23','18988888888',NULL,2),
(25,'唐艺昕3','女','1990-4-23','18988888888',NULL,2),
- 方式一支持子查询,方式二不支持
INSERT INTO beauty(id,name)
SELECT id, boyname FROM boys WHERE id<3;
3. 修改语句
- 修改单表的记录
语法:
update 表名
set 列=新值,列=新值,...
where 筛选条件;
案例1:修改该beauty表中姓唐的女神的电话为13899999999
UPDATE beauty SET phone='13899999999' WHERE name LIKE '唐%';
案例2:修改boys表中id号为2的名称为张飞,魅力值为10
UPDATE boys SET boyname='张飞',usercp=10 WHERE id=2;
- 修改多表的记录(级联更新)
sql92语法:
update 表1 别名,表2 别名
set 列=值,...
WHERE 连接条件 AND 筛选条件;
sql99语法:
update 表1 别名
inner | left | right | join 表2 别名
on 连接条件
set 列=值,…
where 筛选条件
案例1:修改张无忌的女朋友的手机号为114
sql92:UPDATE beauty b, boys bo set b.phone='114' WHERE b.boyfriend_id=bo.id AND bo.boyname='张无忌';
sql99:UPDATE beauty b join boys bo on b.boyfriend_id=bo.id SET b.phone='114' WHERE bo.boyname='张无忌';
案例2:修改没有男朋友的女神的男朋友编号都为2号
UPDATE beauty b left join boys b on b.boyfriend_id = bo.id SET b.boyfriend_id='2' WHERE bo.id IS NULL;
4. 删除语句
方式1:delete
语法:
- 单表的删除
delete from 表名 where 筛选条件
案例1:删除手机号以9结尾的女神信息
DELETE FROM beauty WHERE phone LIKE '%9';
- 多表的删除
sql92:delete 表1的别名,表2的别名 FROM 表1 别名,表2 别名 WHERE 连接条件 AND 筛选条件;
注意:delete后边接的是要删除表的别名,删除哪个表里的添哪个表,都删除就都添
sql99:delete 表1的别名,表2的别名 FROM 表1 别名 inner|left|right join 表2 别名 on 连接条件 where 筛选条件;
案例1:删除张无忌的女朋友的信息
DELETE b
FROM beauty b INNER JOIN boys bo ON b.boyfriend_id=bo.id
WHERE bo.boyname='张无忌';
案例2:删除黄晓明的信息以及他女朋友的信息
DELETE b,bo
FROM beauty b inner join boys bo ON b.boyfriend_id = bo.id
WHERE bo.boyname='黄晓明';
方式2:truncate(清空表中数据)
语法:
truncate table 表名;
delete pk truncate
- delete 可以加where条件,truncate 不能加
- truncate删除,效率高一丢丢
- 假如要删除的表中有自增长列,如果用delete 删除后,再插入数据,自增长列的值从断点开始,而truncate删除后,再插入数据,自增长列的值从1开始。
- truncate删除没有返回值,delete删除有返回值
- truncate删除不能回滚,而delete删除可以回滚。