☰
SQL Server 学习笔记速查手册:建库建表、视图索引与存储过程实战
2026/10/14 17:19:14 网站建设 项目流程

简介:这是一份面向数据库初学者与运维人员的 SQL Server 学习笔记,以 doc 文档形式系统梳理了关系数据库管理系统的核心知识点,适合零基础入门或需要快速查阅语法与概念的读者。压缩包内共 1 个 doc 文件,约 499KB,内容涵盖数据库对象的创建、删除与修改,C/S 体系结构,以及表、列、索引、触发器、存储过程等对象的容量限制。笔记还整理了关系数据库模型中的实体、属性、码、域等概念,层次、关系、网状与面向对象四类数据模型,以及主键、外键、默认值、check、unique 等约束的用法。系统数据库 Master、Model、Tempdb、Msdb、Pubs、Northwind 的作用,数据文件、次要文件、日志文件与文件组等存储机制,以及新建用户、角色与授权的操作也有涉及。目前已有 440 人学习,适合作为课堂笔记补充或日常查阅手册。

1. 从一份 SQL Server 学习笔记说起:为什么我建议你把它当“速查手册”而不是“教材”

如果你手头正放着一份 SQL Server 学习笔记,大概率是两种情况:要么刚接手一个老系统,数据库跑在 SQL Server 上,需要快速把语法和对象体系捡起来;要么在准备面试或课程设计,想找一份能覆盖建库、建表、约束、视图、索引、存储过程、游标的浓缩材料。这份笔记的价值不在于它有多“新”,而在于它把 SQL Server 的核心对象和 T-SQL 语法用一条主线串了起来——从 Create/Drop/Alter 这类 DDL,到 Select/Insert/Update/Delete 这类 DML,再到 Grant/Revoke 权限控制,最后落到约束、范式、存储过程和游标。它更像一本可以随时翻的速查手册,而不是从头读到尾的教科书。适合谁?适合已经有一点数据库概念、需要快速把 SQL Server 的“对象地图”和“语法骨架”搭起来的从业者。下面我按实际复现的顺序,把这份笔记拆成能直接抄作业的步骤。

2. 建库建表与数据类型:把笔记里的语法变成可执行的 T-SQL

2.1 数据库文件与文件组的落地写法

笔记里提到数据库存储被映射成操作系统文件,主要文件 .mdf、次要文件 .ndf、日志文件 .ldf,还有文件组的概念。这部分如果只背概念,实际建库时很容易翻车。常见做法是:建库时显式指定数据文件和日志文件的初始大小、增长增量和最大大小,避免默认配置在生产环境里把磁盘撑爆。

-- 创建数据库,显式指定数据文件和日志文件的存储参数 CREATE DATABASE ShopDB ON PRIMARY ( NAME = 'ShopDB_Data', -- 逻辑文件名 FILENAME = 'D:\SQLData\ShopDB.mdf', -- 物理路径,按实际环境改 SIZE = 10MB, -- 初始大小 MAXSIZE = 500MB, -- 上限,防止无限增长 FILEGROWTH = 5MB -- 每次增长量 ) LOG ON ( NAME = 'ShopDB_Log', FILENAME = 'D:\SQLData\ShopDB_Log.ldf', SIZE = 5MB, MAXSIZE = 200MB, FILEGROWTH = 5MB );

逻辑说明:ON PRIMARY 定义主文件组的数据文件,LOG ON 定义事务日志文件。参数里 SIZE 是初始分配,MAXSIZE 是硬上限,FILEGROWTH 是自动增长步长。笔记里说“一般用户建立数据库时不指定可选项”,这在学习环境没问题,但一旦放到真实磁盘上,不指定 MAXSIZE 就是给自己埋雷。文件组的作用是方便管理,比如把频繁读写的表放到独立文件组,备份和恢复时可以按文件组粒度操作。

2.2 数据类型选择与建表约束

