SQL(Structured Query Language,结构化查询语言)是操作关系型数据库的核心工具,无论是后端开发、数据分析、运维监控,还是大数据处理,SQL都是不可或缺的技能。从简单的"查询数据"到复杂的"多表关联分析",SQL的语法体系既基础又灵活。
本文将从**基础语法、进阶语法、常用函数、性能优化小贴士**四个维度,结合实战案例详细讲解常见SQL语法,覆盖MySQL、Oracle、SQL Server等主流数据库的通用用法,帮你快速掌握SQL的核心应用。
一、先搭个基础:示例表结构
为了让语法示例更易理解,我们先定义三个常用的示例表(后续案例均基于这三张表):
1. 学生表(student)
|--------------|-------------|----------|
| 字段名 | 类型 | 说明 |
| student_id | INT | 学生ID(主键) |
| student_name | VARCHAR(50) | 学生姓名 |
| age | INT | 年龄 |
| gender | VARCHAR(10) | 性别 |
| class_id | INT | 班级ID(外键) |
2. 班级表(class)
|------------|-------------|----------|
| 字段名 | 类型 | 说明 |
| class_id | INT | 班级ID(主键) |
| class_name | VARCHAR(50) | 班级名称 |
| teacher | VARCHAR(50) | 班主任 |
3. 成绩表(score)
|-------------|--------------|----------|
| 字段名 | 类型 | 说明 |
| score_id | INT | 成绩ID(主键) |
| student_id | INT | 学生ID(外键) |
| course_name | VARCHAR(50) | 课程名称 |
| score | DECIMAL(5,2) | 分数 |
二、SQL基础语法:数据库与表的核心操作
SQL基础语法主要分为**DDL(数据定义语言)******和******DML(数据操作语言)**,前者负责定义数据库/表结构,后者负责操作数据。
1. DDL:数据库与表的定义(创建/修改/删除)
(1)数据库操作
sql
-- 1. 创建数据库(指定字符集,避免中文乱码)
CREATE DATABASE IF NOT EXISTS school_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 2. 使用数据库
USE school_db;
-- 3. 删除数据库(谨慎使用!)
DROP DATABASE IF EXISTS school_db;
(2)表操作
sql
-- 1. 创建学生表(含主键、数据类型、注释)
CREATE TABLE IF NOT EXISTS student (
student_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '学生ID',
student_name VARCHAR(50) NOT NULL COMMENT '学生姓名',
age INT COMMENT '年龄',
gender VARCHAR(10) COMMENT '性别',
class_id INT COMMENT '班级ID',
-- 外键关联班级表(可选,视业务场景而定)
FOREIGN KEY (class_id) REFERENCES class(class_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生表';
-- 2. 修改表结构(添加字段、修改字段、删除字段)
-- 添加字段:新增手机号字段
ALTER TABLE student ADD COLUMN phone VARCHAR(20) COMMENT '手机号' AFTER age;
-- 修改字段:修改age字段类型为TINYINT
ALTER TABLE student MODIFY COLUMN age TINYINT COMMENT '年龄';
-- 删除字段:删除手机号字段
ALTER TABLE student DROP COLUMN phone;
-- 3. 删除表(谨慎使用!)
DROP TABLE IF EXISTS student;
-- 4. 清空表数据(保留表结构,自增主键重置)
TRUNCATE TABLE student;
2. DML:数据的增删改查(核心中的核心)
(1)插入数据(INSERT)
sql
-- 1. 插入单条数据(指定字段)
INSERT INTO student (student_name, age, gender, class_id)
VALUES ('张三', 18, '男', 1);
-- 2. 插入多条数据(批量插入,效率更高)
INSERT INTO student (student_name, age, gender, class_id)
VALUES
('李四', 19, '男', 1),
('王五', 18, '女', 2),
('赵六', 20, '男', 2);
-- 3. 从其他表插入数据(将查询结果插入表中)
INSERT INTO student_backup (student_id, student_name, age)
SELECT student_id, student_name, age FROM student WHERE gender = '女';
(2)查询数据(SELECT)
SELECT是SQL中使用最频繁的语法,基础用法如下:
sql
-- 1. 查询所有字段(不推荐,性能差,仅测试用)
SELECT * FROM student;
-- 2. 查询指定字段
SELECT student_id, student_name, age FROM student;
-- 3. 带条件查询(WHERE子句)
SELECT student_name, age FROM student WHERE gender = '男' AND age > 18;
-- 4. 去重查询(DISTINCT)
SELECT DISTINCT class_id FROM student;
-- 5. 别名(AS,可省略):给字段/表起别名,简化代码
SELECT s.student_id AS id, s.student_name AS name FROM student s;
(3)更新数据(UPDATE)
sql
-- 修改单条数据(必须加WHERE条件,否则修改全表!)
UPDATE student SET age = 20, class_id = 3 WHERE student_id = 1;
-- 批量修改数据
UPDATE student SET class_id = 2 WHERE gender = '女';
(4)删除数据(DELETE)
sql
-- 删除单条数据(必须加WHERE条件,否则删除全表!)
DELETE FROM student WHERE student_id = 1;
-- 批量删除数据
DELETE FROM student WHERE class_id = 3;
三、SQL进阶语法:解锁复杂数据操作
基础语法只能处理单表数据,而实际业务中往往需要多表关联、数据聚合、分页等复杂操作,这就需要用到进阶语法。
1. 联表查询:多表数据关联(JOIN)
联表查询是进阶语法的核心,主要分为**内连接、左连接、右连接、全连接**四种,其中内连接和左连接最常用。
(1)内连接(INNER JOIN):只返回两表匹配的数据
sql
-- 查询学生姓名及其所属班级名称(仅显示有班级的学生)
SELECT s.student_name, c.class_name
FROM student s
INNER JOIN class c ON s.class_id = c.class_id;
(2)左连接(LEFT JOIN):返回左表所有数据,右表匹配不到则为NULL
sql
-- 查询所有学生姓名及其所属班级名称(无班级的学生也显示,班级名称为NULL)
SELECT s.student_name, c.class_name
FROM student s
LEFT JOIN class c ON s.class_id = c.class_id;
(3)右连接(RIGHT JOIN):返回右表所有数据,左表匹配不到则为NULL
sql
-- 查询所有班级名称及其对应的学生姓名(无学生的班级也显示,学生姓名为NULL)
SELECT s.student_name, c.class_name
FROM student s
RIGHT JOIN class c ON s.class_id = c.class_id;
(4)全连接(FULL JOIN):返回两表所有数据,匹配不到则为NULL
注意 :MySQL不支持直接使用FULL JOIN,可通过UNION组合左连接和右连接实现;Oracle、SQL Server支持FULL JOIN。
sql
-- MySQL实现全连接
SELECT s.student_name, c.class_name
FROM student s
LEFT JOIN class c ON s.class_id = c.class_id
UNION
SELECT s.student_name, c.class_name
FROM student s
RIGHT JOIN class c ON s.class_id = c.class_id;
2. 子查询:嵌套在主查询中的查询语句
子查询是将一个查询结果作为另一个查询的条件或数据源,分为**标量子查询、列子查询、表子查询**。
(1)标量子查询:返回单个值(一行一列)
sql
-- 查询与张三同班级的学生(先查张三的班级ID,再查该班级的学生)
SELECT student_name FROM student
WHERE class_id = (SELECT class_id FROM student WHERE student_name = '张三');
(2)列子查询:返回一列数据(多行一列),使用IN/ANY/ALL
sql
-- 查询班级1或班级2的学生(返回多个class_id)
SELECT student_name FROM student
WHERE class_id IN (SELECT class_id FROM class WHERE class_name IN ('一班', '二班'));
(3)表子查询:返回多行多列,作为临时表
sql
-- 查询成绩大于80分的学生姓名(先查成绩表的学生ID,再关联学生表)
SELECT s.student_name
FROM student s
INNER JOIN (SELECT student_id FROM score WHERE score > 80) sc ON s.student_id = sc.student_id;
3. 分组与聚合:数据统计分析(GROUP BY + 聚合函数)
GROUP BY用于将数据按指定字段分组,结合聚合函数(如COUNT、SUM、AVG)实现数据统计。
sql
-- 1. 统计每个班级的学生人数
SELECT c.class_name, COUNT(s.student_id) AS student_count
FROM class c
LEFT JOIN student s ON c.class_id = s.class_id
GROUP BY c.class_name;
-- 2. 统计每个学生的总成绩
SELECT s.student_name, SUM(sc.score) AS total_score
FROM student s
LEFT JOIN score sc ON s.student_id = sc.student_id
GROUP BY s.student_name;
-- 3. 分组后过滤(HAVING):统计学生人数大于5的班级
-- 注意:HAVING用于分组后过滤,WHERE用于分组前过滤
SELECT c.class_name, COUNT(s.student_id) AS student_count
FROM class c
LEFT JOIN student s ON c.class_id = s.class_id
GROUP BY c.class_name
HAVING student_count > 5;
4. 排序与分页:控制数据展示顺序和数量
(1)排序(ORDER BY):默认升序(ASC),降序用DESC
sql
-- 按年龄降序、姓名升序排序
SELECT student_name, age FROM student ORDER BY age DESC, student_name ASC;
(2)分页:不同数据库语法不同,是业务中必用的语法(如列表页展示)
sql
-- MySQL:LIMIT 偏移量, 每页条数(偏移量从0开始)
-- 示例:查询第2页数据,每页10条
SELECT student_name, age FROM student ORDER BY student_id LIMIT 10, 10;
-- Oracle:ROWNUM + 子查询
SELECT * FROM (
SELECT s.*, ROWNUM rn FROM student s ORDER BY student_id
) WHERE rn BETWEEN 11 AND 20;
-- SQL Server:OFFSET + FETCH
SELECT student_name, age FROM student ORDER BY student_id OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
四、SQL常用函数:提升数据处理效率
SQL提供了丰富的内置函数,涵盖字符串、数值、日期、聚合等类型,以下是最常用的函数示例。
1. 字符串函数
sql
-- 1. 长度:LENGTH(MySQL)/ LEN(SQL Server)
SELECT LENGTH(student_name) AS name_length FROM student;
-- 2. 拼接:CONCAT(MySQL)/ +(SQL Server)/ ||(Oracle)
SELECT CONCAT(student_name, '-', gender) AS name_gender FROM student;
-- 3. 大小写转换:UPPER(大写)/ LOWER(小写)
SELECT UPPER(student_name) AS upper_name FROM student;
-- 4. 截取字符串:SUBSTRING(通用)
SELECT SUBSTRING(student_name, 1, 1) AS first_char FROM student; -- 截取第一个字符
2. 数值函数
sql
-- 1. 四舍五入:ROUND
SELECT ROUND(score, 1) AS round_score FROM score; -- 保留1位小数
-- 2. 取整:CEIL(向上取整)/ FLOOR(向下取整)
SELECT CEIL(score) AS ceil_score, FLOOR(score) AS floor_score FROM score;
-- 3. 求和/平均值/最大值/最小值:SUM/AVG/MAX/MIN(聚合函数)
SELECT SUM(score) AS total, AVG(score) AS avg, MAX(score) AS max, MIN(score) AS min FROM score;
3. 日期函数
日期函数是处理时间数据的核心,不同数据库语法略有差异,以下是MySQL的常用示例:
sql
-- 1. 获取当前时间:NOW()(日期+时间)/ CURDATE()(仅日期)/ CURTIME()(仅时间)
SELECT NOW(), CURDATE(), CURTIME();
-- 2. 日期格式化:DATE_FORMAT
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s') AS format_time;
-- 3. 日期加减:DATE_ADD/DATE_SUB
SELECT DATE_ADD(NOW(), INTERVAL 7 DAY) AS next_week; -- 7天后
SELECT DATE_SUB(NOW(), INTERVAL 1 MONTH) AS last_month; -- 1个月前
-- 4. 提取日期部分:YEAR/MONTH/DAY/HOUR
SELECT YEAR(NOW()) AS year, MONTH(NOW()) AS month, DAY(NOW()) AS day;
五、SQL语法性能优化小贴士
掌握语法的同时,也要注意性能优化,避免写出"慢SQL"。以下是几个实用的优化技巧:
1. 避免使用SELECT *,只查询需要的字段
SELECT *会查询所有字段,不仅增加网络传输量,还会导致无法使用覆盖索引,严重影响性能。
2. 给查询条件字段加索引
索引是提升查询速度的关键,给WHERE、JOIN、ORDER BY等子句中的字段添加索引(如主键索引、普通索引、联合索引)。
sql
-- 给student表的class_id字段添加普通索引
CREATE INDEX idx_student_class_id ON student(class_id);
3. 尽量使用WHERE代替HAVING
WHERE在分组前过滤数据,HAVING在分组后过滤数据,使用WHERE可以减少分组的数据量,提升性能。
4. 批量操作数据
批量插入/更新数据比单条操作效率高得多,尽量使用INSERT INTO ... VALUES (...), (...)的批量语法。
5. 避免在WHERE子句中使用函数或运算
在WHERE子句中对字段使用函数或运算,会导致索引失效,例如:
sql
-- 错误:索引失效
SELECT * FROM student WHERE YEAR(birthday) = 2000;
-- 正确:改写为范围查询,使用索引
SELECT * FROM student WHERE birthday >= '2000-01-01' AND birthday <= '2000-12-31';
六、实战案例:综合运用SQL语法
最后,我们通过一个综合案例,将上述语法串联起来,加深理解:
需求:查询每个班级的"数学"课程平均分,且平均分大于80分,按平均分降序排列
sql
SELECT c.class_name, AVG(sc.score) AS avg_math_score
FROM class c
LEFT JOIN student s ON c.class_id = s.class_id
LEFT JOIN score sc ON s.student_id = sc.student_id
WHERE sc.course_name = '数学'
GROUP BY c.class_name
HAVING avg_math_score > 80
ORDER BY avg_math_score DESC;
七、总结
SQL的语法体系看似繁杂,但核心逻辑是**"数据定义→数据操作→数据统计"**。对于初学者,先掌握基础的增删改查和联表查询,再逐步学习聚合函数、子查询等进阶语法;对于资深开发者,重点在于结合业务场景优化SQL性能,写出高效、可维护的代码。
记住,SQL是一门"熟能生巧"的技能,多写、多练、多分析慢查询,才能真正掌握它。希望本文的语法解析和实战案例,能帮你夯实SQL基础,应对日常开发和数据分析的需求。