null判断必须用is null而非= null;group by后select列须为分组键或聚合函数;日期范围查询应避免between,改用>=与

WHERE 子句里用 IS NULL 别写成 = NULL
sql 里 NULL 不是值,是“缺失”的标记,所以不能用等号判断。写 WHERE col = NULL 永远不返回任何行,连空数据都捞不到。
-
WHERE col IS NULL才是正确写法;WHERE col IS NOT NULL对应非空过滤 - 在报表中漏掉这一步,常导致聚合结果偏高(比如统计用户数时把未填手机号的全丢了)
- 某些方言如 Presto/Trino 支持
col NULL(空安全等号),但标准 SQL 和 mysql 8.0 以前不认,别混用
GROUP BY 后 select 列必须是分组键或聚合函数
写报表时想查每个部门的平均薪资,又顺手加了个 name 字段,结果报错 Error 1055 (42000) —— 这不是 MySQL 的 bug,是 SQL 标准在强制你明确意图。
- MySQL 5.7+ 默认开启
sql_mode=ONLY_FULL_GROUP_BY,禁止 SELECT 非分组、非聚合字段 - 错误写法:
SELECT dept, name, AVG(salary) FROM emp GROUP BY dept→name不确定取哪一行 - 正确做法:要么去掉
name,要么用MAX(name)或ANY_VALUE(name)(后者需确认业务能接受任意值) - postgresql 更严格,连
ANY_VALUE都不支持,必须显式聚合或重写逻辑
日期范围查询别直接用 BETWEEN 套 dateTIME
想查“2024-01-01 当天所有订单”,写 WHERE created_at BETWEEN '2024-01-01' AND '2024-01-01',结果只拿到零点那一条 —— 因为字符串自动转成 '2024-01-01 00:00:00',末尾时间没覆盖全天。
- 安全写法:
WHERE created_at >= '2024-01-01' AND created_at - 用
DATE(created_at) = '2024-01-01'虽然可读性好,但会跳过created_at索引,大表扫描慢 - 如果字段是
DATE类型(不含时分秒),BETWEEN可用,但建议统一用开闭区间,避免跨库迁移出问题
报表导出前先用 LIMIT 验证逻辑,别直接跑全量
写完一个带多层 JOIN 和子查询的报表 SQL,本地测试只用 3 行数据,一上线就卡住、超时、拖垮数据库 —— 很可能某张表没加索引,或者关联条件漏了 ON 导致笛卡尔积。
- 执行前必加:
SELECT ... FROM ... LIMIT 10,看结果是否符合预期、字段是否对齐、NULL 处理是否合理 - JOIN 顺序影响性能:小表驱动大表,优先把过滤条件写在驱动表的 WHERE 里(比如先筛出最近 7 天订单,再关联用户表)
- 报表定时任务里,记得加超时控制(如 MySQL 的
max_execution_time)和失败重试逻辑,否则凌晨挂了没人知道
日期精度、NULL 语义、分组规则这些地方,看着是语法细节,实际决定报表数据对不对。跑一次全量容易,但修一条错数据背后的时间成本,往往比重写三次 SQL 还高。