笔记里列了 char、varchar、int、bigint、smallint、tinyint、numeric、money、datetime、table 这些类型。实际建表时,char 和 varchar 的区别是高频踩坑点:char(n) 是固定长度,实际存储 n 个字节,不足补空格;varchar(n) 是可变长度,存储实际字符字节数。如果拿 char(50) 存一个 3 个字符的姓名,剩下 47 个位置全是空格,查询时用等号匹配还可能因为尾部空格产生玄学结果。

-- 建表时把主键、外键、默认值、check、unique 一次写全 CREATE TABLE Goods ( goods_id VARCHAR(10) NOT NULL, goods_name VARCHAR(50) NOT NULL, goods_type_name VARCHAR(20) DEFAULT '生活用品', goods_number INT NOT NULL, goods_price MONEY NOT NULL, bid_date DATETIME DEFAULT GETDATE(), CONSTRAINT PK_Goods PRIMARY KEY (goods_id), CONSTRAINT CK_Goods_Number CHECK (goods_number >= 0), CONSTRAINT UQ_Goods_Name UNIQUE (goods_name) );

逻辑说明:PRIMARY KEY 定义主键,主键列不能为空且值唯一;DEFAULT 在插入时未指定该列则自动填默认值;CHECK 限制 goods_number 不能为负;UNIQUE 保证商品名不重复。笔记里强调“插入的列值必须与表中的列个数和顺序匹配”,所以更稳妥的写法是 insert 时显式列出列名,而不是依赖顺序。

-- 显式列名的插入,避免顺序错位 INSERT INTO Goods (goods_id, goods_name, goods_number, goods_price) VALUES ('G001', '课桌', 100, 199.00);

参数说明:goods_type_name 和 bid_date 没写,会走 DEFAULT 约束。如果建表时这两列没有默认值且允许为空,不写就是 NULL;如果既不允许为空又没默认值,这条 insert 直接失败。这就是笔记里说的“如果创建表时列的条件设置可以为空,那么插入数据时没有此项数据可以以 null 代替”的实际含义。

3. 视图、索引与存储过程:三个最容易被“会用”掩盖的细节

3.1 视图定义里的 With Check Option 到底卡住了什么

笔记里给了好几个视图例子,其中 With Check Option 是最容易只抄不理解的。它的作用是:对视图做插入、修改时,必须满足视图定义中 Where 子句的条件,否则操作被拒绝。比如基于“电子产品”条件建的视图,你往视图里插一条“生活用品”的记录,With Check Option 会直接拦下来。

-- 基于 Goods 表建视图,只暴露电子产品,并强制检查条件 CREATE VIEW Goods_Electronics_View AS SELECT goods_name, goods_type_name FROM Goods WHERE goods_type_name = '电子产品' WITH CHECK OPTION;

逻辑说明:查询这个视图只能看到电子产品。如果尝试 INSERT 或 UPDATE 让 goods_type_name 变成非电子产品,With Check Option 会报错。笔记里还提到定义视图的查询表达式不能含 INTO、ORDER BY、COMPUTE、COMPUTE BY,不能引用临时表或表变量。这些限制在实际写视图时如果忽略,创建语句直接失败,报错信息往往不够直白,需要回头逐条核对。

3.2 簇索引与非簇索引的选型边界

笔记里说簇索引与表的物理顺序相同,一个表只能有一个簇索引;非簇索引按完全不同的结构排序,先找到数据位置再取数据。实际选型时,簇索引一般给主键或最频繁的范围查询列,因为簇索引决定了数据行的物理排列顺序。非簇索引适合高频的等值查询和覆盖查询。

-- 唯一簇索引:按 goods_id 物理排序 CREATE UNIQUE CLUSTERED INDEX IX_Goods_Id ON Goods (goods_id); -- 复合非簇索引:覆盖 goods_id 和 goods_type_name 的查询 CREATE INDEX IX_Goods_Type ON Goods (goods_id, goods_type_name);

