SQL 语句速查

SQL 语句速查表收录查询与条件过滤、排序分页、聚合与分组、多表连接、子查询与公共表表达式、插入更新删除、建表与约束、索引与执行计划分析、窗口函数、事务与并发控制以及字符串日期空值等常用函数写法,适合开发、数据分析和运维排查时快速查阅,免费在线使用,无需安装。

SQL 常用语句速查,以 MySQL 为主、兼顾通用写法;输入关键字过滤(如 join / 索引 / group),点击左侧语句即可复制。

查询与条件过滤

SELECT id, name FROM t只取需要的列,避免 SELECT *
SELECT DISTINCT city FROM t去重取值
SELECT COUNT(*) FROM t统计行数(含 NULL 行)
WHERE age BETWEEN 18 AND 30闭区间,含两端
WHERE status IN (1, 2)多值匹配,比多个 OR 更利于索引
WHERE status NOT IN (1, 2)排除多值;列可为 NULL 时结果不可靠
WHERE name LIKE '张%'前缀匹配可用索引,'%张%' 会全表扫描
WHERE name NOT LIKE '%test%'排除包含某片段
WHERE email IS NULL判空只能用 IS NULL,不能写 = NULL
WHERE email IS NOT NULL判非空
WHERE deleted_at = '1970-01-01'DATE/DATETIME 用字符串比较会隐式转换
WHERE id = 1 AND status = 1多条件 AND,等值条件放前面
WHERE (a = 1 OR b = 2) AND c = 3OR 混合务必加括号,否则优先级出错
WHERE JSON_EXTRACT(ext, '$.city') = '杭州'MySQL 5.7+ 取 JSON 字段,简写 ext->>'$.city'

排序与分页

ORDER BY create_time DESC按时间倒序(新的在前)
ORDER BY score DESC, id ASC多列排序,次键保证结果稳定
ORDER BY RAND()随机取一行;大表禁用,代价极高
LIMIT 10只取 10 行
LIMIT 20, 10MySQL 偏移写法:跳过 20 取 10
LIMIT 10 OFFSET 20标准写法,PostgreSQL 通用
WHERE id > 100000 ORDER BY id LIMIT 10深分页用游标(上次最大 id)代替大 OFFSET
FETCH FIRST 5 ROWS ONLYSQL:2008 写法,Oracle/PG 支持

聚合与分组

SELECT COUNT(*), SUM(amount) FROM t聚合函数忽略 NULL,COUNT(*) 不忽略行
COUNT(DISTINCT user_id)去重计数
AVG(score), MAX(score), MIN(score)均值、最大、最小
GROUP BY city按城市分组,SELECT 只能有分组列或聚合
GROUP BY city, channel多列联合分组
HAVING COUNT(*) > 5对分组后的结果过滤,不能用 WHERE
WHERE status = 1 GROUP BY city HAVING SUM(amount) > 0先过滤行再分组,最后过滤组
GROUP BY DATE(create_time)MySQL 按天聚合
GROUP BY DATE_TRUNC('day', create_time)PostgreSQL 按天聚合
GROUP BY city WITH ROLLUPMySQL 追加小计与总计行
GROUP_CONCAT(name ORDER BY id SEPARATOR ',')MySQL 组内拼接字符串
STRING_AGG(name, ',' ORDER BY id)PostgreSQL 组内拼接

多表连接

FROM a INNER JOIN b ON a.id = b.aid只保留两边都匹配的行(JOIN 即内连接)
FROM a LEFT JOIN b ON a.id = b.aid左表全保留,右表无匹配补 NULL
FROM a RIGHT JOIN b ON a.id = b.aid右表全保留,通常改写为左连接
FROM a FULL OUTER JOIN b ON a.id = b.aid两边都保留;MySQL 需 UNION 模拟
FROM a CROSS JOIN b笛卡尔积,慎用
LEFT JOIN b ON a.id = b.aid WHERE b.aid IS NULL反连接:找出 a 中没有匹配 b 的行
WHERE a.status = 1 AND b.amount > 0把右表条件写进 WHERE 会把左连接变成内连接
LEFT JOIN b ON a.id = b.aid AND b.status = 1右表条件应写在 ON 里
FROM t a JOIN t b ON a.pid = b.id自连接,常用于层级表
SELECT ... FROM a UNION SELECT ... FROM b合并结果并去重
SELECT ... FROM a UNION ALL SELECT ... FROM b合并不去重,性能更好

子查询与 CTE

