涵盖:数据库基础概念、数据类型、五大约束、DDL 库表结构操作、DML 增删改查、多表 JOIN、分组聚合、分页、子查询、结果集合并,附带练习案例与避坑要点
一、数据库基础必学概念
核心学习清单:数据库、架构 (schema)、表、字段、数据类型、约束、视图、存储过程、函数、触发器、临时表、表变量。
1. 常用重点数据类型
| 分类 | 类型 | 说明与注意事项 |
|---|---|---|
| 字符类型 | varchar(n) | 非 Unicode 字符串,存中文容易乱码,适合纯英文数字 |
nvarchar(n) | Unicode 类型,中文优先使用,n 代表最多字符数量 | |
char / nchar | 定长字符,长度不足自动补空格,一般很少使用 | |
| 数值类型 | int | 整型,普通数字 |
bigint | 长整型,用于自增主键 Id,数据量大时使用 | |
decimal(精度,小数位) | 定点小数,金额、价格必须用这个,避免精度丢失 | |
float | 浮点数,存在精度误差,禁止用于金额计算 | |
| 时间类型 | datetime | 旧版时间类型,精度较低 |
datetime2 | 推荐使用,时间范围更大、精度更高 |
💡坑点总结:存储中文,字符字段一律选用nvarchar,避免中文乱码
2. 五大约束(保证数据完整性,防止脏数据)
约束作用:对表中数据做限制,从数据库层面拦截非法数据。
| 缩写 | 约束名称 | 关键字 | 作用说明 |
|---|---|---|---|
| PK | 主键约束 | PRIMARY KEY | 唯一标识一行数据;不能为 NULL,不能重复;一张表仅能设置 1 个主键,支持多个字段组成复合主键 |
| UK | 唯一约束 | UNIQUE | 字段值不能重复;SQL Server 允许最多 1 行 NULL,不能多条 NULL;一张表可设置多个唯一约束 |
| FK | 外键约束 | FOREIGN KEY | 引用另一张表的主键,保障关联数据一致性;例:订单表UserId必须在用户表中真实存在 |
| CHECK | 检查约束 | CHECK() | 限制字段取值范围;例:价格≥0、年龄 > 0 |
| DEFAULT | 默认值约束 | DEFAULT 值 | 插入数据不填写该字段时,自动填充预设值;例:IsDelete bit DEFAULT 0默认未删除 |
示例 1:创建用户表 UserInfo
CREATE TABLE UserInfo ( Id bigint PRIMARY KEY IDENTITY(1,1), -- PK主键,自增从1开始,步长1 UserName nvarchar(50) NOT NULL, Phone nvarchar(11) UNIQUE, -- UK唯一约束:手机号不能重复 Age int CHECK(Age>0), -- CHECK约束:年龄必须大于0 Balance decimal(18,2) DEFAULT 0, -- DEFAULT 默认值 IsDelete bit DEFAULT 0 )示例 2:创建订单表 OrderInfo,外键关联用户表
CREATE TABLE OrderInfo( OrderId bigint PRIMARY KEY IDENTITY(1,1), UserId bigint, OrderMoney decimal(18,2), -- FK外键,关联UserInfo的Id主键 FOREIGN KEY(UserId) REFERENCES UserInfo(Id) );📝课堂练习:新建 Product 产品表 需求:主键 Id、产品名称(唯一)、价格大于等于 0、默认库存 100
CREATE TABLE Product( Id bigint PRIMARY KEY IDENTITY(1,1), ProductName nvarchar(50) UNIQUE, Price decimal(18,2) CHECK(Price>=0), Inventory int DEFAULT 100 );二、DDL 数据定义语言(操作库、表结构,不操作表内数据)
核心关键字:CREATE创建、ALTER修改、DROP删除
⚠️警告:
DROP直接销毁对象,没有回收站,生产环境谨慎执行!
1. 数据库操作
CREATE DATABASE StudyDB; -- 创建数据库StudyDB USE StudyDB; -- 切换当前操作的数据库 DROP DATABASE StudyDB; -- 删除数据库练习任务:
- 创建数据库
BlogDB USE BlogDB;切换库- 新建 Article 文章表:主键 Id,标题 nvarchar,阅读量 int 默认 0
- 使用 ALTER 新增创建时间字段 datetime2
CREATE DATABASE BlogDB; GO USE BlogDB; CREATE TABLE Article( Id bigint PRIMARY KEY IDENTITY(1,1), Title nvarchar(100) NOT NULL, ReadNum int DEFAULT 0 ); -- ALTER新增创建时间 ALTER TABLE Article ADD CreateTime datetime2 DEFAULT SYSDATETIME();2.ALTER 修改表结构
-- 新增字段 ALTER TABLE UserInfo ADD Email nvarchar(100); -- 修改字段类型 ALTER TABLE UserInfo ALTER COLUMN Email nvarchar(200); -- 删除字段 ALTER TABLE UserInfo DROP COLUMN Email;3.DROP 删除表
DROP TABLE UserInfo; -- 删除整张表,表结构+数据全部消失三、DML 数据操作语言(重点!操作表里的数据行)
关键字:SELECT查询、INSERT新增、UPDATE修改、DELETE删除
✅ SELECT 完整书写顺序(牢记)
SELECT 字段列表 FROM 表 别名 JOIN 关联表 ON 关联条件 WHERE 行过滤条件 GROUP BY 分组字段 HAVING 分组后过滤 ORDER BY 排序字段 OFFSET ... FETCH NEXT 分页1. 多表连接 JOIN
| 连接类型 | 说明 |
|---|---|
INNER JOIN内连接 | 只返回两边表可以匹配上的数据,相当于交集 |
LEFT JOIN左连接 | 左表所有数据全部保留;右表匹配不到,右表字段填充 NULL |
RIGHT JOIN右连接 | 右表全部保留,左表匹配不到为 NULL |
CROSS JOIN交叉连接 | 笛卡尔积,大部分业务场景不使用 |
2.WHERE
- 在分组之前过滤原始数据行
- ❌不能使用聚合函数
SUM、COUNT、MAX等
3.GROUP BY 分组 + 聚合函数
常用聚合函数SUM()求和、COUNT()计数、AVG()求平均值、MAX()最大值、MIN()最小值
规则:SELECT 后面写的普通非聚合字段,需要放到 GROUP BY 中; 如果分组字段是主键,SQL Server 允许同表其他字段不写进 GROUP BY,为了兼容多数据库,建议全部写上
COUNT 补充重点
COUNT(字段):统计该字段不为 NULL 的行数;左连接统计子表记录优先用这个;NULL 不会计数COUNT(*):统计行数,不管是否为 NULL,左连接统计子表不要用,会统计出来错误数据
AS 别名
WHERE:过滤原始行;HAVING:过滤分组后的结果
AS用来给列设置查询临时别名,不会修改原表字段,AS 可以省略ORDER BY可以识别别名;GROUP BY、HAVING不能识别别名COUNT(o.OrderId) AS OrderCount --带AS COUNT(o.OrderId) OrderCount --省略AS,效果一样- 分组统计完成之后对分组结果过滤
- ✅可以写聚合函数,这是和 WHERE 最大区别
5.ORDER BY 排序
ORDER BY CreateTime DESC; --DESC降序,最新数据放最上面;ASC升序(默认)6. 分页两种写法
写法 1:TOP,简单取前 N 条
SELECT TOP 10 * FROM UserInfo;写法 2:OFFSET ... FETCH NEXT(SQL Server2012 及以上推荐)
⚠️强制要求:分页必须搭配
ORDER BY,否则分页结果错乱不稳定 计算公式:OFFSET = (页码-1)*每页条数
--第1页,取10条 SELECT * FROM UserInfo ORDER BY Id OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY;📝综合练习任务(LEFT JOIN + 分组 + HAVING + 排序 + 分页)
需求:
- LEFT JOIN 关联用户表、订单表,统计每个用户订单总数
- HAVING 筛选订单总数≥2 的用户
- ORDER BY 总金额降序
- OFFSET FETCH 取第 1 页,5 条数据
SELECT u.ID,u.UserName, COUNT(o.OrderId) OrderCount , SUM(o.OrderMoney) TotalMoney FROM UserInfo u LEFT JOIN OrderInfo o ON u.Id=o.UserId GROUP BY u.Id,u.UserName HAVING COUNT(o.OrderId)>=2 ORDER BY TotalMoney DESC OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY;7. 子查询
- 标量子查询:返回单个值,可以放在 SELECT、WHERE 后使用
- IN 子查询:返回一组值,
WHERE Id IN (1,2,3) - EXISTS:判断子查询是否有返回数据;找到匹配立刻停止,性能优于 IN
示例:查询有订单的用户
SELECT * FROM UserInfo u WHERE EXISTS (SELECT 1 FROM OrderInfo o WHERE o.UserId = u.Id);8.UNION/ UNION ALL 合并结果集
要求:前后查询列数量、数据类型必须保持一致
UNION:合并结果并且自动去重,性能差UNION ALL:直接拼接结果,不去重,业务优先使用,速度更快
SELECT Id,UserName FROM UserInfo WHERE Id=1 UNION ALL SELECT Id,UserName FROM UserInfo WHERE Id=29.INSERT/ UPDATE / DELETE 增删改
-- INSERT插入 INSERT INTO UserInfo(UserName,Age) VALUES(N'张三',20); -- UPDATE修改 UPDATE UserInfo SET Age=21 WHERE Id=1; -- DELETE删除 DELETE FROM UserInfo WHERE Id=1;⚠️生产重要提醒:UPDATE和DELETE执行前,先用 SELECT 验证 WHERE 条件! 一旦忘记写 WHERE 条件,会造成全表更新、全表删除重大事故。