参数说明:UNIQUE 表示索引键值不允许重复;CLUSTERED 表示簇索引;ASC/DESC 控制排序方向。笔记里列了“需要创建索引的地方”:经常搜索的列、需要排序的列、主键或外键、经常出现在 Where 里的列。但索引不是越多越好,每个索引都会增加 insert、update、delete 的维护成本。我一般会先看执行计划,确认全表扫描是瓶颈再补索引,而不是建表时先把能建的索引全建一遍。

3.3 存储过程的参数与嵌套层级

笔记里提到一个存储过程最多 1024 个参数、32 级嵌套。实际写存储过程时,参数命名用 @ 前缀,调用时按位置或按名称传参。下面这个存储过程模拟“修改商品库存并写入历史表”的操作,对应笔记里 modify_process 的思路。

CREATE PROCEDURE Modify_Goods_Process @bid_user VARCHAR(10), @bid_date DATETIME, @bid_number INT, @bid_goods_id VARCHAR(10), @goods_price MONEY AS BEGIN -- 扣减库存 UPDATE Goods SET goods_number = goods_number - @bid_number WHERE goods_id = @bid_goods_id; -- 写入用户历史表 INSERT INTO User_History (user_name, amount, bid_date) VALUES (@bid_user, @goods_price * @bid_number, @bid_date); END; GO -- 调用 EXEC Modify_Goods_Process @bid_user = 'U001', @bid_date = '2025-01-01', @bid_number = 2, @bid_goods_id = 'G001', @goods_price = 199.00;

逻辑说明:存储过程把多条 SQL 封装成一个调用单元,减少网络往返。参数用 @ 声明,调用时推荐按名称传参,避免顺序错位。笔记里说“存储过程中的 SQL 语句已被封装,所以无法对其所引用的表进行存在性验证”,意思是创建存储过程时不会检查引用的表是否存在,只有执行时才报错。这个特性在重构表结构时特别容易踩坑:表改了名,存储过程创建时不报错,运行时才炸。

4. 避坑与排查:这份笔记里没写透的五个翻车点

4.1 现象:插入中文变成问号;原因:varchar 没指定排序规则或列长度不够;解决:改用 nvarchar 并确认数据库排序规则

笔记里只列了 char 和 varchar,没提 nvarchar。实际存中文时,如果数据库排序规则不是中文相关,varchar 可能丢字符。常见做法是中文列用 nvarchar(n),n 按字符数算,不是字节数。如果已经建了 varchar 列,改类型用 ALTER TABLE ... ALTER COLUMN,但要注意长度只能增大不能减小,且改类型前要确认没有索引依赖。

4.2 现象:删除列时报错“对象依赖于列”;原因:该列被约束、索引或默认值绑定;解决:先删约束再删列

笔记里明确写了“要删除商品数量,需要先删除商品的约束条件”。实际操作顺序是:先 ALTER TABLE ... DROP CONSTRAINT 约束名,再 ALTER TABLE ... DROP COLUMN 列名。如果列上还有索引,也要先 DROP INDEX。被复制列、用在索引中的列、有绑定默认值或规则的列,都不能直接删。

4.3 现象:视图更新失败;原因:视图定义里含聚合函数、DISTINCT、GROUP BY、UNION 或派生列;解决:改基表或重建可更新视图

笔记里列了更新视图必须满足的条件:From 子句至少引用一个表,选择列表没有派生列,没有聚合函数,不含 TOP、GROUP BY、UNION、DISTINCT。如果视图不满足这些条件,Update 语句会直接失败。排查方法是看视图定义,逐条对照这些限制。

4.4 现象:存储过程调用报参数数量不匹配;原因:按位置传参时漏传或顺序错;解决:改用按名称传参

笔记里说存储过程最多 1024 个参数,但没说调用时的传参方式。按位置传参时,参数顺序必须和定义完全一致,漏一个就报错。按名称传参用 @参数名 = 值 的形式,顺序可以打乱,可读性也更好。我一般写存储过程调用时强制用名称传参,尤其是参数超过三个的时候。