WHERE id IN (SELECT aid FROM b)子查询作为多值条件
WHERE EXISTS (SELECT 1 FROM b WHERE b.aid = a.id)相关子查询,命中即返回,通常优于 IN
WHERE NOT EXISTS (SELECT 1 FROM b WHERE b.aid = a.id)不存在匹配(差集)
SELECT * FROM (SELECT ... ) t派生表必须有别名
WHERE score > (SELECT AVG(score) FROM t)标量子查询,只允许返回一行一列
WITH s AS (SELECT ... ) SELECT * FROM sCTE(公用表表达式),可读且可复用
WITH RECURSIVE t (id, pid, lvl) AS (...)递归 CTE,处理树形/层级数据
CREATE TEMPORARY TABLE tmp AS SELECT ...临时表,会话结束自动清理

插入、更新与删除

INSERT INTO t (a, b) VALUES (1, 'x')指定列插入,列名务必写全
INSERT INTO t (a, b) VALUES (1,'x'), (2,'y')批量插入,比循环单条快得多
INSERT INTO t2 SELECT * FROM t1 WHERE ...从查询结果插入(复制数据)
INSERT IGNORE INTO t VALUES (...)MySQL:冲突行跳过不报错
ON DUPLICATE KEY UPDATE cnt = cnt + 1MySQL:主键/唯一冲突时改为更新
ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.namePostgreSQL 的 upsert 写法
REPLACE INTO t VALUES (...)MySQL:冲突先删后插,会改自增 id
UPDATE t SET status = 1 WHERE id = 10更新必须带 WHERE,否则全表
UPDATE t SET cnt = cnt + 1 WHERE id = 10自增,读取与写入在同一条语句内完成
UPDATE a JOIN b ON a.id = b.aid SET a.x = b.yMySQL 多表联动更新
DELETE FROM t WHERE id = 10按条件删除行
DELETE FROM t删全部行但保留表结构,可回滚
TRUNCATE TABLE t清空并重置信增,速度快但不可回滚
SELECT * FROM t FOR UPDATE事务内加行级写锁,防并发扣减出错
SELECT * FROM t LOCK IN SHARE MODE共享读锁(PG 用 FOR SHARE)

建表与约束

CREATE TABLE IF NOT EXISTS t (id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(64) NOT NULL DEFAULT '')建表基础语法
UNIQUE KEY uk_name (name)唯一索引,业务幂等常用
KEY idx_status_time (status, create_time)联合索引,列顺序决定能否命中
FOREIGN KEY (uid) REFERENCES u(id)外键约束,保证引用完整性
ON DELETE CASCADE ON UPDATE CASCADE父行删除/更新时联动子行
CHECK (amount >= 0)取值约束;MySQL 8.0.16+ 才真正生效
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4MySQL 建表尾:事务引擎 + 完整 Unicode
COMMENT '订单主表'列或表注释,便于协作
ALTER TABLE t ADD COLUMN note VARCHAR(255) NULL加列
ALTER TABLE t MODIFY COLUMN name VARCHAR(128) NOT NULLMySQL 改列类型
ALTER TABLE t CHANGE name user_name VARCHAR(64)MySQL 重命名列
ALTER TABLE t RENAME TO t2重命名表
ALTER TABLE t DROP INDEX idx_x, DROP COLUMN y删索引与列
CREATE INDEX CONCURRENTLY idx_x ON t (x)PostgreSQL 不锁表建索引
DROP TABLE IF EXISTS t删表;先备份或用改名代替
TRUNCATE TABLE t RESTART IDENTITYPostgreSQL 清空并重置序列
SHOW CREATE TABLE tMySQL 查看建表语句
DESC t查看列结构(PG 用 \d t)

索引与执行计划

EXPLAIN SELECT ...MySQL 查看执行计划与预估行数
EXPLAIN ANALYZE SELECT ...实际执行并输出真实耗时(PG / MySQL 8)
EXPLAIN FORMAT=JSON SELECT ...MySQL 更详细代价信息
SHOW INDEX FROM t查看表的索引与基数
type=ref / range / index / ALL访问类型,ALL 即全表扫描需优化
Using filesort / Using temporary额外排序或临时表,考虑加合适索引
WHERE a = 1 AND b > 2 ORDER BY c联合索引遵循最左前缀原则
WHERE YEAR(create_time) = 2026对索引列套函数会导致索引失效
WHERE id = '123'字符串与数字比较引发隐式转换,索引失效
ANALYZE TABLE tMySQL 重新统计索引信息
VACUUM ANALYZEPostgreSQL 回收空间并更新统计
SELECT * FROM information_schema.processlistMySQL 查看正在执行的语句
SHOW FULL PROCESSLIST找出长事务与慢查询

窗口函数

