本文目录导读:

编写数据库查询脚本是数据管理和分析的核心技能,为了给你最实用、专业的指导,我将从基础语法、不同数据库的差异以及最佳实践三个层面来讲解。
第一部分:核心基础(SQL 标准语法)
无论你使用 MySQL、PostgreSQL、SQL Server 还是 Oracle,以下语法是通用的。
基本查询结构
-- 注释:单行注释用两个短横线,多行用 /* */ SELECT 列名1, 列名2, ... -- 指定你要查询哪些列 FROM 表名 -- 指定从哪个表查 WHERE 条件 -- 筛选行(可选) GROUP BY 列名 -- 分组聚合(可选) HAVING 聚合条件 -- 对分组结果筛选(可选) ORDER BY 列名 [ASC|DESC]; -- 排序(可选)
常用子句详解
-
SELECT:你可以用 选择所有列,但生产环境中强烈建议显式列出列名,以提高性能。-- 不推荐 SELECT * FROM users; -- 推荐 SELECT id, username, email, signup_date FROM users;
-
WHERE:用于过滤记录。-- 精确匹配 SELECT * FROM orders WHERE status = 'paid'; -- 范围查询 SELECT * FROM products WHERE price BETWEEN 10 AND 100; -- 模糊匹配 SELECT * FROM customers WHERE name LIKE '%张%'; -- % 表示任意字符 -- 多条件 SELECT * FROM employees WHERE department = 'IT' AND salary > 5000; SELECT * FROM products WHERE category = 'A' OR category = 'B';
-
JOIN:连接多张表(这是查询最强大的功能之一)。-- 内连接:返回两张表中匹配的记录 SELECT u.username, o.order_amount FROM users u INNER JOIN orders o ON u.id = o.user_id; -- 左外连接:返回左表所有记录,右表无匹配则显示 NULL SELECT u.username, o.order_amount FROM users u LEFT JOIN orders o ON u.id = o.user_id; -- 右外连接:与 LEFT JOIN 相反 -- 全外连接:MySQL 不支持但其他支持,表示并集
-
GROUP BY与聚合函数-- 常用聚合函数: COUNT, SUM, AVG, MAX, MIN SELECT department, AVG(salary) as avg_salary, COUNT(*) as emp_count FROM employees GROUP BY department HAVING avg_salary > 6000; -- HAVING 是对分组后的结果过滤,WHERE 是对分组前过滤
-
ORDER BY与分页-- 排序 SELECT * FROM products ORDER BY price DESC, name ASC; -- 分页 (不同数据库语法不同) -- MySQL / PostgreSQL SELECT * FROM products LIMIT 10 OFFSET 20; -- 第3页,每页10条 -- SQL Server SELECT * FROM products ORDER BY id OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
第二部分:不同数据库的特定语法差异
写脚本时注意这些差异可以避免报错。
| 特性 | MySQL | PostgreSQL | SQL Server | Oracle |
|---|---|---|---|---|
| 字符串连接 | CONCAT(a, b) 或 a \|\| b |
a \|\| b 或 CONCAT() |
a + b (注意类型) |
a \|\| b |
| 当前日期 | CURDATE(), NOW() |
CURRENT_DATE, NOW() |
GETDATE() |
SYSDATE |
| 文本长度 | LENGTH() |
LENGTH() 或 CHAR_LENGTH() |
LEN() |
LENGTH() |
| 系统表/视图 | information_schema |
pg_catalog 或 information_schema |
sys.tables, INFORMATION_SCHEMA |
ALL_TABLES |
| 分页语法 | LIMIT x OFFSET y |
LIMIT x OFFSET y |
OFFSET...FETCH |
ROWNUM 或 FETCH (12c+) |
| 查询前N条 | LIMIT 10 |
LIMIT 10 |
SELECT TOP 10 ... |
FETCH FIRST 10 ROWS ONLY |
第三部分:真实场景脚本示例
假设我们有一个电商数据库。
场景 1:查询“最近30天活跃用户及其订单总额”
-- 目标:找出活跃用户及其消费能力
SELECT
u.id,
u.username,
COUNT(o.id) AS order_count, -- 下单次数
SUM(o.total_amount) AS total_spent -- 总消费金额
FROM
users u
INNER JOIN
orders o ON u.id = o.user_id
WHERE
o.created_at >= CURRENT_DATE - INTERVAL '30' DAY -- 最近30天
GROUP BY
u.id, u.username
HAVING
COUNT(o.id) >= 2 -- 至少下过2单
ORDER BY
total_spent DESC
LIMIT 20; -- 只看前20名
场景 2:检查数据库性能(查询慢查询或索引状态)
-- MySQL 查看当前运行的查询 SHOW FULL PROCESSLIST; -- 查看是否有表锁 (MySQL) SHOW OPEN TABLES WHERE In_use > 0; -- SQL Server 查看当前阻塞 SELECT * FROM sys.dm_exec_requests WHERE blocking_session_id != 0;
场景 3:数据清洗(查找重复数据)
-- 找出 email 重复的用户
SELECT
email,
COUNT(*) AS cnt
FROM
users
GROUP BY
email
HAVING
COUNT(*) > 1;
-- 删除重复数据(保留 ID 最小的那一条,谨慎操作)
DELETE FROM users
WHERE id NOT IN (
SELECT MIN(id)
FROM users
GROUP BY email
);
第四部分:最佳实践与注意事项
-
安全第一:不要直连生产库写脚本。
- 在测试数据库或只读副本上验证脚本正确性。
- 执行
UPDATE或DELETE语句前,先转成SELECT看一眼结果。
-
性能优化(索引与执行计划)。
WHERE子句中的列尽量有索引。- 避免在
WHERE中对列使用函数(如WHERE DATE(create_time) = '2023-01-01',应改为WHERE create_time >= '2023-01-01' AND create_time < '2023-01-02')。 - 使用
EXPLAIN命令(如EXPLAIN SELECT ...)查看查询执行计划,找出慢的原因。
-
可读性。
- SQL 关键字使用大写,表名/列名使用小写(团队约定)。
- 复杂查询使用 CTE(公用表表达式,
WITH子句)拆分逻辑。
-- 使用 CTE 的可读性更好 WITH active_users AS ( SELECT user_id, COUNT(*) as cnt FROM orders WHERE created_at > '2023-01-01' GROUP BY user_id HAVING cnt > 5 ) SELECT u.name, a.cnt FROM users u INNER JOIN active_users a ON u.id = a.user_id; -
参数化查询。
- 如果你在代码(如 Python、Java)中拼接查询字符串,务必使用参数占位符,防止 SQL 注入。
# Python 示例(错误做法) cursor.execute("SELECT * FROM users WHERE name = '" + name + "'") # Python 示例(正确做法) cursor.execute("SELECT * FROM users WHERE name = %s", (name,))
总结步骤
- 明确需求:我需要哪几张表的哪些列?筛选条件是什么?
- 从单表开始:先写
SELECT ... FROM ... WHERE ...跑通看数据对不对。 - 逐步加 JOIN:确认连接键(通常为主外键)是否正确。
- 加入聚合与排序:
GROUP BY后再ORDER BY。 - 调试与优化:
EXPLAIN检查性能,加索引。 - 安全上线:在非生产环境测试无误后,再在生产环境执行。
如果你有具体的数据库类型(如 MySQL 8.0 还是 PostgreSQL 15)或者特定的业务场景,可以告诉我,我能提供更精确的脚本示例。