4.5 现象:游标循环结束后资源未释放;原因:只 Close 没 Deallocate;解决:Close 之后必须 Deallocate

笔记里的游标示例有 OPEN、FETCH、CLOSE、DEALLOCATE。Close 只是关闭游标,释放结果集;Deallocate 才是释放游标占用的资源。如果只 Close 不 Deallocate,游标定义还在,重复执行会报“游标已存在”。排查方法是查 sys.dm_exec_cursors 看当前会话的游标状态。

5. 从范式到模糊查询:把笔记里的零散知识点串成一条可复用的排查链

5.1 用范式检查表设计:第一范式到 BCNF 的落地判断

笔记里把第一范式、第二范式、第三范式、BCNF 都过了一遍。实际工作中不需要背定义,而是用它们当检查清单。第一范式:每一列不可再分,不能有组合列。第二范式:非主属性完全依赖码,不能只依赖联合主键的一部分。第三范式:不存在非主属性对码的传递依赖。BCNF:所有决定因素都包含码。下面这张表可以用来快速判断。

范式检查问题典型违规修正方式
1NF列是否可再分一列存多个商品类别拆列或拆行
2NF非主属性是否完全依赖码联合主键下部分依赖拆表,把部分依赖列移出
3NF是否存在传递依赖A→B→C,C 不依赖 A把 B、C 拆到独立表
BCNF所有决定因素是否包含码非码列决定码列进一步拆表

判断顺序是:先看列是否原子,再看主键和依赖关系,最后看传递依赖。笔记里用“商品编号、商品所属类别”的例子演示了第一范式的拆分,实际项目中遇到最多的是第二范式和第三范式问题,尤其是联合主键表里塞了不该塞的描述性字段。

5.2 模糊查询与数据导出:两个高频需求的写法

笔记最后提到模糊查询和数据导出。模糊查询用 LIKE 配合通配符,% 匹配任意字符,_ 匹配单个字符。如果关键字在列中间,用 %关键字%;如果只匹配开头,用 关键字%。下面这个查询把标题匹配关键字的排前面,不匹配但包含关键字的排后面,对应笔记里 union 的写法。

-- 标题以关键字开头的优先,其余包含关键字的排后 SELECT title, 1 AS rank_order FROM MyDB WHERE title LIKE '关键字%' UNION ALL SELECT title, 2 AS rank_order FROM MyDB WHERE title NOT LIKE '关键字%' AND CHARINDEX('关键字', title) > 0 ORDER BY rank_order, title;

逻辑说明:UNION ALL 不去重,比 UNION 快;rank_order 用来控制排序优先级;CHARINDEX 返回关键字在字符串中的位置,大于 0 表示包含。数据导出可以用 SQL Server 的导入导出向导,也可以用 SELECT ... INTO OUTFILE 的思路先查出来再走前台导出。笔记里说“可以通过前台来实现数据的导出”,实际就是应用层查数据后写文件,数据库层只负责查询。

5.3 权限管理与系统数据库:授权和角色别混着用

笔记里提到授权通过新建用户实现,Sp_addlogin、Sp_adduser、Sp_addrole 是三个不同层级的操作。登录名是服务器级,用户是数据库级,角色是权限集合。常见做法是:先建登录名,再映射到数据库用户,然后把用户加入角色,最后给角色授权。Grant 给权限,Revoke 回收权限。系统数据库里 Master 存登录账号和配置,Model 是新建数据库的模板,Tempdb 存临时表,Msdb 存调度作业和警报信息。Pubs 和 Northwind 是示例库,新版本里默认不一定装,需要单独附加。

从那以后我每次拿到一份数据库学习笔记,都会先挑一个最小场景把建库、建表、约束、视图、索引、存储过程、游标各跑一遍,跑不通的地方才是真正需要补的。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询