ROW_NUMBER() OVER (PARTITION BY uid ORDER BY id DESC)组内编号,不并列
RANK() OVER (...)并列跳号(1,1,3)
DENSE_RANK() OVER (...)并列不跳号(1,1,2)
SUM(amount) OVER (PARTITION BY uid ORDER BY day)累计求和(到当前行为止)
AVG(score) OVER (PARTITION BY cls)组内均值,行数不减少
LAG(amount, 1, 0) OVER (ORDER BY day)取上一行,用于环比
LEAD(amount, 1, 0) OVER (ORDER BY day)取下一行
FIRST_VALUE(name) OVER (PARTITION BY uid ORDER BY id)组内第一行取值
NTILE(4) OVER (ORDER BY score)分成 4 桶(分位数)
QUALIFY ROW_NUMBER() OVER (...) = 1PG/Snowflake 对窗口结果过滤,取每组最新一条

事务与并发

START TRANSACTION / COMMIT / ROLLBACK开启、提交、回滚事务
SET autocommit = 0会话级关闭自动提交
SAVEPOINT sp1 / ROLLBACK TO sp1部分回滚
SET TRANSACTION ISOLATION LEVEL READ COMMITTED设置隔离级别
REPEATABLE READ / SERIALIZABLEMySQL 默认可重复读;最严格为串行化
SELECT ... FOR UPDATE NOWAIT取不到锁立刻报错,避免长时间阻塞
SELECT ... FOR UPDATE SKIP LOCKED跳过已锁定行,适合任务队列消费
SET SESSION innodb_lock_wait_timeout = 5锁等待超时秒数
SELECT * FROM performance_schema.data_lock_waitsMySQL 8 查看锁等待链

常用函数

IFNULL(x, 0) / COALESCE(a, b, 0)空值替换;COALESCE 跨库通用
NULLIF(a, 0)相等时返回 NULL,常用于避免除零
CONCAT(a, '-', b)字符串拼接;PG 也可用 a || b
SUBSTRING(name, 1, 3) / LEFT(name, 3) / RIGHT(name, 3)截取字符串
LENGTH(name) / CHAR_LENGTH(name)字节长度与字符长度(中文不同)
UPPER(name) / LOWER(name) / TRIM(name)大小写与去空格
REPLACE(name, 'a', 'b')替换片段
LOCATE('key', name)子串位置,0 表示不存在
ROUND(x, 2) / CEIL(x) / FLOOR(x) / ABS(x)数值取整与绝对值
MOD(a, b) / a DIV b取余与整除
NOW() / CURDATE() / CURTIME()当前日期时间
DATE_ADD(NOW(), INTERVAL 7 DAY)日期加减(PG 用 NOW() + INTERVAL '7 days')
DATEDIFF(d1, d2)天数差;MySQL 参数顺序是结束在前
DATE_FORMAT(t, '%Y-%m-%d %H:%i')MySQL 日期转字符串
STR_TO_DATE('2026-01-01', '%Y-%m-%d')字符串转日期
EXTRACT(YEAR FROM t) / YEAR(t) / MONTH(t)取年、月等字段
UNIX_TIMESTAMP(t) / FROM_UNIXTIME(sec)与秒级时间戳互转
CAST(x AS DECIMAL(10, 2))显式类型转换,跨库通用
CASE WHEN s = 1 THEN '正常' ELSE '异常' END条件映射,可与聚合组合做行转列
SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) AS ok_cnt条件计数(行转列常用技巧)
MD5(x) / SHA2(x, 256)哈希;密码请用专门算法而非 MD5
UUID() / gen_random_uuid()MySQL / PostgreSQL 生成 UUID

库表信息与权限

SHOW DATABASES / \l列出所有库(MySQL / PG)
USE db_nameMySQL 切换当前库
SHOW TABLES LIKE 'order%'按名字模式找表
SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'db'跨库查表清单
SELECT COLUMN_NAME, DATA_TYPE FROM information_schema.COLUMNS WHERE TABLE_NAME = 't'查列定义
SELECT ROUTINE_NAME FROM information_schema.ROUTINES查存储过程与函数
CREATE USER 'app'@'%' IDENTIFIED BY '密码'新建账号
GRANT SELECT, INSERT ON db.* TO 'app'@'%'按库授权,遵循最小权限
REVOKE ALL ON db.* FROM 'app'@'%'回收权限
SHOW GRANTS FOR 'app'@'%'查看已授权限
mysqldump -u root -p db > backup.sqlMySQL 逻辑备份
pg_dump -Fc db > backup.dumpPostgreSQL 自定义格式备份
mysql -u root -p db < backup.sql导入备份
LOAD DATA INFILE 'x.csv' INTO TABLE t FIELDS TERMINATED BY ','MySQL 快速导入 CSV
COPY t FROM 'x.csv' CSV HEADERPostgreSQL 导入 CSV