SQL 格式化最佳实践:写出可读的查询语句

CodeKit
sql格式化数据库

SQL 格式化最佳实践:写出可读的查询语句

SQL 是与数据库交互的标准语言,但”能运行”和”可读”之间往往存在巨大鸿沟。一条写在一行上的复杂查询,和一条经过精心格式化的查询,功能完全相同,但在代码审查、调试和维护时的体验天差地别。本文将探讨 SQL 格式化的重要性、常见的风格指南、不同 SQL 方言的差异,以及如何利用自动格式化工具提升效率。

一、为什么格式化重要

1.1 可读性即生产力

考虑以下两条功能相同的 SQL:

未格式化:

SELECT u.id,u.name,o.total FROM users u JOIN orders o ON u.id=o.user_id WHERE u.status='active' AND o.created_at>='2025-01-01' ORDER BY o.total DESC LIMIT 10;

格式化后:

SELECT
    u.id,
    u.name,
    o.total
FROM users u
JOIN orders o
    ON u.id = o.user_id
WHERE u.status = 'active'
    AND o.created_at >= '2025-01-01'
ORDER BY o.total DESC
LIMIT 10;

格式化后的版本一目了然:查询哪些列、从哪些表、连接条件是什么、过滤条件有哪些。在代码审查时,审查者可以快速定位问题;在调试时,你可以迅速找到需要修改的子句。

1.2 减少错误

格式化的 SQL 更容易发现常见错误:

-- 未格式化:容易遗漏 JOIN 条件,导致笛卡尔积
SELECT * FROM users JOIN orders WHERE status = 'active'

-- 格式化后:ON 子句独占一行,缺失一目了然
SELECT *
FROM users
JOIN orders
    -- 缺少 ON 条件!
WHERE status = 'active'

1.3 团队协作

统一的格式化风格意味着:

  • 任何人都能快速理解他人的查询
  • 代码审查聚焦于逻辑而非格式
  • 减少因格式差异产生的无意义 diff

二、常见风格指南

2.1 关键字大小写

大写关键字(推荐):

SELECT id, name
FROM users
WHERE status = 'active'
ORDER BY name ASC;

大写关键字是最广泛使用的约定,优势在于:

  • 关键字与标识符视觉区分明显
  • 与大多数 SQL 教程和文档一致
  • SQL 编辑器通常默认高亮大写关键字

小写关键字:

select id, name
from users
where status = 'active'
order by name asc;

小写风格在一些 Ruby/Python 社区中流行,理由是减少 Shift 键操作。但可读性不如大写。

2.2 缩进与换行

主要子句独占一行:

SELECT
    id,
    name,
    email
FROM users
WHERE status = 'active'
    AND created_at >= '2025-01-01'
GROUP BY status
HAVING COUNT(*) > 10
ORDER BY created_at DESC
LIMIT 20;

缩进规则:

  • 顶级关键字(SELECT、FROM、WHERE 等)不缩进
  • 列名、条件等缩进 4 个空格
  • 嵌套子查询增加一级缩进
SELECT
    u.id,
    u.name,
    (
        SELECT COUNT(*)
        FROM orders o
        WHERE o.user_id = u.id
    ) AS order_count
FROM users u
WHERE u.status = 'active';

2.3 逗号位置

逗号在前(行首逗号):

SELECT
    u.id
    , u.name
    , u.email
FROM users u

优势:添加或删除列时不影响其他行,diff 更干净。但在 SQL 社区中争议较大。

逗号在后(行末逗号,更主流):

SELECT
    u.id,
    u.name,
    u.email
FROM users u

优势:更符合自然阅读习惯,是大多数风格指南的推荐方式。

2.4 JOIN 格式化

-- 推荐:JOIN 和 ON 分两行,ON 缩进
SELECT
    u.id,
    u.name,
    o.total
FROM users u
JOIN orders o
    ON u.id = o.user_id
LEFT JOIN payments p
    ON o.id = p.order_id
    AND p.status = 'completed'
WHERE u.status = 'active';

多个 JOIN 条件用 AND 连接,与 WHERE 中的 AND 保持相同的缩进级别。

2.5 子查询格式化

-- 推荐:子查询加括号,内部正常缩进
SELECT
    u.id,
    u.name
FROM users u
WHERE u.id IN (
    SELECT DISTINCT user_id
    FROM orders
    WHERE total > 1000
);

对于复杂的子查询,考虑使用 CTE(Common Table Expression)替代:

