函数
1、内置函数
数学
SELECT ABS(-1); -- 1
SELECT ABS(3); -- 3
SELECT CEIL(1.23); -- 2
SELECT CEIL(1.9); -- 2
SELECT FLOOR(1.23); -- 1
SELECT FLOOR(1.93); -- 1
SELECT MOD(1,3); -- 1
SELECT MOD(2,8); -- 2 2/8的余数
SELECT MOD(3,1) -- 0
SELECT PI(); -- 3.141593
SELECT RAND(); -- 其中一次的随机值为 0.34172691809174316
SELECT round(1.5); -- 2
SELECT round(1.25); -- 1
SELECT round(1.2355555, 3); -- 1.236
SELECT round(1, 3); -- 1 // 整数即使传了第二个参数也是保留整数, 不会补足小数
SELECT TRUNCATE(1.3234234,4); -- 1.3234
SELECT TRUNCATE(34,4); -- 34 // 不会补足小数
聚合
聚合函数,查表用
特点,就像一个汇总,所有的行都会汇聚到一行。这样得到的结果表就不能查其他列了。
AVG() 平均值
SELECT AVG(salary) FROM employee;
-- 别名定义
SELECT AVG(salary) AS '平均薪资' FROM employee;
COUNT() 计算非NULL个数
SELECT COUNT(id) FROM employee; -- 查出employee.id不为NULL的总数
SELECT COUNT(*) FROM employee; -- 【不推荐写法】* 的查法,就是先把employee表查出来,然后看这个表的每一行,只要每一行中至少一个单元格不为NULL,就算一个数。
MIN() 最小值获取
SELECT min(salary) FROM employee;
MAX() 最小值获取
SELECT MAX(salary) FROM employee;
SUM() 求和
SELECT SUM(salary) FROM employee;
多个聚合查询
SELECT COUNT(id) AS '员工个数',
AVG(salary) AS '平均薪资',
MAX(salary) AS '最高薪资',
MIN(salary) AS '最低薪资',
SUM(salary) AS '公司总支出'
FROM employee;
字符
CONCAT()
SELECT CONCAT(`name`, '_', id, '_', location) FROM employee; -- 涂萌紫_2_人民北路
CONCAT_WS()
SELECT CONCAT_WS('/',`name`, location, salary) FROM employee; -- 涂萌紫/人民北路/14684.16
TRIM()
SELECT TRIM(' bar ');
SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx'); -- 删除指定的首字符x,得到「barxxx」
SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx'); -- 删除指定的首尾字符 x, 得到「bar」
SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz'); -- 删除指定的尾字符 x, 得到「barx」
LTRIM()
SELECT LTRIM(' guo '); -- 得到‘guo ’
RTRIM()
SELECT RTRIM(' guo '); -- 得到‘ guo’
日期
CURDATE()、CURRENT_DATE()
SELECT CURRENT_DATE(); -- 2021-01-19 得到今天
CURTIME()、CURRENT_TIME()
SELECT CURTIME(); -- 22:08:12 得到当前时间点
TIMESTAMPDIFF()
SELECT TIMESTAMPDIFF(MICROSECOND, '2019-2-25', '2021-1-19'); -- 相差毫秒值 59961600000000
SELECT TIMESTAMPDIFF(SECOND, '2019-2-25', '2021-1-19'); -- 相差秒值 59961600
SELECT TIMESTAMPDIFF(MINUTE, '2019-2-25', '2021-1-19'); -- 相差分钟值 999360
SELECT TIMESTAMPDIFF(HOUR, '2019-2-25', '2021-1-19'); -- 相差小时值 16656
SELECT TIMESTAMPDIFF(DAY, '2019-2-25', '2021-1-19'); -- 相差天数 694
SELECT TIMESTAMPDIFF(WEEK, '2019-2-25', '2021-1-19'); -- 相差周 99
SELECT TIMESTAMPDIFF(MONTH, '2019-2-25', '2021-1-19'); -- 相差月 22
SELECT TIMESTAMPDIFF(QUARTER, '2019-2-25', '2021-1-19'); -- 相差季度 7
SELECT TIMESTAMPDIFF(YEAR, '2019-2-25', '2021-1-19'); -- 相差年 1
应用
年龄、司龄、入职天数等跟日期相关的查询
SELECT `name`,
TIMESTAMPDIFF(year, birthday, CURRENT_DATE) AS 'age',
TIMESTAMPDIFF(year, joinDate, CURRENT_DATE) AS '司龄',
TIMESTAMPDIFF(day, joinDate, CURRENT_DATE) AS '入职天数'
FROM employee;
2、自定义函数
不讲了,自己学
分组【扩展】
用于比较复杂的查询场景。
但是注意,分组后,只能查询分组的列和聚合列
GROUP BY
查询员工分布的居住地,以及每个居住地有多少名员工
-- 查询员工分布的居住地,以及每个居住地有多少名员工
SELECT location, -- 分组后,只能查询分组的列和聚合列
COUNT(id) AS '员工数量' -- 聚合列
FROM employee
GROUP BY location
ORDER BY location;
按照居住地、性别进行分组和查询
-- 可以按照多列分组、这种情况下,也就可以查分组的多列
SELECT location, ismale, -- 多列查询
COUNT(id) AS '员工数量'
FROM employee
GROUP BY location, ismale -- 多列分组
ORDER BY location;
HAVING
在GROUP BY分组的基础上进行筛选
-- 查询员工分布的居住地、性别,以及每个居住地不同性别有多少名员工
SELECT location, ismale,
COUNT(id) AS '员工数量'
FROM employee
GROUP BY location, ismale
HAVING ismale = 1 -- 分组后进行筛选,只展示男员工
ORDER BY location;
HAVING可以使用SELECT的别名
- 根据数据库而定,有的数据库不支持(因为having的顺序滞后于select)
- having 过滤未分组的字段是不支持的。
-- 查询员工分布的居住地、性别,以及每个居住地不同性别有多少名员工
SELECT location,ismale AS sex, -- 定义别名「sex」
COUNT(id) AS '员工数量'
FROM employee
GROUP BY location, ismale
HAVING sex = 1 -- 使用别名进行筛选
-- HAVING id > 10 -- 这样写报错,因为id没有被分组
ORDER BY location;
运行顺序:
注意:不同的数据库对于HAVING的处理不同,执行顺序不同。有的是放在SELECT之前,有的是之后。HAVING + WHERE
SELECT location,ismale AS sex,
COUNT(id) AS '员工数量'
FROM employee
WHERE location LIKE '%天府%'
GROUP BY location, ismale
HAVING sex = 1
ORDER BY location;
练习题
1. 查询渡一每个部门的员工数量
SELECT d.name AS '所属部门',
COUNT(e.id) AS '员工数量'
FROM employee AS e
INNER JOIN department AS d ON e.deptId = d.id
inner JOIN company AS c ON d.companyId = c.id
WHERE c.`name` LIKE '%渡一%'
GROUP BY d.name;
老师
SELECT d.`name`, COUNT(e.id) AS number
FROM company as c INNER JOIN department as d on c.id = d.companyId
INNER JOIN employee as e on d.id = e.deptId
WHERE c.`name` LIKE '%渡一%'
GROUP BY d.id, d.`name`
2. 查询每个公司的员工数量
-- 我这里根据原题做了进一步的扩展:根据性别进行了分组
SELECT c.name AS '企业',
CASE e.ismale
WHEN 1 THEN '男'
ELSE '女'
END '性别',
COUNT(e.id) AS '员工数量'
FROM employee AS e
INNER JOIN department AS d ON d.id = e.deptId
INNER JOIN company AS c ON c.id = d.companyId
GROUP BY c.name, e.ismale
老师
SELECT c.`name`, COUNT(e.id) AS number
FROM company as c INNER JOIN department as d on c.id = d.companyId
INNER JOIN employee as e on d.id = e.deptId
GROUP BY c.id, c.`name`
3. 查询所有公司五年内入职的居住在万家湾的女员工数量
按照下图的思路往下写,报错了,说什么不在子句中。。。1055 -表达式#1的SELECT列表不在GROUP BY子句中,包含非聚合列’company.e。id’在功能上不依赖于GROUP BY子句中的列;与sql_mode=only_full_group_by, Time: 0.00000不兼容
SELECT companyName AS '企业名称',
COUNT(result_table.id) AS '员工数量'
FROM (
-- SQL子句
select e.id,e.location, e.ismale,
-- d.name as 'departmentName',
c.name as 'companyName',
timestampdiff(year, e.joinDate, current_date) as '司龄'
from employee as e
inner join department as d on d.id = e.deptId
inner join company as c on c.id = d.companyId
where timestampdiff(year, e.joinDate, current_date) > 5
and e.location like '%万家湾%' and e.ismale = 0
order by e.id
) as result_table
group by result_table.companyName
老师
第一种方法:查出来的之后有数据的公司,没数据的公司不展示(where那里筛选掉了)
SELECT c.`name`, COUNT(e.id) AS 数量
FROM company as c INNER JOIN department as d on c.id = d.companyId
INNER JOIN employee as e on d.id = e.deptId
WHERE TIMESTAMPDIFF(YEAR, e.joinDate, CURDATE()) <= 6 -- 20年卡5,21年卡6
AND e.location LIKE '%万家湾%'
AND e.ismale = 0
GROUP BY c.id, c.`name`
期望没数据的公司,number列展示0。于是需要用子句
SELECT company.`name`,
-- 当显示null时换成0
CASE
WHEN result_table.number IS NULL THEN
0
ELSE
result_table.number
END AS 符合条件的员工数量
-- 将上边的结果表当成一张表,左连接到company表。
FROM company LEFT JOIN (
SELECT c.id, c.`name`, COUNT(e.id) AS number
FROM company as c INNER JOIN department as d on c.id = d.companyId
INNER JOIN employee as e on d.id = e.deptId
WHERE TIMESTAMPDIFF(YEAR, e.joinDate, CURDATE()) <= 6 -- 20年卡5,21年卡6
AND e.location LIKE '%万家湾%'
AND e.ismale = 0
GROUP BY c.id, c.`name`
) AS result_table ON result_table.id = company.id
4. 查询渡一所有员工分布在哪些居住地,每个居住地的数量
SELECT location AS '居住地',
COUNT(location) AS '居住人数',
-- companyName AS '企业名称'
FROM (
-- SQL子句
select e.id, e.location,
c.name as 'companyName'
from employee as e
inner join department as d on d.id = e.deptId
inner join company as c on c.id = d.companyId
where c.name like '%渡一%'
) as result_table
GROUP BY location,companyName
老师
SELECT e.location, COUNT(e.id) AS number
FROM company AS c INNER JOIN department AS d ON c.id = d.companyId
INNER JOIN employee AS e ON d.id = e.deptId
WHERE c.`name` LIKE '%渡一%'
GROUP BY e.location
5. 查询员工人数大于200的公司信息
SELECT c2.*
FROM (
-- -- SQL子句
select c.id
from employee as e
inner join department as d on d.id = e.deptId
inner join company as c on c.id = d.companyId
GROUP BY c.id
HAVING count(e.id) > 200
) AS result_table
INNER JOIN company AS c2 ON c2.id = result_table.id
老师
在第二题的基础上,加上having过滤即可
SELECT c.`name`, COUNT(e.id) AS number
FROM company as c INNER JOIN department as d on c.id = d.companyId
INNER JOIN employee as e on d.id = e.deptId
GROUP BY c.id, c.`name`
HAVING number > 200
但是这样查出来的表,只显示了公司的名称,不显示其他详细信息。
期望和第三题一样做一个子句查询,补充公司的数据
SELECT * FROM company
WHERE id in (
SELECT c.id
FROM company as c INNER JOIN department as d on c.id = d.companyId
INNER JOIN employee as e on d.id = e.deptId
GROUP BY c.id, c.`name`
HAVING COUNT(e.id) >= 200
)
6. 查询渡一公司里比他平均工资高的员工
SELECT e2.id,
e2.`name`,
salary,
result_table.name AS 'company',
avgSalary
FROM (
-- SQL子句
select c.id, c.`name`, AVG(e.salary) as avgSalary
from employee as e
inner join department as d on d.id = e.deptId
inner join company as c on c.id = d.companyId
where c.name like '%渡一%'
GROUP BY c.id, c.`name`
) AS result_table
INNER JOIN employee AS e2
WHERE e2.salary > avgSalary
ORDER BY e2.salary
老师
SELECT e.*
FROM company as c INNER JOIN department as d on c.id = d.companyId
INNER JOIN employee as e on d.id = e.deptId
WHERE c.`name` LIKE '%渡一%' AND
e.salary > (
-- 子句
SELECT avg(e.salary)
FROM company as c INNER JOIN department as d on c.id = d.companyId
INNER JOIN employee as e on d.id = e.deptId
WHERE c.`name` LIKE '%渡一%'
)
ORDER BY e.salary
7. 查询渡一所有名字为两个字和三个字的员工对应人数
-- 写不出来。。
老师:
SELECT CHAR_LENGTH(e.`name`) as 姓名长度, COUNT(e.`name`) as 员工数量
FROM company as c INNER JOIN department as d on c.id = d.companyId
INNER JOIN employee as e on d.id = e.deptId
WHERE c.`name` LIKE '%渡一%'
GROUP BY CHAR_LENGTH(e.`name`) -- 按照姓名长度分组
HAVING 姓名长度 in (2,3) -- 这里要么写聚合,要么写别名,已经娶不到e.`name`了
8. 查询每个公司每个月的总支出薪水,并按照从低到高排序
SELECT companyId, companyName, SUM(salary) as salary
FROM three_table_join -- 用了视图
GROUP BY companyId, companyName
ORDER BY salary
老师:
SELECT c.`id`, c.`name`, SUM(e.salary) AS sumSalary
FROM company as c INNER JOIN department as d on c.id = d.companyId
INNER JOIN employee as e on d.id = e.deptId
GROUP BY c.`name`, c.id
ORDER BY sumSalary -- ORDER BY 顺序最后,所以需要别名