https://www.microsoft.com/zh-cn/evalcenter/download-sql-server-2022
🚩 在 SQL Server 中,数据库是由一系列对象的集合组成的。常见的数据库对象如下
SQL Server 数据库主要有文件和文件组组成,数据库中的所有数据和对象都被储存在文件中
🚩 数据库文件与文件组
SQL Server 的系统数据库是维持整个数据库实例正常运行和管理的关键组成部分。它们由系统自动创建和管理,包含了数据库管理系统(DBMS)运行所需的元数据、配置信息、历史记录等
SQL Server 主要包含以下 5 个核心系统数据库:
这是 SQL Server 实例的核心系统数据库,记录了实例的所有系统级信息。它包含了所有其他数据库的元数据 4)、登录账户和权限信息、系统级配置选项等
当 SQL Server 启动时,会首先加载 master 数据库,如果该数据库损坏或不可用,将导致 SQL Server 实例无法启动
用作在 SQL Server 实例上创建所有新数据库的模板。当执行 CREATE DATABASE 语句创建新数据库时,SQL Server 会复制 model 数据库的内容和配置 5)
来初始化新数据库
因此,对 model 数据库的任何修改都会影响以后创建的所有新数据库
这是 SQL Server 的管理数据库,主要由 SQL Server 代理使用。它用于存储和调度警报、自动化作业、备份和还原的历史记录、数据库维护计划以及数据库邮件等信息
这是一个全局的工作空间,用于保存临时对象 6)或中间结果集 7)
tempdb 在每次 SQL Server 实例启动时都会重新创建,并在实例关闭时永久删除其中的所有数据,以确保其始终处于干净可用的状态
这是一个只读隐藏的数据库,物理上包含了 SQL Server 附带的所有系统对象 8)
这些系统对象在物理上保留在 Resource 数据库中,但在逻辑上会显示在每个数据库的 sys 架构中。由于它是只读的,用户无法直接修改它
如果 SQL Server 实例配置了复制功能,还会存在一个 distribution 数据库,用于存储复制所需的元数据、历史记录和事务信息
create database 数据库名称;
USE master; -- 切换到系统数据库 master,因为创建新数据库必须在 master 库下执行 GO CREATE DATABASE Sales -- Sales:指定新数据库的名称(在实例中必须唯一) CONTAINMENT = NONE -- CONTAINMENT:指定数据库的包含状态。NONE表示非包含(默认),PARTIAL表示部分包含 ON PRIMARY -- ON:定义存储数据的文件组;PRIMARY:指定该文件组为主文件组(必须存在,通常存系统表) ( NAME = Sales_dat, -- NAME:数据文件的逻辑名称(在 SQL Server 内部引用时使用) FILENAME = 'C:\SQLData\saledat.mdf', -- FILENAME:物理路径和文件名(执行前文件夹必须已存在) SIZE = 10MB, -- SIZE:文件的初始大小(支持KB/MB/GB/TB,不指定则默认使用 model 库的大小) MAXSIZE = 50MB, -- MAXSIZE:文件允许增长到的最大大小(设为 UNLIMITED 表示直到磁盘满) FILEGROWTH = 5MB -- FILEGROWTH:自动增长的增量(可设为具体大小如5MB,或百分比如10%,设为0则关闭自动增长) ) LOG ON -- LOG ON:定义存储事务日志的文件(如果不写这句,系统会自动生成一个日志文件) ( NAME = Sales_log, -- NAME:日志文件的逻辑名称 FILENAME = 'C:\SQLData\salelog.ldf', -- FILENAME:日志文件的物理路径和文件名(通常以 .ldf 结尾) SIZE = 5MB, -- SIZE:日志文件的初始大小 MAXSIZE = 25MB, -- MAXSIZE:日志文件允许增长到的最大大小 FILEGROWTH = 5MB -- FILEGROWTH:日志文件的自动增长增量 ) COLLATE Chinese_PRC_CI_AS; -- COLLATE:指定数据库的排序规则(字符集和排序方式),不指定则使用实例默认规则 GO
USE master; -- 切换到系统数据库 master,修改数据库配置通常需要在此上下文中执行 GO -- ========================================== -- 1. 修改现有文件属性(例如:扩大初始大小、修改最大限制和增长步长) -- ========================================== ALTER DATABASE Sales -- 指定要修改的目标数据库名称 MODIFY FILE -- 关键字:表示接下来要修改文件的物理属性 ( NAME = Sales_dat, -- NAME:指定要修改的文件的逻辑名称(必须是已存在的文件) SIZE = 20MB, -- SIZE:将文件的初始大小强制修改为 20MB(注意:新大小不能小于当前实际已用大小) MAXSIZE = 100MB, -- MAXSIZE:将文件允许增长的最大上限修改为 100MB FILEGROWTH = 10MB -- FILEGROWTH:将自动增长的增量修改为 10MB(当文件写满时,每次自动增加10MB) ); GO -- ========================================== -- 2. 向现有的主文件组中添加一个新的数据文件 -- ========================================== ALTER DATABASE Sales -- 指定目标数据库 ADD FILE -- 关键字:表示要向数据库中添加新的数据文件 ( NAME = Sales_dat_2, -- NAME:新文件的逻辑名称 FILENAME = 'C:\SQLData\saledat2.ndf', -- FILENAME:新文件的物理路径(.ndf 是辅助数据文件的标准后缀) SIZE = 10MB, -- SIZE:新文件的初始大小 MAXSIZE = 50MB, -- MAXSIZE:新文件的最大大小限制 FILEGROWTH = 5MB -- FILEGROWTH:新文件的自动增长步长 ) TO FILEGROUP [PRIMARY]; -- TO FILEGROUP:指定将新文件添加到哪个文件组(这里是添加到默认的主文件组) GO -- ========================================== -- 3. 修改数据库级别的选项(例如:更改恢复模式、开启自动创建统计信息) -- ========================================== ALTER DATABASE Sales -- 指定目标数据库 SET -- 关键字:表示接下来要修改数据库的运行配置选项 RECOVERY FULL, -- RECOVERY:将数据库的恢复模式设置为“完整模式”(适合生产环境,支持时间点恢复) AUTO_CREATE_STATISTICS ON, -- AUTO_CREATE_STATISTICS:开启自动创建统计信息(让查询优化器自动收集数据分布,提升查询性能) AUTO_UPDATE_STATISTICS ON, -- AUTO_UPDATE_STATISTICS:开启自动更新统计信息(当数据发生大量增删改时,自动刷新统计信息) AUTO_SHRINK OFF; -- AUTO_SHRINK:关闭自动收缩(强烈建议设为OFF,因为自动收缩会导致严重的性能问题和碎片) GO
drop database 数据库名称; 11)
🚩 SQL Server 的基本数据类型主要包括用于存数值的数字类、存文本的字符串类、存日期的时间类、存文件的二进制类以及存标识符等其他类,详见如下表格
| 数据类型分类 | 数据类型 | 存储大小 | 取值范围 / 精度 | 适用场景 |
|---|---|---|---|---|
| 整数类型 | TINYINT | 1 字节 | 0到255 | 存储较小的非负整数(如年龄、状态码、枚举值) |
| SMALLINT | 2 字节 | -32,768 到 32,767 | 存储中等大小的整数,节省空间 | |
| INT | 4 字节 | -2^31 到 2^31-1 | 最常用的整数类型,适合绝大多数主键和计数 | |
| BIGINT | 8 字节 | -2^63 到 2^63-1 | 存储超大整数(如海量日志ID、跨系统唯一标识) | |
| 精确数值 | DECIMAL(p,s) | 5到 17 字节 | 取决于精度(p)和小数位数(s) | 财务、货币等对精度要求极高的数据(不会丢失精度) |
| NUMERIC(p,s) | 5到 17 字节 | 取决于精度(p)和小数位数(s) | 财务、货币等对精度要求极高的数据(不会丢失精度) | |
| 近似数值 | FLOAT(n) | 4 或 8 字节 | 约 15 位有效数字 | 科学计算、工程数据等允许微小误差的近似数值 |
| REAL | 4 字节 | 约 7 位有效数字 | 精度要求不高的浮点数,相当于 FLOAT(24) | |
| 日期和时间 | DATE | 3 字节 | 仅日期 (0001-01-01 到 9999-12-31) | 只需要记录年月日(如出生日期、入职日期) |
| TIME | 3 到 5 字节 | 仅时间 (精确到 100ns) | 只需要记录时分秒(如打卡时间、航班时刻) | |
| DATETIME2 | 6 到 8 字节 | 日期+时间 (精确到 100ns) | 微软推荐使用的日期时间类型,替代传统的 DATETIME | |
| DATETIMEOFFSET | 8 到 10 字节 | 日期+时间+时区偏移 | 跨国应用,需要明确记录时区信息的数据 | |
| 字符串类型 | CHAR(n) | n 字节 | 非 Unicode | 长度固定的纯英文/数字字符串(如身份证号、邮编) |
| VARCHAR(n) | 实际长度 + 2 字节 | 非 Unicode | 长度可变的纯英文/数字字符串,节省空间 | |
| NCHAR(n) | n × 2 字节 | Unicode | 长度固定的多语言字符串 | |
| NVARCHAR(n) | 实际长度 × 2 + 2 字节 | Unicode | 最常用的字符串类型,支持中文、Emoji等多语言 | |
| VARCHAR(MAX) | 实际长度 + 2 字节 | 非 Unicode | 存储超长文本(最多 2GB),如文章正文、JSON字符串 | |
| 其他常用类型 | BIT | 1 字节 | 取值只能是 0、1 或 NULL | 替代布尔值 (Boolean),表示是/否、开/关状态 |
| UNIQUEIDENTIFIER | 16 字节 | 全局唯一标识符 (GUID) | 分布式系统中生成绝对不重复的主键(由 NEWID() 生成) | |
| VARBINARY(MAX) | 实际长度 + 2 字节 | 二进制大对象 (BLOB) | 存储图片、文档、音视频等非结构化文件(或文件流) |
show tables; 12)
exec sp_tables
CREATE TABLE t_student ( 学号 INT ( 5 ), -- 5数字不需要写,会自动增长,无法限制长度 姓名 VARCHAR((mysql 命令)), -- 不固定的用varchar最大显示5个字符 性别 CHAR(1), -- 固定长度用char 身高 DECIMAL(3,2), -- 3表示一共显式3位数字,2表示小数位数 # 浮点行为FLOAT和DOUBLE,定点型只有DECIMAL。定点型在数据库中以字符串的形式存放,因此更为精确 入学时间 date -- date 日期 datetime 日期时间 );
-- 1. 切换上下文:建议在指定的数据库下创建表,避免建错位置 USE Sales; -- 切换到名为 Sales 的数据库 GO -- 2. 创建表的核心命令 CREATE TABLE Employees -- Employees:指定新表的名称(在当前数据库中必须唯一) ( -- ========================================== -- 字段定义区(列名 + 数据类型 + 约束) -- ========================================== EmployeeID INT IDENTITY(1,1) PRIMARY KEY, -- EmployeeID:列名(员工编号) -- INT:整数数据类型 -- IDENTITY(1,1):自增属性。从 1 开始,每次插入新记录自动加 1 -- PRIMARY KEY:主键约束。保证该列的值唯一且不能为 NULL,是表的唯一标识 EmployeeName NVARCHAR(50) NOT NULL, -- EmployeeName:列名(员工姓名) -- NVARCHAR(50):可变长度的 Unicode 字符串,最多存储 50 个字符(支持中文) -- NOT NULL:非空约束。插入数据时该列必须有值,不允许留空 Email VARCHAR(100) UNIQUE, -- Email:列名(电子邮箱) -- VARCHAR(100):可变长度的非 Unicode 字符串,最多 100 个字符 -- UNIQUE:唯一约束。保证所有员工的邮箱都不重复,但允许为 NULL HireDate DATE DEFAULT GETDATE(), -- HireDate:列名(入职日期) -- DATE:仅存储日期(年-月-日),不包含时间 -- DEFAULT GETDATE():默认值约束。如果不手动指定日期,系统会自动填入当前日期 Salary DECIMAL(10,2) CHECK (Salary >= 0), -- Salary:列名(薪水) -- DECIMAL(10,2):精确数值类型。总共 10 位数字,其中小数点后占 2 位(如 99999999.99) -- CHECK (Salary >= 0):检查约束。限制插入或更新的薪水必须大于等于 0 DepartmentID INT NULL, -- DepartmentID:列名(部门编号) -- NULL:显式声明该列允许为空(如果不写,默认也是允许为空的) -- ========================================== -- 表级约束区(跨列约束) -- ========================================== CONSTRAINT FK_Emp_Dept FOREIGN KEY (DepartmentID) REFERENCES Departments(DeptID) -- CONSTRAINT FK_Emp_Dept:为这个约束起一个自定义名称(方便日后维护或删除) -- FOREIGN KEY (DepartmentID):外键约束。将当前表的 DepartmentID 列设为外键 -- REFERENCES Departments(DeptID):引用(关联)到 Departments 表的 DeptID 列 ); GO
-- 1. 切换上下文:建议在指定的数据库下操作,避免改错表 USE Sales; -- 切换到名为 Sales 的数据库 GO -- ========================================== -- 1. 添加新列 (ADD) -- ========================================== ALTER TABLE Employees -- 指定要修改的目标表 ADD PhoneNumber VARCHAR(20) NULL, -- 添加一个允许为空的手机号列 IsActive BIT DEFAULT 1; -- 添加一个状态列,默认值为 1(代表在职) GO -- ========================================== -- 2. 修改现有列的属性 (ALTER COLUMN) -- ========================================== ALTER TABLE Employees -- 指定目标表 ALTER COLUMN Email NVARCHAR(200) NOT NULL; -- 将 Email 列的数据类型扩大为 NVARCHAR(200),并修改为不允许为空 -- ⚠️ 注意:如果表中已有数据,且该列存在 NULL 值,执行 NOT NULL 会报错。需先清理数据。 GO -- ========================================== -- 3. 删除现有列 (DROP COLUMN) -- ========================================== ALTER TABLE Employees -- 指定目标表 DROP COLUMN PhoneNumber; -- 彻底删除 PhoneNumber 这一列及其所有数据 GO -- ========================================== -- 4. 添加表级约束 (ADD CONSTRAINT) -- ========================================== ALTER TABLE Employees -- 指定目标表 ADD -- 添加唯一约束:保证身份证号不重复 CONSTRAINT UQ_Emp_IDCard UNIQUE (IDCardNumber), -- 添加检查约束:限制年龄必须在 18 到 65 之间 CONSTRAINT CK_Emp_Age CHECK (Age >= 18 AND Age <= 65); GO -- ========================================== -- 5. 删除表级约束 (DROP CONSTRAINT) -- ========================================== ALTER TABLE Employees -- 指定目标表 DROP CONSTRAINT CK_Emp_Age; -- 删除名为 CK_Emp_Age 的检查约束 GO -- ========================================== -- 6. 重命名表 (系统存储过程) -- ========================================== -- ⚠️ 注意:重命名表不是用 ALTER TABLE,而是调用系统内置的存储过程 sp_rename EXEC sp_rename 'Employees', -- 参数1:原表名 'Staff'; -- 参数2:新表名 GO
insert into 表名(字段名1,字段名2....) values ('字段值1','字段值2',...),('字段值1','字段值2',...), ... ; 18)
insert into 表名 values ('字段值1','字段值2',...),('字段值1','字段值2',...), ... ; 19)
delete from 表名 where 条件 20)
update 表名 set 字段名1 = '更新值1',字段名2 = '更新值2',... where 条件 21)
select * from 表名
create table 表格名称( 字段1 数据类型 primary key, --主键约束 字段2 数据类型 not null, --非空约束 字段3 数据类型 check(字段条件), --检查约束 字段4 数据类型 default '默认值', --默认约束 字段5 数据类型 unique, --唯一约束 foreign key(外键字段) references 表格名称2(主键字段) --外键约束 )
🚩 以学生信息为例,创建约束
CREATE TABLE t_student ( 学号 INT PRIMARY KEY auto_increment, -- 主键约束自带非空唯一, auto_increment代表自增 姓名 VARCHAR(5) NOT NULL, -- 非空约束 性别 CHAR(1) DEFAULT '男' CHECK(性别 = '男' || 性别 = '女'), -- 默认和检查约束 身高 DECIMAL(3,2) CHECK(身高 >= 1.50 AND 身高 <= 2.00), -- 检查约束 手机号 INT UNIQUE -- 唯一约束 );
学生信息加别名
CREATE TABLE t_student ( 学号 INT auto_increment, 姓名 VARCHAR(5) NOT NULL, 性别 CHAR(1) DEFAULT '男', 身高 DECIMAL(3,2), 手机号 INT, CONSTRAINT pk_stu PRIMARY KEY(学号), CONSTRAINT ck_stu_sex CHECK(性别 = '男' || 性别 = '女'), CONSTRAINT ck_stu_high CHECK(身高 >= 1.50 AND 身高 <= 2.00), CONSTRAINT uq_stu_phone UNIQUE(手机号), CONSTRAINT wj_1 foreign key(学号) references t_class(班号) -- 学号可以不为主键,但班号必须主键 -- foreign key 为创建表的键外键,t_class代表第二张表有主键为班号的字段,外键的值主键里必须有 );
alter table 表名称 modify 字段 数据类型 约束条件; --约束条件:primary key auto_increment ,not null,default,unique等都支持 alter table 表名称 add 约束条件 约束名称(需约束的字段); --支持 primary key 和 unique 等 ,其他约束条件基本不支持,,主键无需约束名 alter table 表名称 add constraint 约束名称 约束条件(需约束的字段); --约束条件: auto_increment,not null,default,等不支持,check条件自带字段,无需加约束字段,,约束名称可省略 alter table 表名称 alter column 字段 数据类型 约束条件; alter table 表名称 add constraint 约束名称 约束条件(字段); --约束名称可省略,check条件自带字段,无需加约束字段 alter table 表名称 add constraint 约束名称 default '默认值' for 字段; --起名可省略, auto_increment,not null等可能支持 alter table 表名称 add constraint 约束名称 foreign key(外键字段) references 表格名称2(主键字段); alter table 表名称 add constraint 约束名称 foreign key(外键字段) references 表格2(主键字段) on update cascade on delete cascade; -- cascade 操作主键表的时候会影响从表的外键信息,意思是主键表值改变了,外键值会自动更新 alter table 表名称 add constraint 约束名称 foreign key(外键字段) references 表格2(主键字段)on update set null on delete set null; -- set null 操作主键表的时候会影响从表的外键信息,意思是主键表值改变了,外键值会设为null
alter table 表名称 modify 字段 数据类型 null; -- mysql 命令 ,null可扩其他约束条件如:default等 alter table 表名称 alter column 字段 数据类型 null; -- sql server命令 null可扩其他约束条件如:default等 alter table 表名称 drop 约束条件; alter table 表名称 drop constraint 约束名; alter table 外键表名称 drop constraint 外键约束名;
表 A 中的一条记录,在表 B 中只能对应唯一的一条记录;反之亦然
当一张表字段过多时,将不常用的字段(如用户简历、身份证号)拆分到另一张表,以提高主表的查询性能
在 SQL Server 中,通常通过外键约束 + 唯一约束(Unique Constraint)来实现
-- 示例:用户表与用户详情表 CREATE TABLE Users ( UserId INT PRIMARY KEY IDENTITY, UserName NVARCHAR(50) ); CREATE TABLE UserDetails ( DetailId INT PRIMARY KEY IDENTITY, UserId INT UNIQUE, -- 关键:添加唯一约束,确保一个UserId只能出现一次 Bio NVARCHAR(MAX), FOREIGN KEY (UserId) REFERENCES Users(UserId) );
表 A 中的一条记录,在表 B 中可以有零条、一条或多条记录;但表 B 中的一条记录在表 A 中只能对应唯一的一条记录
一个部门有多个员工、一个作者写了多本书、一个客户有多个订单
在“多”的一方(从表)中创建外键,指向“一”的一方(主表)的主键。不需要在外键上添加唯一约束
-- 示例:部门与员工 CREATE TABLE Departments ( DeptId INT PRIMARY KEY IDENTITY, DeptName NVARCHAR(50) ); CREATE TABLE Employees ( EmpId INT PRIMARY KEY IDENTITY, EmpName NVARCHAR(50), DeptId INT, -- 外键放在“多”的一方 FOREIGN KEY (DeptId) REFERENCES Departments(DeptId) );
表 A 中的一条记录,在表 B 中可以有零条、一条或多条记录;同时表 B 中的一条记录,在表 A 中也可以有零条、一条或多条记录
学生与课程:一个学生选多门课,一门课被多个学生选
关系型数据库不能直接建立多对多关系。必须引入第三张表,称为关联表(Junction Table / Bridge Table)
-- 示例:学生与课程 CREATE TABLE Students ( StudentId INT PRIMARY KEY IDENTITY, StudentName NVARCHAR(50) ); CREATE TABLE Courses ( CourseId INT PRIMARY KEY IDENTITY, CourseName NVARCHAR(50) ); -- 关联表 CREATE TABLE StudentCourses ( StudentId INT NOT NULL, CourseId INT NOT NULL, EnrollmentDate DATE, -- 关联表还可以包含关系本身的属性(如选课时间) PRIMARY KEY (StudentId, CourseId), -- 联合主键 FOREIGN KEY (StudentId) REFERENCES Students(StudentId), FOREIGN KEY (CourseId) REFERENCES Courses(CourseId) );