SQL(Structured Query Language,结构化查询语言)是操作关系型数据库的标准语言,无论是数据查询、插入、更新,还是数据库表结构的创建与修改,都离不开 SQL。SQL Server、MySQL、Oracle 等主流关系型数据库管理系统均兼容 SQL 核心语法,仅在细节上略有差异。本文将从数据类型、核心查询语法、常用操作命令、语法规范等维度,系统梳理 SQL 基础知识点,帮新手搭建完整的 SQL 知识框架,快速实现从入门到上手。
数据类型是数据库表设计的基础,决定了列能存储的数据种类、范围和存储效率。不同数据库(如 SQL Server、MySQL)的数据类型命名略有差异,但核心分类一致,主要分为数值型、字符串型、日期时间型、特殊类型四大类。
数值型是最常用的数据类型之一,按是否包含小数可分为整数型和浮点型,需根据数值范围选择对应类型,避免存储空间浪费或数据溢出。
| 类型分类 | 具体类型(SQL Server/MySQL) | 取值范围 | 适用场景 |
|---|---|---|---|
| 整数型 | INT/INT | -2^31 ~ 2^31-1(约 ±21 亿) | 存储年龄、数量、编号等常规整数 |
| 整数型 | BIGINT/BIGINT | -2^63 ~ 2^63-1(约 ±9e18) | 存储超大整数,如订单号、用户 ID(避免 INT 溢出) |
| 整数型 | SMALLINT/SMALLINT | -2^15 ~ 2^15-1(约 ±3 万) | 存储范围较小的整数,如性别(1/0)、状态码 |
| 整数型 | TINYINT/TINYINT | 0 ~ 255(SQL Server);-128~127(MySQL) | 存储极小整数,如评分(1-5)、开关状态(0/1) |
| 浮点型 | DECIMAL(M,N)/DECIMAL(M,N) | 定点数,M 为总位数,N 为小数位数(如 DECIMAL (10,2) 表示最多 10 位,其中 2 位小数) | 存储金额、精度要求高的数值(如单价、工资) |
| 浮点型 | FLOAT/FLOAT | 单精度浮点数,精度约 7 位 | 存储精度要求不高的小数,如身高、体重 |
| 浮点型 | DOUBLE/DOUBLE | 双精度浮点数,精度约 15 位 | 存储精度要求较高的小数,如科学计算数据 |
注意:浮点型(FLOAT/DOUBLE)存在精度丢失问题,金融、财务类数据必须使用 DECIMAL,避免计算误差。
字符串型用于存储字符、文本类数据,核心区别在于 “固定长度” 和 “可变长度”,需根据内容长度特性选择,平衡存储效率和查询性能。
| 类型 | 特点 | 适用场景 | 注意事项 |
|---|---|---|---|
| CHAR(n) | 固定长度,n 为字符数(1~8000),不足补空格 | 长度固定的文本,如手机号(11 位)、身份证号(18 位)、邮编(6 位) | 查询速度快,但易浪费存储空间 |
| VARCHAR(n) | 可变长度,n 为最大字符数(1~8000),仅占用实际字符空间 | 长度不固定的文本,如姓名、地址、商品名称 | 节省存储空间,查询速度略低于 CHAR |
| TEXT/TINYTEXT/MEDIUMTEXT/LONGTEXT | 可变长度,无字符数上限(不同类型容量不同) | 存储大段文本,如文章内容、备注、日志 | 不能直接用于索引,查询效率较低 |
| NCHAR/NVARCHAR | 统一字符编码(Unicode),支持多语言(如中文、英文、日文) | 存储包含多语言的文本,如用户名、产品描述 | 占用空间是 CHAR/VARCHAR 的 2 倍,需按需使用 |
日期时间型用于记录时间信息,不同数据库的类型命名差异较大,但核心功能一致,需注意格式和取值范围。
| 类型(SQL Server) | 类型(MySQL) | 格式 | 适用场景 |
|---|---|---|---|
| DATE | DATE | YYYY-MM-DD | 仅存储日期,如生日、下单日期 |
| TIME | TIME | HH:MM | 仅存储时间,如打卡时间、会议时长 |
| DATETIME | DATETIME | YYYY-MM-DD HH:MM | 存储日期 + 时间,如订单创建时间、登录时间 |
| SMALLDATETIME | - | YYYY-MM-DD HH:MM(范围更小) | 存储精度要求不高的日期时间 |
| DATETIME2 | DATETIME2 | YYYY-MM-DD HH:MM.fffffff | 高精度日期时间,支持 7 位小数 |
| TIMESTAMP | TIMESTAMP | YYYY-MM-DD HH:MM | 自动记录数据修改时间,时区敏感 |
常用示例:
展开代码-- 创建表时指定日期时间类型 CREATE TABLE OrderInfo ( OrderID INT PRIMARY KEY, OrderDate DATE, -- 下单日期 CreateTime DATETIME -- 订单创建完整时间 );
除上述基础类型外,数据库还提供特殊类型适配特定场景:
CRUD 是数据库操作的核心,分别对应查询(Read)、新增(Create)、更新(Update)、删除(Delete),所有操作均围绕单表或多表展开,本节先聚焦单表 CRUD,详细讲解语法规则和实操示例(以下示例均基于Student学生表,表结构如下):
为统一示例场景,先创建Student学生表,后续 CRUD 操作均基于此表:
展开代码CREATE TABLE Student ( Sno INT PRIMARY KEY AUTO_INCREMENT, -- 学号,主键自增 Sname VARCHAR(20) NOT NULL, -- 姓名,非空 Sex CHAR(1) DEFAULT '男', -- 性别,默认男 Age TINYINT, -- 年龄 ClassName VARCHAR(30), -- 班级名称 Phone VARCHAR(11), -- 手机号 CreateTime DATETIME DEFAULT CURRENT_TIMESTAMP -- 创建时间,默认当前时间 );
用于向表中插入一条或多条数据,核心是保证列值与数据类型匹配,且满足约束(如非空、主键唯一)。
展开代码-- 方式1:指定列插入(推荐,可读性高,适配表结构变更) INSERT INTO 表名 (列1, 列2, ...) VALUES (值1, 值2, ...); -- 方式2:不指定列(需按表的列顺序填写所有值,不推荐) INSERT INTO 表名 VALUES (值1, 值2, ...); -- 方式3:批量插入(高效,减少IO次数) INSERT INTO 表名 (列1, 列2, ...) VALUES (值1, 值2, ...), (值1, 值2, ...), ...;
展开代码-- 示例1:指定列插入单条数据(仅填必填/核心列) INSERT INTO Student (Sname, Sex, Age, ClassName) VALUES ('张三', '男', 18, '高一(1)班'); -- 示例2:利用默认值插入(性别用默认值“男”,创建时间用默认当前时间) INSERT INTO Student (Sname, Age, ClassName) VALUES ('李四', 19, '高一(2)班'); -- 示例3:批量插入3条数据 INSERT INTO Student (Sname, Sex, Age, ClassName, Phone) VALUES ('王五', '女', 18, '高一(1)班', '13800138000'), ('赵六', '男', 17, '高一(2)班', '13900139000'), ('钱七', '女', 18, '高一(1)班', '13700137000');
Sname)必须赋值,否则报错;AUTO_INCREMENT),插入时可省略,数据库自动生成;YYYY-MM-DD HH:MM:SS),或用CURRENT_TIMESTAMP取当前时间。数据查询是 SQL 最核心的功能,用于从表中提取符合条件的数据,灵活度最高,完整语法如下:
展开代码SELECT [DISTINCT] <目标列名序列> -- DISTINCT去重,*代表所有列 FROM <表名> [AS 别名] -- 指定数据来源,AS可省略 [WHERE <行选择条件>] -- 筛选符合条件的行 [GROUP BY <分组依据列>] -- 对查询结果分组 [HAVING <组筛选条件>] -- 对分组后的结果筛选(支持聚合函数) [ORDER BY <排序依据列> [ASC/DESC]] -- 对结果集排序,ASC升序(默认),DESC降序 [LIMIT <行数>] -- MySQL:限制返回行数;SQL Server用TOP N
展开代码-- 示例1:查询所有列的所有数据(测试/小表用,大表禁止用*) SELECT * FROM Student; -- 示例2:查询指定列(姓名、年龄、班级) SELECT Sname, Age, ClassName FROM Student; -- 示例3:列起别名(提升可读性) SELECT Sname AS 姓名, Age AS 年龄, ClassName AS 班级 FROM Student; -- 示例4:去重查询(查询所有班级名称,不重复) SELECT DISTINCT ClassName FROM Student; -- 示例5:条件筛选(查询高一(1)班的女生) SELECT Sname, Age FROM Student WHERE ClassName = '高一(1)班' AND Sex = '女'; -- 示例6:范围筛选(查询年龄18~19岁的学生) SELECT Sname, Age FROM Student WHERE Age BETWEEN 18 AND 19; -- 示例7:模糊查询(查询姓“张”的学生) SELECT Sname, ClassName FROM Student WHERE Sname LIKE '张%'; -- 示例8:排序(按年龄降序,年龄相同按姓名升序) SELECT Sname, Age FROM Student ORDER BY Age DESC, Sname ASC; -- 示例9:限制返回行数(MySQL:只返回前2条数据) SELECT * FROM Student LIMIT 2; -- 示例10:分组统计(统计每个班级的学生人数) SELECT ClassName AS 班级, COUNT(*) AS 人数 FROM Student GROUP BY ClassName; -- 示例11:分组筛选(统计人数大于2的班级) SELECT ClassName AS 班级, COUNT(*) AS 人数 FROM Student GROUP BY ClassName HAVING COUNT(*) > 2;
WHERE筛选行,在分组前执行;HAVING筛选分组结果,在分组后执行,且支持聚合函数;NULL值判断必须用IS NULL/IS NOT NULL,不能用=/!=;%开头会导致索引失效,尽量避免(如%张三)。用于修改表中已存在的数据,核心是必须加 WHERE 条件,否则会更新全表数据!
展开代码UPDATE 表名 SET 列1=值1, 列2=值2, ... -- 多个列用逗号分隔 [WHERE 条件]; -- 筛选要更新的行,必加!
展开代码-- 示例1:更新单条数据(将学号1的学生年龄改为20) UPDATE Student SET Age = 20 WHERE Sno = 1; -- 示例2:更新多条数据(将高一(1)班所有学生的年龄加1) UPDATE Student SET Age = Age + 1 WHERE ClassName = '高一(1)班'; -- 示例3:更新多列数据(修改学号2的学生姓名和手机号) UPDATE Student SET Sname = '李小四', Phone = '13600136000' WHERE Sno = 2; -- 示例4:结合默认值/函数更新(将未填手机号的学生手机号设为默认值) UPDATE Student SET Phone = '未填写' WHERE Phone IS NULL;
SELECT * FROM Student WHERE ClassName = '高一(1)班');BEGIN → 执行 UPDATE → 验证数据 → COMMIT/ROLLBACK),避免误操作。用于删除表中已存在的数据,同样必须加 WHERE 条件,否则会清空全表!
展开代码DELETE FROM 表名 [WHERE 条件]; -- 筛选要删除的行,必加!
展开代码-- 示例1:删除单条数据(删除学号3的学生) DELETE FROM Student WHERE Sno = 3; -- 示例2:删除多条数据(删除高一(2)班年龄小于18的学生) DELETE FROM Student WHERE ClassName = '高一(2)班' AND Age < 18; -- 示例3:删除空值数据(删除未填写手机号的学生) DELETE FROM Student WHERE Phone IS NULL;
DELETE仅删除数据,保留表结构;若需清空全表且重置自增主键,用TRUNCATE TABLE 表名(效率更高,但不可恢复);IsDelete列,值为 1 表示删除,0 表示正常),而非物理删除。实际业务中,数据通常分散在多个表中,需通过 “连接” 整合,核心连接类型:
| 连接类型 | 含义 | 示例 |
|---|---|---|
| INNER JOIN(内连接) | 仅返回两表匹配的记录 | Student JOIN SC ON Student.Sno = SC.Sno |
| LEFT JOIN(左连接) | 返回左表所有记录 + 右表匹配记录(无匹配则右表列值为 NULL) | Student LEFT JOIN SC ON Student.Sno = SC.Sno |
| RIGHT JOIN(右连接) | 返回右表所有记录 + 左表匹配记录 | Student RIGHT JOIN SC ON Student.Sno = SC.Sno |
| FULL JOIN(全连接) | 返回两表所有记录(无匹配则对应列值为 NULL) | Student FULL JOIN SC ON Student.Sno = SC.Sno |
展开代码-- 先创建选课表SC,用于多表连接示例 CREATE TABLE SC ( Sno INT, -- 学号 Cno INT, -- 课程号 Grade TINYINT, -- 成绩 PRIMARY KEY (Sno, Cno), -- 复合主键 FOREIGN KEY (Sno) REFERENCES Student(Sno) -- 外键关联学生表 ); -- 内连接查询学生姓名及对应的选课成绩 SELECT Student.Sname, SC.Cno, SC.Grade FROM Student INNER JOIN SC ON Student.Sno = SC.Sno; -- 左连接查询所有学生(包括未选课的)及选课成绩 SELECT Student.Sname, SC.Cno, SC.Grade FROM Student LEFT JOIN SC ON Student.Sno = SC.Sno;
展开代码-- 创建数据库(指定字符集,避免中文乱码) CREATE DATABASE SchoolDB CHARACTER SET utf8mb4; -- 选择要操作的数据库 USE SchoolDB; -- 删除数据库(谨慎执行!) DROP DATABASE SchoolDB;
展开代码-- 修改表:添加列 ALTER TABLE Student ADD Email VARCHAR(50); -- 修改表:修改列类型 ALTER TABLE Student MODIFY COLUMN Email VARCHAR(100); -- 修改表:删除列 ALTER TABLE Student DROP COLUMN Email; -- 删除表(谨慎执行!) DROP TABLE Student;
索引是数据库优化的核心手段,为频繁查询的列创建索引,可大幅提升查询效率。
展开代码-- 为学生表的姓名列创建索引 CREATE INDEX idx_student_name ON Student(Sname); -- 删除索引 DROP INDEX idx_student_name ON Student;
索引使用原则:
--,多行注释用/* ... */;AS为列 / 表起别名,AS 可省略,如SELECT Sname 姓名 FROM Student。AVG(Grade)仅计算非空成绩的平均值;%开头(如%张三)会导致索引失效,尽量避免;WHERE Sno = '1'(字符型)和WHERE Sno = 1(数值型)的区别。掌握以上基础知识点后,可进一步学习子查询、存储过程、事务、视图等进阶内容,逐步实现从 “会用” 到 “用好” SQL 的进阶。
本文作者:zzz
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!