WITH high_value_orders AS (
    SELECT DISTINCT user_id
    FROM orders
    WHERE total > 1000
)
SELECT
    u.id,
    u.name
FROM users u
JOIN high_value_orders hvo
    ON u.id = hvo.user_id;

2.6 CASE 表达式格式化

SELECT
    id,
    CASE
        WHEN score >= 90 THEN 'A'
        WHEN score >= 80 THEN 'B'
        WHEN score >= 70 THEN 'C'
        WHEN score >= 60 THEN 'D'
        ELSE 'F'
    END AS grade
FROM students;

2.7 INSERT 语句格式化

INSERT INTO users (id, name, email, status)
VALUES
    (1, 'Alice', 'alice@example.com', 'active'),
    (2, 'Bob', 'bob@example.com', 'inactive'),
    (3, 'Charlie', 'charlie@example.com', 'active');

三、方言差异

不同数据库的 SQL 方言在语法上存在差异,格式化时需要注意:

3.1 字符串引号

方言标准引号扩展引号
MySQL单引号 '双引号 " 或反引号 `
PostgreSQL单引号 '双引号 " 用于标识符
SQL Server单引号 '方括号 [] 用于标识符
SQLite单引号 '双引号 " 或方括号 []

3.2 方言特有语法

MySQL:

SELECT * FROM users
WHERE created_at BETWEEN '2025-01-01' AND '2025-12-31'
LIMIT 10 OFFSET 20;

PostgreSQL:

SELECT * FROM users
WHERE created_at BETWEEN '2025-01-01' AND '2025-12-31'
LIMIT 10 OFFSET 20;
-- PostgreSQL 还支持:
-- FETCH FIRST 10 ROWS ONLY
-- 和 RETURNING 子句

SQL Server:

SELECT TOP 10 * FROM users
WHERE created_at BETWEEN '2025-01-01' AND '2025-12-31'
ORDER BY created_at DESC
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

3.3 格式化器的方言支持

选择格式化工具时,务必确认它支持你使用的 SQL 方言。不同方言的关键字列表、函数名、标识符引用方式都可能不同。

四、自动格式化

4.1 为什么需要自动格式化

手动格式化 SQL 存在以下问题:

  • 耗时且容易不一致
  • 团队成员风格偏好不同
  • 容易在修改时破坏格式

自动格式化工具可以:

  • 一键统一风格
  • 集成到 CI/CD 流水线
  • 在编辑器中保存时自动格式化

4.2 常用工具

命令行工具:

  • sqlfluff:支持多种方言,可配置规则,适合 CI 集成
  • pg_format:PostgreSQL 专用格式化器
  • sqlparse:Python 库,支持基本格式化

编辑器插件:

  • VS Code 的 SQL Formatter 扩展
  • DataGrip 内置格式化功能
  • DBeaver 的 SQL 格式化器

4.3 在线格式化

CodeKit SQL 格式化器 提供在线 SQL 格式化功能,支持 MySQL、PostgreSQL、SQL Server、SQLite 等多种方言。只需粘贴 SQL 语句,选择方言和格式化选项,即可获得格式规范、缩进清晰的 SQL 代码。

4.4 配置团队规范

建议在项目中添加格式化配置文件,确保团队一致性:

{
    "sql": {
        "dialect": "postgresql",
        "keywordCase": "upper",
        "indentStyle": "space",
        "indentSize": 4,
        "logicalOperatorNewline": "before",
        "commaPosition": "after"
    }
}

将格式化检查加入 CI 流水线,确保不符合规范的 SQL 无法合并:

# GitHub Actions 示例
- name: Check SQL formatting
  run: |
    sqlfluff lint --dialect postgres queries/

五、格式化检查清单

编写 SQL 时,对照以下清单检查格式:

  • 关键字是否大写
  • 主要子句(SELECT、FROM、WHERE 等)是否各占一行
  • 列名和条件是否正确缩进
  • JOIN 和 ON 是否分两行
  • AND/OR 是否独占一行
  • 子查询是否正确缩进
  • CASE 表达式是否格式清晰
  • 逗号位置是否一致
  • 是否有多余的空行或尾随空格

总结

SQL 格式化不是锦上添花,而是专业开发的基本功。格式良好的 SQL 不仅更容易阅读和理解,还能减少错误、提升团队协作效率。遵循一致的风格指南——关键字大写、主要子句换行、合理缩进——并借助自动格式化工具确保规范落地。从今天开始,让你的每一条 SQL 都清晰可读。