SQL调优
SQL浅复习
增(Create)
注意INTO和VALUES关键字
1 | -- 指定字段插入多条数据 |
删(Delete)
注意FROM关键字
1 | DELETE FROM `user` WHERE username = '赵六'; |
改(Update)
注意SET关键字
1 | UPDATE `user` SET age = 31, email = 'lisi_new@example.com' WHERE id = 2; |
查(Read)
查的方法方式很多,下面列举常见的:
排序可以多字段,并且每个字段的升降序可以不同,如下:
1
2
3
4
5
6
7SELECT * FROM products
ORDER BY prod_price DESC, prod_name ASC;
-- 汇总字段也可以进行排序
SELECT cust_name, COUNT(cust_address) AS addr_num
FROM Customers GROUP BY cust_name
ORDER BY addr_num DESC;having在group by之后,where在group by之前;having只能针对group by或汇总(聚合)字段进行过滤
1
2
3
4
5SELECT cust_name, COUNT(*) AS NumberOfOrders
FROM Customers
WHERE cust_email IS NOT NULL
GROUP BY cust_name
HAVING COUNT(*) > 1; -- 汇总字段,也可以用别名NumberOfOrders判断是否null用
is null,where的等号是单个的=,字符串是单引号''包裹的LIKE操作符在WHERE子句中使用,作用是确定字符串是否匹配模式,支持两个通配符匹配选项:
%表示任何字符出现任意次数,_表示任何字符出现一次;不要滥用通配符,通配符位于开头处匹配会非常慢。IN操作符在WHERE子句中使用,作用是在指定的几个特定值中任选一个值;BETWEEN操作符在WHERE子句中使用,作用是选取介于某个范围内的值。
1
2
3
4
5
6
7SELECT *
FROM products
WHERE vend_id IN ('DLL01', 'BRS01');
SELECT *
FROM products
WHERE prod_price BETWEEN 3 AND 5;
子查询
子查询可以嵌入 SELECT、INSERT、UPDATE 和 DELETE 语句中,也可以和 =、<、>、IN、BETWEEN、EXISTS 等运算符一起使用。
1 | -- 放在where后边 |
连接(JOIN)和组合(UNION)
JOIN是将两个表水平放置,UNION是垂直放置;
JOIN
JOIN主要分为INNER, LEAF, RIGHT, FULL;默认是INNER JOININNER JOIN可以用WHERE替代UNION
所有查询的列数和列顺序必须相同,每个查询中涉及表的列的数据类型必须相同或兼容
常见函数,以MySQL为例
文本处理
- LENGTH():以字节为单位的长度;CHAR_LENGTH():以字符为单位的长度,中文特殊符号都算1个
- LOWER()、UPPER():小写或大写
- CONCAT(str1, str2, …):字符串拼接,如果存在NULL则返回NULL
- SUBSTRING(‘MySQL函数’, 1, 5):子串,输入MySQL,索引开始是1,而非0
- TRIM():去掉首尾的空格
数值函数
- ABS()
- ROUND(n, decimals):四舍五入到decimals位,省略则取整数
- MOD(n, m):n % m
- RAND([seed]):0~1之间的随机浮点数
- POWER(base, exponent)或POW()
- SQRT():平方根
日期和时间
可以参考JavaGuide的这一块儿
NOW():返回当前时间,格式
YYYY-MM-DD HH:MM:SS;CURDATE()/CURTIME():仅返回当前日期或时间DATE_FORMAT(date, format):date是
now()或原始日期字符串,支持多种分隔符;format是格式化字符串,特殊符号如下:
%Y:4位数字年份;%y:2位数字年份;
%m:2位月份,01-12;%M:月份英文全称,January;
%d:月份中的天数,01-31;%e:月份中的天数,1-31;
%H:小时,00-23;%i:分钟,00-59;%s:秒,00-59;
%W:星期英文全称,如Sunday;1
SELECT DATE_FORMAT(NOW(), '%Y年%m月%d日 %H时%i分%s秒') AS cn_time;
Year()、Month()、Day()、Hour()、Minute()、Second():返回一个时间的对应部分
DATE_ADD(date, INTERVAL expr unit):给日期增加指定时间间隔
1
2SELECT DATE_ADD(NOW(), INTERVAL 7 DAY); → 7 天后的时间
-- unit: DAY/MONTH/YEAR/HOUR/MINUTE/SECONDDATEDIFF(date1, date2):返回天数差,半开半闭区间,注意是
前-后1
SELECT DATEDIFF('2026-02-01', '2026-01-26'); -- 结果为6
TIMESTAMPDIFF(unit, start_date, end_date):闭区间,注意是
后-前1
2SELECT TIMESTAMPDIFF(MONTH, '2026-01-10', '2026-03-15'); -- 结果为2
-- unit: DAY/MONTH/YEAR/HOUR/MINUTE/SECOND
聚合
使用DISTINCT可以让聚合函数针对不同的值进行聚合
- AVG():返回某列的平均值,会忽略NULL
- SUM():计算某列之和
开窗函数/窗口函数
基于当前行,在一个 “窗口”(指定范围的结果集)内对数据进行计算,不会像 GROUP BY 那样合并行,而是保留每行的独立结果
LAG()和LEAD():取前面或后面的offset列,如果不设置default参数,会返回NULL1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27LAG(col, offset, default) OVER (
[PARTITION BY 分组列] -- 可选,按指定的列进行分组(例如相同班级),在组内独立计算前一个或后一个
ORDER BY 排序列 [ASC/DESC] -- 必选,定义行的顺序,否则偏移无意义,不能和分组列相同
)
LEAD(col, offset, default) OVER (
[PARTITION BY 分组列]
ORDER BY 排序列 [ASC/DESC]
)
-- 计算当前员工与上一个同部门的员工的薪资差值
SELECT
dept,
name,
salary,
prev_salary,
salary - prev_salary AS salary_diff_pre
next_salary - salary AS salary_diff_nxt
FROM (
SELECT
dept,
name,
salary,
LAG(salary, 1, salary) OVER (PARTITION BY dept ORDER BY id) AS prev_salary
LEAD(salary, 1, salary) OVER (PARTITION BY dept ORDER BY id) AS next_salary
FROM employee
) AS t;聚合函数
包括:SUM/AVG/COUNT/MAX/MIN;ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW一般用于SUM函数,表示从分区的第一行到当前行的累计和
1 | 聚合函数(col) OVER ( |
排序函数
1 | 排序函数() OVER ( |
排序主要是针对并列值的不同处理逻辑,分为如下的排序函数,主要就前两个:
- ROW_NUMBER():连续排名,并列值也会分配不同排名
- RANK():跳跃排名,并列后跳过后续排名,例如 1,2,2,4
- DENSE_RANK():密集排名,并列后不跳过,例如 1,2,2,3
1 | SELECT |
SQL刷题记录
需要刷一些leetcode的SQL题目巩固SQL能力,题单在此
1. 1581. 进店却未进行过交易的顾客
保留进店的记录,和交易表进行left join,最后统计交易id为null的进店记录的数量。
1 | select v.customer_id, count(*) as count_no_trans |
2. 197. 上升的温度
自己和自己连接
1
2
3
4
5select t1.id from
Weather t1 inner join Weather t2
on DateDiff(t1.recordDate, t2.recordDate) = 1
-- where TIMESTAMPDIFF(DAY, w2.RecordDate, w1.RecordDate) = 1 -- 注意TIMESTAMPDIFF是`后-前`
where t1.Temperature > t2.Temperature;使用LAG()获取按日期排序后上一条数据的日期和温度,如果日期和温度都满足,则作为结果数据
1 | select t.id |



