目录

SQL 语言

SQL 基础

SQL 1)是用于管理关系数据库管理系统(RDBMS)的标准编程语言, 用来存储、查询、更新和管理数据,根据操作目的,SQL 语句通常分为以下四类

分类 全称 作用 常见关键字
DQL Data Query Language 数据查询:从数据库中检索数据 SELECT, FROM, WHERE, JOIN, GROUP BY
DML Data Manipulation Language 数据操作:对表中的数据进行增删改 INSERT, UPDATE, DELETE
DDL Data Definition Language 数据定义:定义或修改数据库结构(表、索引等) CREATE, ALTER, DROP, TRUNCATE
DCL Data Control Language 数据控制:管理权限和事务 GRANT, REVOKE, COMMIT, ROLLBACK

SQL 执行逻辑顺序

常量

数字常量

数字常量包括整数、小数以及浮点数 2)

字符串常量

字符串常量括在单引号内,包含字母和数字字符以及特殊字符,如 !,@,#,如果单引号的字符串包含一个嵌入的引号,可以使用两个的单引号表示嵌入的单引号

🚩 假设你要插入一条包含 It's 的数据: INSERT INTO messages (content) VALUES ('It''s a test');

日期和时间常量

在标准的 SQL 语法中,日期和时间常量通常遵循以下格式:

符号常量

类别 符号常量 (标准 SQL) 含义与说明 常见数据库方言/替代写法
空值与逻辑 NULL 数据缺失、未知,不可用 = 比较,必须用 IS NULL 通用
空值与逻辑 TRUE 布尔真值 MySQL 旧版视为 1;Oracle 无原生布尔,常用 1 或 'Y'
空值与逻辑 FALSE 布尔假值 MySQL 旧版视为 0;Oracle 常用 0 或 'N'
日期与时间 CURRENT_DATE 当前系统日期 (无时间部分) Oracle: TRUNC(SYSDATE)
日期与时间 CURRENT_DATE 当前系统日期 (无时间部分) MySQL: CURDATE()
日期与时间 CURRENT_DATE 当前系统日期 (无时间部分) SQL Server: CAST(GETDATE() AS DATE)
日期与时间 CURRENT_TIME 当前系统时间 (无日期部分,含时区) Oracle: 无直接对应,需 TO_CHAR(SYSDATE, 'HH24:MI:SS')
日期与时间 CURRENT_TIME 当前系统时间 (无日期部分,含时区) MySQL: CURTIME()
日期与时间 CURRENT_TIMESTAMP 当前完整日期和时间 (含时区) Oracle: SYSTIMESTAMP
日期与时间 CURRENT_TIMESTAMP 当前完整日期和时间 (含时区) MySQL: NOW()
日期与时间 CURRENT_TIMESTAMP 当前完整日期和时间 (含时区) SQL Server: SYSDATETIME()
日期与时间 LOCALTIMESTAMP 当前本地日期和时间 (不含时区) Oracle: SYSDATE
日期与时间 LOCALTIMESTAMP 当前本地日期和时间 (不含时区) MySQL: NOW()
日期与时间 LOCALTIMESTAMP 当前本地日期和时间 (不含时区) SQL Server: GETDATE()
用户与环境 CURRENT_USER 当前会话的数据库用户名 Oracle: USER
用户与环境 CURRENT_USER 当前会话的数据库用户名 MySQL: USER()
用户与环境 CURRENT_USER 当前会话的数据库用户名 SQL Server: SUSER_SNAME()
用户与环境 SESSION_USER 会话初始连接用户 (通常与 CURRENT_USER 相同) SQL Server: ORIGINAL_LOGIN()
用户与环境 SYSTEM_USER 底层操作系统用户名 SQL Server: SYSTEM_USER
用户与环境 SYSTEM_USER 底层操作系统用户名 Oracle/MySQL: 无直接标准对应
用户与环境 CURRENT_SCHEMA 当前默认的 Schema/数据库名 MySQL: DATABASE()
用户与环境 CURRENT_SCHEMA 当前默认的 Schema/数据库名 SQL Server: SCHEMA_NAME()
系统状态 UNKNOWN 三值逻辑中的“未知”状态 (NULL 参与比较时产生) 极少直接使用,通常由 NULL 比较自动产生

变量

在 SQL 中,变量用于在批处理、脚本或存储过程中临时存储数据值,是控制程序逻辑(如循环、条件判断)和处理中间结果的重要工具

局部变量

在 SQL 中,局部变量和全局变量的核心区别在于作用域(可见范围)和生命周期,局部变量是由用户自己定义的,用于在特定的代码块或事务中临时存储数据

全局变量

在 SQL Server 中,我们通常所说的“全局变量”实际上是由系统预定义和维护的系统函数。它们主要用于提供有关 SQL Server 系统配置、当前会话状态或上一条 SQL 语句执行结果的信息

🚩以下是整理好的 SQL Server 常用全局变量表格

分类 全局变量 (系统函数) 含义与说明
系统与配置 @@VERSION 返回当前 SQL Server 的版本、处理器架构和操作系统信息
系统与配置 @@SERVERNAME 返回运行 SQL Server 的本地服务器名称
系统与配置 @@LANGUAGE 返回当前使用的语言名称
系统与配置 @@MAX_CONNECTIONS 返回 SQL Server 实例允许同时进行的最大用户连接数
语句执行状态 @@ROWCOUNT 返回受上一条 SQL 语句影响的行数(常用于判断操作是否成功)
语句执行状态 @@ERROR 返回最后执行的 T-SQL 语句的错误号(成功返回 0,失败返回错误代码)
语句执行状态 @@IDENTITY 返回当前会话中最后一次插入的标识值(自增 ID)
事务与连接 @@TRANCOUNT 返回当前连接(会话)中打开的活动事务数
事务与连接 @@SPID 返回当前用户进程的服务器进程 ID
性能与统计 @@CONNECTIONS 返回自 SQL Server 上次启动以来的登录或尝试登录的次数
性能与统计 @@CPU_BUSY 返回自 SQL Server 上次启动以来,CPU 用于执行 SQL Server 工作的微秒数
性能与统计 @@IDLE 返回自 SQL Server 上次启动以来,SQL Server 处于空闲状态的微秒数
性能与统计 @@TOTAL_READ 返回 SQL Server 执行的磁盘读取次数
性能与统计 @@TOTAL_WRITE 返回 SQL Server 执行的磁盘写入次数

注释符、运算符与通配符

注释符

:TIP 不同数据库的特殊注释语法:MySQL:支持 # 作为单行注释

算术运算符

说 明

当两个整数相除,SQL Server和 MySQL 默认会执行整数除法,结果会截断小数部分

🚩 SELECT 7 / 2;结果:3 (而不是 3.5)

解决办法:将其中一个数转换为浮点数,如 SELECT 7.0 / 2; 或 SELECT CAST(7 AS DECIMAL)/2;

任何数与 NULL 运算,结果都是 NULL

运算符 含义 示例 结果
+ 加法 SELECT 10 + 5; 15
- 减法 SELECT 10 - 5; 5
* 乘法 SELECT 10 * 5; 50
/ 除法 SELECT 10 / 5; 2
% 取模(求余数) SELECT 10 % 3; 1

赋值运算符

在 SQL Server 中,赋值主要通过 SET 或 SELECT 语句结合 = 号来实现

DECLARE @myVar INT; SET @myVar = 10; -- 使用 = 将 10 赋给 @myVar

从 SQL Server 2008 开始,引入了复合赋值运算符3)

SET @myVar += 5; 等价于 SET @myVar = @myVar + 5;

:TIP 在 SQL Server 中,= 就是赋值;在 MySQL 的 SELECT 语句中,必须用 := 来赋值,= 只用来做比较

比较运算符

运算符 含义 示例 说明
= 等于 WHERE age = 18 判断两个表达式是否相等
<> 或 != 不等于 WHERE status != 'Active' <> 是 ISO 标准,!= 也是广泛支持的非标准写法
> 大于 WHERE price > 100 判断左侧表达式是否大于右侧
< 小于 WHERE age < 60 判断左侧表达式是否小于右侧
>= 大于或等于 WHERE score >= 90 判断左侧表达式是否大于或等于右侧
小于或等于 WHERE age ⇐ 18 判断左侧表达式是否小于或等于右侧
BETWEEN … AND … 范围查询 WHERE price BETWEEN 10 AND 20 包含边界值,等价于 >= 10 AND ⇐ 20
IN (…) 列表匹配 WHERE status IN ('Active', 'Pending') 判断值是否在给定的列表中(多选一)
LIKE 模糊匹配 WHERE name LIKE '%张%' % 代表任意长度字符,_ 代表单个字符
IS NULL 判断为空 WHERE email IS NULL 判断字段是否为空值(不可用 = NULL)
IS NOT NULL 判断非空 WHERE phone IS NOT NULL 判断字段是否不为空值(不可用 != NULL)

逻辑运算符

运算符 含义 示例 说明
AND 逻辑与 WHERE age > 18 AND status = 'Active' 两个条件都为 TRUE 时,结果才为 TRUE
OR 逻辑或 WHERE city = 'Beijing' OR city = 'Shanghai' 只要有一个条件为 TRUE,结果即为 TRUE
NOT 逻辑非 WHERE NOT status = 'Inactive' 对条件结果取反,TRUE 变 FALSE,FALSE 变 TRUE
&& 逻辑与 (非标准) WHERE age > 18 && status = 'Active' 部分数据库支持,建议优先使用 AND
|| 逻辑或 (非标准) WHERE city = 'Beijing' || city = 'Shanghai' 部分数据库支持,建议优先使用 OR
! 逻辑非 (非标准) WHERE !status = 'Inactive' 部分数据库支持,建议优先使用 NOT

连接运算符

连接运算符 + 主要用于将两个或多个数据项(如字符串、变量、表达式或常量)合并为一个整体,其核心作用是在数据处理和输出格式化中实现内容的无缝拼接

运算符优先级

关键字 核心作用 常用场景与示例
ALL 必须满足子查询返回的所有条件 WHERE Salary > ALL (SELECT Salary FROM SalesDept)
SOME 满足子查询返回的任意一个条件即可(与 ANY 等价) WHERE Salary > SOME (SELECT Salary FROM SalesDept)
ANY 满足子查询返回的任意一个条件即可(与 SOME 等价) WHERE Salary > ANY (SELECT Salary FROM SalesDept)
EXISTS 检查子查询是否至少有一行结果(返回 TRUE/FALSE) WHERE EXISTS (SELECT 1 FROM Orders WHERE CustomerID = c.ID)
AS 起别名、定义查询结构或指定转换类型 SELECT Name AS 姓名、WITH CTE AS (…)、CAST(123 AS VARCHAR)

通配符

通配符 含义 示例 说明
% 代表任意长度的任意字符 WHERE name LIKE '%张%' 匹配包含“张”的任意字符串,如“张三”、“小张”、“老张”
_ 代表任意单个字符 WHERE name LIKE '_三' 匹配以任意单个字符开头且以“三”结尾的名字,如“张三”、“李三”
[] 字符列表中的任一单个字符 WHERE name LIKE '[张李王]三' 匹配“张三”、“李三”或“王三”(SQL Server 支持)
[^] 不在字符列表中的任一单个字符 WHERE name LIKE '[^张李]三' 匹配不以“张”或“李”开头且以“三”结尾的名字(SQL Server 支持)
[-] 字符范围内的任一单个字符 WHERE code LIKE '[A-C]001' 匹配“A001”、“B001”或“C001”(SQL Server 支持)

流程控制

BEGIN...END

BEGIN…END 是流程控制语言的关键字,主要用于将多条 SQL 语句组合为一个逻辑代码块,它的作用类似于 C、Java 等编程语言中的大括号 {}

IF (@@ERROR <> 0)
BEGIN
    SET @ErrorSaveVariable = @@ERROR;
    PRINT 'Error encountered, ' + CAST(@ErrorSaveVariable AS VARCHAR(10));
END
-- 如果不加 BEGIN...END,当 @@ERROR <> 0 时,只有 SET 语句会被执行,而 PRINT 语句无论条件是否成立都会执行

IF

IF<条件表达式>
  {命令行|程序块}

IF...ELSE

IF<条件表达式>
   {命令行1|程序块1}
 
ELSE
   {命令行2|程序块2}

CASE

在 SQL 中,CASE 表达式用于实现条件逻辑,它允许你根据不同的条件返回不同的值。你可以把它理解为 SQL 中的 IF…ELSE IF…ELSE 逻辑

CASE input_expression
    WHEN when_expression_1 THEN result_1
    WHEN when_expression_2 THEN result_2
    ...
    [ELSE else_result]
END

🚩

SELECT ProductName,
       CASE CategoryID
           WHEN 1 THEN '电子产品'
           WHEN 2 THEN '服装'
           WHEN 3 THEN '食品'
           ELSE '其他类别'
       END AS CategoryName
FROM Products;

用于评估多个布尔表达式,返回第一个计算结果为 TRUE 的对应值。它比简单 CASE 更灵活,支持范围判断和复杂的逻辑条件

CASE
    WHEN boolean_condition_1 THEN result_1
    WHEN boolean_condition_2 THEN result_2
    ...
    [ELSE else_result]
END

🚩

SELECT ProductName, Price,
       CASE
           WHEN Price > 1000 THEN '昂贵'
           WHEN Price BETWEEN 100 AND 1000 THEN '适中'
           WHEN Price < 100 THEN '便宜'
           ELSE '未定价'
       END AS PriceLevel
FROM Products;

说 明

END 在这里的作用不是结束一个代码块,而是结束这个表达式

IF...ELSE 是控制流语句,它需要 BEGIN...END 来划定一个代码块,告诉数据库引擎:“请把这一大堆语句当成一个整体来执行”

CASE 是一个表达式(Expression):它的作用是“计算并返回一个值”。就像 1 + 2 返回 3

为什么不需要 BEGIN? 因为 CASE 表达式内部不允许包含多条独立的 SQL 语句

WHILE

WHILE<条件表达式>
BEGIN
     <命令行|程序块>
END

WHILE...CONTINUE...BREAK

WHILE<条件表达式>
BEGIN
     <命令行|程序块>
     [BREAK]
     [CONTINUE]
     [命令行|程序块]
END

RETURN

在 SQL 中,RETURN 是一个非常关键的控制流关键字,它的主要作用是无条件地立即终止当前的执行流程,并退出当前的程序单元

状态码 官方建议含义 状态码 官方建议含义
-1 找不到对象或权限不足 -2 发生语法错误
-3 超时(Timeout) -4 违反权限规则
-5 发生死锁(Deadlock) -6 发生致命错误
-7 发生数据类型转换错误 -8 字符串被截断
-9 无效的列名 -10 无效的表名
-11 无效的数据库名 -12 无效的参数
-13 违反约束 -14 违反触发器
-99 到 -999 系统保留的错误代码范围 F 程序执行成功

GOTO

在 SQL Server 中,GOTO 是一种流程控制语句,它的主要作用是改变代码的执行顺序,使程序无条件跳转到指定的“标签(Label)”处继续执行

-- 1. 定义标签(标签名后必须加冒号)
label_name:
 
-- 2. 改变执行流程(跳转到指定标签)
GOTO label_name;

WAITFOR

WAITFOR 是 SQL Server中用于控制执行流程的命令。它的主要作用是暂停或延迟批处理、存储过程或事务的执行,直到指定的时间间隔过去,或者到达某个特定的时间点

下面的代码会让程序暂停 10 秒钟后再执行程序

WAITFOR DELAY '00:00:10';

下面的代码会让程序一直等待,直到晚上 10 点 20 分才开始执行程序

WAITFOR TIME '22:20';

常用命令

DBCC

DBCC(Database Console Commands,数据库控制台命令)是 SQL Server 中一组非常强大的系统级指令,它主要用于数据库的维护、验证、信息收集等任务。

🚩 为了让你更直观地了解 DBCC 的常用功能,这里列举几个最核心的命令

命令名称 主要功能
DBCC CHECKDB 检查指定数据库中所有对象的分配和结构完整性,是最常用的诊断命令
DBCC SHRINKDATABASE 尝试收缩指定数据库的所有数据和日志文件的大小
DBCC SHRINKFILE 收缩当前数据库中指定数据或日志文件的大小
DBCC TRACEON 启用指定的跟踪标志,常用于开启死锁诊断或改变查询优化器行为
DBCC HELP 显示指定 DBCC 语句的语法帮助信息

CHECKPOINT

在 SQL Server 中,CHECKPOINT 是一个至关重要的机制,它的主要作用是将内存中已修改但尚未写入磁盘的数据页 4)强制刷新到磁盘,并在事务日志中记录

简单来说,它的核心目的有两个:

  1. 缩短崩溃恢复时间: 当数据库意外崩溃或重启时,SQL Server 只需要从最近一次 CHECKPOINT 之后的日志开始重做(Redo)操作,而不需要重做所有的历史日志
  2. 提升性能:将多次内存修改合并为一次磁盘写入,减少了频繁的磁盘 I/O 操作

DECLARE

在 SQL Server 中,DECLARE 是用来定义(声明)局部变量或表变量的关键字

基本语法: DECLARE @变量名 数据类型;

🚩 常用示例

-- 1. 声明一个整数变量
DECLARE @EmployeeID INT;
 
-- 2. 声明一个字符串变量(指定最大长度)
DECLARE @EmployeeName NVARCHAR(50);
 
-- 3. 声明的同时直接赋值
DECLARE @CurrentDate DATE = GETDATE();
 
-- 4. 声明多个变量(用逗号隔开)
DECLARE @Age INT = 25, @Salary DECIMAL(10,2) = 5000.00;

基本语法: DECLARE @表变量名 TABLE ( 列名1 数据类型,列名2 数据类型,...);

🚩 实例

-- 声明一个表变量,用来暂存部门信息
DECLARE @TempDepartments TABLE (
    DeptID INT PRIMARY KEY,
    DeptName NVARCHAR(50)
);
 
-- 往表变量里插入数据
INSERT INTO @TempDepartments (DeptID, DeptName)
VALUES (1, 'IT部'), (2, '人事部');
 
-- 像查询普通表一样查询它
SELECT * FROM @TempDepartments WHERE DeptID = 1;

PRINT

在 SQL Server 中,PRINT 是一个非常基础且常用的命令,主要用于向客户端输出文本消息

基本语法: PRINT '要输出的文本内容'; 或者 PRINT @变量名;

RAISERROR

在 SQL Server 中,RAISERROR 是一个用于主动抛出自定义错误或警告信息的强大命令

基本语法: RAISERROR ( '错误消息文本' , 严重级别 , 状态 )

READTEXT

在 SQL Server 中,READTEXT 是一个专门用于从 text、ntext 或 image 数据类型的列中,读取部分或全部数据的命令

它允许你指定从哪个位置(偏移量)开始读取,以及读取多少个字节或字符

基本语法: READTEXT { table.column text_ptr offset size } [ HOLDLOCK ]

说 明

table.column:指定要读取的表名和列名

text_ptr:一个有效的文本指针(必须是 binary(16) 类型),通常需要通过 TEXTPTR() 函数获取

offset:开始读取前的偏移量(跳过的字节数或字符数)

size:要读取的字节数或字符数,如果设置为 0,则默认读取 4KB 的数据

HOLDLOCK(可选):加上此选项会在事务结束前锁定该文本值,防止其他用户修改

:TIP READTEXT 是一个即将被废弃的功能,在新的开发工作中避免使用它,并着手将现有应用中的 READTEXT 替换为更现代的 SUBSTRING 函数

BACKUP

在 SQL Server 中,BACKUP 是数据库管理员(DBA)工具,它的主要作用是为数据库、事务日志或文件创建一个安全副本,以便在发生数据损坏、误操作或硬件故障时进行恢复

SQL Server 支持三种不同维度的备份策略,通常会组合使用

  1. 完整备份 (Full Backup)
    1. 作用:备份整个数据库的所有数据,这是所有其他备份的基础
    2. 特点:恢复时只需要这一个文件,但备份过程耗时最长,占用空间最大
  2. 差异备份 (Differential Backup)
    1. 作用:只备份自上一次完整备份以来发生更改的数据
    2. 备份速度快,占用空间小,随着时间推移,差异备份的文件会越来越大,直到下一次完整备份将其“清零”
  3. 事务日志备份 (Transaction Log Backup)
    1. 作用:备份自上一次日志备份以来的所有事务日志记录
    2. 前提:数据库必须处于完整恢复模式 (Full Recovery Model)
    3. 特点:可以实现“时间点恢复”(比如精确恢复到误删数据的前一秒),并且能防止事务日志文件无限膨胀

🚩常用语法与示例

-- 将 MyDatabase 完整备份到指定的磁盘文件
BACKUP DATABASE [MyDatabase] 
TO DISK = 'D:\Backup\MyDatabase_Full.bak'
WITH FORMAT, -- 覆盖媒体集,开始新的备份集
     COMPRESSION, -- 启用备份压缩,节省磁盘空间
     STATS = 10; -- 每完成 10% 在消息栏输出一次进度
BACKUP DATABASE [MyDatabase] 
TO DISK = 'D:\Backup\MyDatabase_Diff.bak'
WITH DIFFERENTIAL, -- 关键参数:指定为差异备份
     COMPRESSION,
     STATS = 10;
BACKUP LOG [MyDatabase] -- 注意这里是 BACKUP LOG
TO DISK = 'D:\Backup\MyDatabase_Log.trn'
WITH COMPRESSION,
     STATS = 10;

RESTORE

在 SQL Server 中,RESTORE 命令它的主要作用就是从备份文件(.bak 或 .trn)中读取数据,并将数据库恢复到指定的状态

简单来说,BACKUP 负责“存档”,而 RESTORE 负责“读档,RESTORE 命令非常灵活,根据不同的需求,主要有以下几种用法

-- 从磁盘文件还原整个数据库
RESTORE DATABASE [MyDatabase] 
FROM DISK = 'D:\Backup\MyDatabase_Full.bak'
WITH RECOVERY; -- 默认就是 RECOVERY,让数据库立即可用
--还原事务日志备份
RESTORE LOG [MyDatabase] 
FROM DISK = 'D:\Backup\MyDatabase_Log.trn'
WITH RECOVERY;

SELECT

在 SQL Server 中,SELECT 不仅仅是用来“查”数据的,它还是给变量赋值、甚至快速创建表的主力军

DECLARE @Name NVARCHAR(50), @Age INT;
-- 一条语句搞定两个变量的赋值
SELECT @Name = 'Admin', @Age = 25; 
 
-- SELECT 从查询中赋值
DECLARE @EmployeeName NVARCHAR(50);
-- 将查询到的第一行数据的 Name 列的值赋给变量
SELECT @EmployeeName = Name FROM Employees WHERE ID = 1;

SET

在 SQL Server 中,SET 是一个极其重要的关键字,它主要有两大核心身份:一是作为给变量赋值的专用命令,二是作为修改当前会话环境的配置开关

基本语法: SET @变量名 = 值;

🚩 实例

DECLARE @Name NVARCHAR(50);
DECLARE @Count INT;
 
-- 给字符串变量赋值
SET @Name = 'Admin';
 
-- 给数字变量赋值
SET @Count = 100;
 
-- 支持复合赋值运算符(类似 C# 或 Java)
SET @Count += 10; -- 等同于 @Count = @Count + 10

除了赋值,SET 还能用来控制当前数据库连接(会话)的各种行为,这些设置会影响后续 SQL 语句的执行方式

🚩 常用场景示例

SET NOCOUNT ON : 默认情况下,每次执行 INSERT、UPDATE 或 DELETE 后,SQL Server 都会返回一条类似“(1 行受影响)”的消息,加上这句可以屏蔽这些消息,显著提升性能

SET IDENTITY_INSERT ON : 当表的主键是自动增长的(Identity)时,默认是不允许手动插入 ID 的,用这个命令可以临时开启手动插入权限

SET STATISTICS IO ON / TIME ON : 在调优 SQL 语句时非常有用,它会输出查询消耗了多少次磁盘读取以及执行耗时

SET DATEFIRST : 控制 DATEPART 函数中“星期几”的计算起点 6)

SHUTDOWN

在 SQL Server 中,SHUTDOWN 是一个用于立即停止 SQL Server 数据库引擎服务的 Transact-SQL 命令

基本语法: SHUTDOWN [ WITH NOWAIT ]

WRITETEXT

在 SQL Server 中,WRITETEXT 是一个专门用于对 text、ntext 或 image 数据类型的列进行交互式更新的命令,它的核心作用是完全覆盖目标列中现有的所有数据

和 READTEXT 一样,WRITETEXT 也是一个即将被废弃的功能,微软官方明确建议,在新的开发工作中避免使用它

并推荐改用大值数据类型(如 VARCHAR(MAX))配合 UPDATE 语句的 .WRITE 子句

USE

在 SQL Server 中,USE 是一个非常基础且高频使用的命令,它的主要作用是切换当前会话的数据库上下文

基本语法: USE 数据库名;

SQL 函数

聚合函数

在 SQL Server 中,聚合函数是对一组值执行计算并返回单个值的函数,通常与 GROUP BY 子句配合使用,用于对数据进行分组汇总

COUNT:统计数量

🚩 假设我们有一张 Employees(员工表),包含 Department(部门)、Salary(薪资)和 Age(年龄)等字段

-- 统计公司总人数
SELECT COUNT(*) AS TotalEmployees FROM Employees;
 
-- 统计“销售部”的人数
SELECT COUNT(*) FROM Employees WHERE Department = '销售部';
 
-- 注意:COUNT(列名) 会忽略该列值为 NULL 的行
SELECT COUNT(Salary) FROM Employees; 

SUM:求和

计算全公司的薪资总支出: SELECT SUM(Salary) AS TotalSalary FROM Employees;

AVG:求平均值

计算全公司的平均年龄: SELECT AVG(Age) AS AverageAge FROM Employees;

MAX 和 MIN:找极值

找出公司里的最高薪资和最低薪资: SELECT MAX(Salary) AS HighestSalary, MIN(Salary) AS LowestSalary FROM Employees;

DISTINCT: 去重

查询所有不重复的员工名字: SELECT DISTINCT Name FROM Employees;

TOP: 限制显示行数

限制查询结果显示的行数: SELECT TOP 5 Name FROM Employees;

数学函数

函数名称 作用说明 示例代码 示例结果
ABS() 求绝对值 SELECT ABS(-15) 15
ROUND() 四舍五入到指定小数位 SELECT ROUND(123.456, 2) 123.460
FLOOR() 向下取整(去尾法) SELECT FLOOR(123.99) 123
CEILING() 向上取整(进一法) SELECT CEILING(123.01) 124
POWER() 求幂(次方) SELECT POWER(2, 3) 8
SQRT() 求平方根 SELECT SQRT(16) 4
SIGN() 判断正负(正1,负-1,0为0) SELECT SIGN(-50) -1
RAND() 生成 0 到 1 之间的随机浮点数 SELECT RAND() 0.123…
LOG() 求自然对数(以 e 为底) SELECT LOG(10) 2.302…
EXP() 求指数(e 的指定次幂) SELECT EXP(2) 7.389…
SIN() 求正弦值(弧度) SELECT SIN(1.57) 1.000…
COS() 求余弦值(弧度) SELECT COS(0) 1

字符串函数

函数名称 作用说明 示例代码 示例结果
ASCII() 返回字符最左侧的 ASCII 码值 SELECT ASCII('A') 65
LEN() 返回字符串的字符数 SELECT LEN('SQL') 3
UPPER() 将字符串转换为大写 SELECT UPPER('sql') SQL
LOWER() 将字符串转换为小写 SELECT LOWER('SQL') sql
LTRIM() 去除字符串左侧的空格 SELECT LTRIM(' Hello') Hello
RTRIM() 去除字符串右侧的空格 SELECT RTRIM('Hello ') Hello
REPLACE() 替换字符串中的指定字符 SELECT REPLACE('abc', 'b', 'x') axc
SUBSTRING() 截取字符串的一部分 SELECT SUBSTRING('Hello', 2, 3) ell
CONCAT() 拼接两个或多个字符串 SELECT CONCAT('A', 'B') AB
REVERSE() 反转字符串 SELECT REVERSE('abc') cba

日期时间函数

函数名称 作用说明 示例代码 示例结果
GETDATE() 获取当前系统日期和时间 SELECT GETDATE() 2026-07-15 15:52:00
YEAR() 返回日期的年份 SELECT YEAR('2026-07-15') 2026
MONTH() 返回日期的月份 SELECT MONTH('2026-07-15') 7
DAY() 返回日期的天数 SELECT DAY('2026-07-15') 15
DATEADD() 在日期上增加指定的时间间隔 SELECT DATEADD(day, 1, '2026-07-15') 2026-07-16
DATEDIFF() 计算两个日期之间的差值 SELECT DATEDIFF(day, '2026-07-01', '2026-07-15') 14

转换函数

函数名称 作用说明 示例代码 示例结果
CAST() 数据类型转换(ANSI标准) SELECT CAST(123 AS VARCHAR) '123'
CONVERT() 数据类型转换(SQL Server特有) SELECT CONVERT(VARCHAR, GETDATE(), 112) 20260715
ISNULL() 如果表达式为 NULL,则返回指定值 SELECT ISNULL(NULL, '默认值') 默认值

元数据函数

函数名称 作用说明 示例代码 示例结果
DB_ID() 返回数据库的 ID 号 SELECT DB_ID() 5
DB_NAME() 返回数据库的名称 SELECT DB_NAME() MyDatabase
OBJECT_ID() 返回数据库对象的 ID 号 SELECT OBJECT_ID('Employees') 123456789
OBJECT_NAME() 返回数据库对象的名称 SELECT OBJECT_NAME(123456789) Employees

SQL 查询

SELECT 检索数据

一个完整的 SELECT 语句包含多个子句(参数),它们必须按照固定的顺序书写,完整语法结构如下

SELECT [ ALL | DISTINCT ] [ TOP ( expression ) [ PERCENT ] [ WITH TIES ] ] 
    列名1, 列名2
INTO 新表名
FROM 表名
WHERE 筛选条件
GROUP BY 分组列
HAVING 分组后的筛选条件
ORDER BY 排序列 [ ASC | DESC ]

WITH 子句

在 SQL Server 中,WITH 子句用于定义公用表表达式(Common Table Expression,简称 CTE)

你可以把 CTE 理解为一个“临时的、命名的结果集”,它就像你在查询过程中临时搭建的一个“虚拟视图”,只在当前这一条查询语句中有效

基本语法

WITH CTE名称 (列名1, 列名2, ...) AS
(
    -- 这里写定义 CTE 的查询语句
    SELECT 列名1, 列名2
    FROM 表名
    WHERE 条件
)
-- 紧接着必须是一条引用该 CTE 的语句(SELECT, INSERT, UPDATE, DELETE 等)
SELECT * FROM CTE名称;

🚩 常用场景与代码示例

-- 定义一个 CTE 来计算每个部门的平均薪资
WITH DeptAvgSalary AS (
    SELECT Department, AVG(Salary) AS AvgSalary
    FROM Employees
    GROUP BY Department
)
-- 在主查询中直接引用这个 CTE
SELECT * FROM DeptAvgSalary WHERE AvgSalary > 10000;
WITH 
-- 第一个 CTE:筛选出在职员工
ActiveEmployees AS (
    SELECT EmployeeID, Name, Department 
    FROM Employees 
    WHERE Status = 'Active'
),
-- 第二个 CTE:基于第一个 CTE 统计各部门人数
DeptCount AS (
    SELECT Department, COUNT(*) AS TotalCount 
    FROM ActiveEmployees 
    GROUP BY Department
)
-- 主查询:引用第二个 CTE
SELECT * FROM DeptCount ORDER BY TotalCount DESC;
-- 查询员工及其上级领导的层级关系
WITH EmployeeHierarchy AS (
    -- 锚点成员:找到没有上级的老板(顶层)
    SELECT EmployeeID, Name, ManagerID, 0 AS Level
    FROM Employees
    WHERE ManagerID IS NULL
 
    UNION ALL
 
    -- 递归成员:找到老板手下的员工,并不断向下递归
    SELECT e.EmployeeID, e.Name, e.ManagerID, eh.Level + 1
    FROM Employees e
    INNER JOIN EmployeeHierarchy eh ON e.ManagerID = eh.EmployeeID
)
SELECT * FROM EmployeeHierarchy;

SELECT ... FROM

如果把一条完整的 SQL 查询比作“去仓库取货”,那么:FROM 决定了你要去哪个仓库(数据源),SELECT 决定了你要从仓库里拿哪些具体的商品(数据列)

SELECT * FROM Employees;

SELECT e.Name, d.DepartmentName FROM Employees e INNER JOIN Departments d ON e.DeptID = d.ID;

SELECT Name, Salary 
FROM (
    SELECT Name, Salary FROM Employees WHERE Department = '销售部'
) AS TempTable; -- 必须给子查询起别名
WITH HighSalary AS (
    SELECT Name, Salary FROM Employees WHERE Salary > 20000
)
SELECT * FROM HighSalary;

INTO 子句

在 SQL Server 中,INTO 子句通常配合 SELECT 语句使用(即 SELECT … INTO),它的核心作用是将查询结果直接存入一张全新的表中

基本语法: SELECT 列名1, 列名2, ...INTO 新表名 FROM 源表名 WHERE 筛选条件;

WHERE 子句

在 SQL Server 中,WHERE 子句是数据查询语句中的“过滤器”,它紧跟在 FROM 子句之后,用于指定搜索条件,从而筛选出满足特定条件的数据行

基本语法: SELECT 列名1, 列名2, ...FROM 表名 WHERE 筛选条件

GROUP BY 子句

在 SQL Server 中,GROUP BY 子句是数据分析的“分类整理大师”,它的核心作用是将查询结果集中的数据,按照一个或多个指定的列进行分组

基本语法: SELECT 分组列1, 分组列2, 聚合函数(列名) FROM 表名 WHERE 筛选条件 GROUP BY 分组列1, 分组列2;

🚩常用场景与代码示例

-- 统计每个部门的员工总数
SELECT Department, COUNT(*) AS EmployeeCount
FROM Employees
GROUP BY Department;
-- 统计每个部门中,不同职位的员工人数
SELECT Department, JobTitle, COUNT(*) AS JobCount
FROM Employees
GROUP BY Department, JobTitle;
-- 按年份统计每年的订单总金额
SELECT YEAR(OrderDate) AS OrderYear, SUM(TotalAmount) AS YearlyTotal
FROM Orders
GROUP BY YEAR(OrderDate);

HAVING 子句

在 SQL Server 中,HAVING 子句是专门用来对 GROUP BY 分组后的结果进行筛选的

基本语法: SELECT 分组列, 聚合函数(列名) FROM 表名 GROUP BY 分组列 HAVING 聚合函数的筛选条件;

🚩 常用场景与代码示例

-- 统计每个部门的人数,并只保留人数大于 10 的部门
SELECT Department, COUNT(*) AS EmployeeCount
FROM Employees
GROUP BY Department
HAVING COUNT(*) > 10;
-- 找出平均薪资大于 15000,且总薪资支出超过 200000 的部门
SELECT Department, AVG(Salary) AS AvgSalary, SUM(Salary) AS TotalSalary
FROM Employees
GROUP BY Department
HAVING AVG(Salary) > 15000 AND SUM(Salary) > 200000;
-- 筛选出部门名称以“销售”开头的分组
SELECT Department, COUNT(*) 
FROM Employees
GROUP BY Department
HAVING Department LIKE '销售%';

ORDER BY 子句

在 SQL Server 中,ORDER BY 子句是查询语句的“排版师”,它的核心作用是对最终查询出来的结果集进行排序

基本语法: SELECT 列名1, 列名2 FROM 表名 ORDER BY 排序列 [ASC | DESC];

:TIP ASC:升序(从小到大,A-Z,旧到新),这是默认选项,不写也代表升序。DESC:降序(从大到小,Z-A,新到旧)

🚩 常用场景与代码示例

-- 按年龄从小到大排序
SELECT Name, Age FROM Employees ORDER BY Age;
 
-- 按薪资从高到低排序(显式指定 DESC)
SELECT Name, Salary FROM Employees ORDER BY Salary DESC;
-- 先按部门名称升序排列;如果部门相同,再按薪资降序排列
SELECT Name, Department, Salary 
FROM Employees 
ORDER BY Department ASC, Salary DESC;
-- 按计算出的年薪进行降序排列
SELECT Name, Salary * 12 AS YearlySalary 
FROM Employees 
ORDER BY YearlySalary DESC;

你可以用 SELECT 后面列的顺序号(从 1 开始)来代替列名

-- 等同于 ORDER BY Name
SELECT Name, Department FROM Employees ORDER BY 1;

UNION 合并

在 SQL Server 中,UNION 操作符用于将两个或多个 SELECT 语句的查询结果合并成一个结果集

如果说 JOIN 是根据列把两张表“横向”拼接起来,那么 UNION 就是把多个查询结果“纵向”堆叠在一起

基本语法: SELECT 列名1, 列名2 FROM 表1 UNION SELECT 列名1, 列名2 FROM 表2;

UNION 与 UNION ALL 的区别:UNION:合并数据 + 自动去重,UNION ALL:合并数据 + 保留所有行

🚩 常用场景与代码示例

假设我们有两个表:Employees(正式员工)和 Contractors(外包人员),我们想生成一份包含所有人员名字的名单

-- 查询正式员工的名字
SELECT Name, '正式员工' AS Type FROM Employees
UNION
-- 查询外包人员的名字
SELECT Name, '外包人员' AS Type FROM Contractors;

说 明

使用 UNION 时,必须严格遵守以下规则,否则语句会报错

1.列数必须相同:参与合并的所有 SELECT 语句,查询的列数必须完全一致

2.数据类型必须兼容:对应位置的列,其数据类型必须相似或兼容(例如都是整数,或都能隐式转换为字符串)

3.列的顺序必须一致:结果集的列名和顺序,通常以第一个 SELECT 语句的列为准

子查询与嵌套查询

在 SQL Server 中,子查询(Subquery)就是一个嵌套在另一个查询(如 SELECT、INSERT、UPDATE 或 DELETE)内部的查询语句

自包含子查询

🚩 内部查询完全独立,不依赖外部查询的任何数据,可以单独拿出来执行,数据库引擎通常只会执行它一次

-- 查询薪资高于公司平均薪资的员工
SELECT Name, Salary 
FROM Employees 
WHERE Salary > (
    -- 这是一个自包含子查询,先算出平均薪资
    SELECT AVG(Salary) FROM Employees
);

关联子查询

🚩这种子查询不能独立执行,它必须引用外部查询中的列,外部查询每处理一行数据,内部查询就会跟着执行一次

-- 查询每个部门中薪资最高的员工
SELECT e1.Name, e1.Department, e1.Salary
FROM Employees e1
WHERE e1.Salary = (
    -- 内部查询引用了外部查询的 e1.Department
    SELECT MAX(Salary) 
    FROM Employees e2 
    WHERE e2.Department = e1.Department
);

按返回结果分类

-- 多值子查询:查询属于“销售部”或“人事部”的所有员工
SELECT Name FROM Employees 
WHERE DepartmentID IN (
    SELECT ID FROM Departments WHERE Name IN ('销售部', '人事部')
);

嵌套查询

嵌套查询就是子查询的另一种叫法,你可以把它们理解为概念:只要是把一个 SELECT 查询语句“嵌套”在另一个查询(如 SELECT、INSERT、UPDATE、DELETE)内部的,都统称为嵌套查询

SELECT * FROM TableA WHERE ID IN (SELECT ID FROM TableB);

-- 这是一个两层嵌套的例子
SELECT Name FROM Employees
WHERE DepartmentID IN (
    SELECT ID FROM Departments
    WHERE CompanyID IN (
        SELECT ID FROM Companies WHERE CompanyName = '阿里巴巴'
    )
);

连接查询

在 SQL Server 中,连接查询(JOIN) 是关系型数据库最核心的功能,它的主要作用是将两张或多张表中的数据,

根据它们之间共有的关联字段(通常是主键和外键)“横向”拼接在一起,从而在一个查询结果中获取分散在不同表里的完整信息

内连接(INNER JOIN)

ON 子句是连接查询(JOIN)的“粘合剂”和“匹配规则”,它紧跟在 JOIN 关键字之后,用来指定两张表之间通过哪些列进行关联,如果没有 ON 子句,数据库就不知道怎么把两张表的数据拼在一起

🚩 内连接是最常用、也是默认的连接方式,它只返回两张表中满足连接条件的交集数据,如果某行数据在另一张表中找不到匹配项,这行数据就不会出现在结果中

-- 查询有部门信息的员工(没有分配部门的员工会被过滤掉)
SELECT e.Name, d.DepartmentName
FROM Employees e
INNER JOIN Departments d ON e.DeptID = d.ID;

左外连接(LEFT JOIN / LEFT OUTER JOIN)

🚩 以 JOIN 关键字左边的表为主表,它会返回左表中的所有行,即使右表中没有匹配的数据,如果右表没有匹配项,结果集中右表的列会显示为 NULL

-- 查询所有员工及其部门信息(即使员工还没分配部门,也会显示员工名字,部门显示为 NULL)
SELECT e.Name, d.DepartmentName
FROM Employees e
LEFT JOIN Departments d ON e.DeptID = d.ID;

右外连接(RIGHT JOIN / RIGHT OUTER JOIN)

与左连接相反,以 JOIN 关键字右边的表为主表,它会返回右表中的所有行,即使左表中没有匹配的数据

全外连接(FULL JOIN / FULL OUTER JOIN)

左表和右表的数据全部保留,无论是否匹配,两张表的所有行都会出现在结果集中,没有匹配到的部分,缺失的一侧会显示为 NULL

-- 查询所有员工和所有部门(无论有没有匹配上,全部显示)
SELECT e.Name, d.DepartmentName
FROM Employees e
FULL JOIN Departments d ON e.DeptID = d.ID;

交叉连接(CROSS JOIN)

🚩 在 SQL Server 中,CROSS JOIN 是最简单、也最“暴力”的一种连接方式,它的核心作用是将左表的每一行与右表的每一行进行组合,生成一个“笛卡尔积”

假设我们有一张颜色表(3行)和一张尺码表(3行):交叉连接后,结果为9行

-- 颜色表:红色、蓝色、绿色
-- 尺码表:S、M、L
 
SELECT c.ColorName, s.SizeName
FROM Colors c
CROSS JOIN Sizes s;

隐式连接

基本语法: SELECT 列名 FROM 表1, 表2 WHERE 表1.关联列 = 表2.关联列;

-- 隐式内连接:查询员工姓名和部门名称
SELECT e.Name, d.DepartmentName
FROM Employees e, Departments d
WHERE e.DeptID = d.ID;
 
-- 显式内连接(现代标准写法)
SELECT e.Name, d.DepartmentName
FROM Employees e
INNER JOIN Departments d ON e.DeptID = d.ID;
 
--3张以上表写法
 
-- 显式内连接(三张表标准写法)
SELECT 
    e.Name, 
    d.DepartmentName, 
    c.CompanyName
FROM Employees e
INNER JOIN Departments d ON e.DeptID = d.ID       -- 第一步:员工表 关联 部门表
INNER JOIN Companies c ON d.CompanyID = c.ID;     -- 第二步:部门表 关联 公司表

:TIP 不推荐这种隐式写法,简单来说,把多表连接写在 WHERE 里属于“上个时代的产物”,了解它的原理有助于你读懂老代码

CASE 函数查询

在 SQL Server 中,CASE 函数是 SQL 中唯一的条件逻辑表达式,它的作用像 if…else 或 switch 语句,允许你在查询结果中根据不同的条件返回不同的值

两种语法格式

CASE 
    WHEN 条件1 THEN 结果1
    WHEN 条件2 THEN 结果2
    ELSE 默认结果
END
CASE 字段名
    WHEN 值1 THEN 结果1
    WHEN 值2 THEN 结果2
    ELSE 默认结果
END

🚩 常用场景与代码示例

-- 将状态码翻译成中文
SELECT Name, 
    CASE Status
        WHEN 1 THEN '在职'
        WHEN 0 THEN '离职'
        ELSE '未知'
    END AS StatusText
FROM Employees;
-- 根据薪资范围划分等级
SELECT Name, Salary,
    CASE 
        WHEN Salary >= 20000 THEN '高薪'
        WHEN Salary >= 10000 THEN '中等'
        ELSE '低薪'
    END AS SalaryLevel
FROM Employees;
--在聚合函数中使用(行转列统计)
--这是 CASE 非常高级且实用的用法,常用于生成复杂的统计报表
-- 统计各部门中,薪资高于1万和低于1万的人数
SELECT Department,
    SUM(CASE WHEN Salary >= 10000 THEN 1 ELSE 0 END) AS HighSalaryCount,
    SUM(CASE WHEN Salary < 10000 THEN 1 ELSE 0 END) AS LowSalaryCount
FROM Employees
GROUP BY Department;

视图

在 SQL Server 中,视图(View) 本质上是一个保存下来的、带有名字的查询语句,你可以把它想象成一张“虚拟表”,视图本身并不存储具体的数据(除非是特殊的索引视图)

它只存储了 SELECT 查询的定义,当你查询视图时,数据库会在后台动态执行这段保存好的 SQL 语句,并返回结果

基本语法: CREATE VIEW 视图名称 AS SELECT 列名1, 列名2 FROM 表名 WHERE 筛选条件;

查询视图: SELECT * FROM 视图名称;

修改视图: ALTER VIEW 视图名称 AS SELECT 列名1, 列名2 FROM 表名 WHERE 筛选条件;

向视图添加数据: 新添加的数据储存在与视图相关的表中,对原表不影响

🚩 INSERT INTO 视图名称(Name, Department, Salary)VALUES ('张三', '销售部', 12000.00);

删除视图: DROP VIEW 视图名称;

重命名视图: exec sp_rename 视图名称

1)
Structured Query Language 结构化查询语言
2)
浮点常量使用符号e指定
3)
+=,-=,*=,/=
4)
称为“脏页”
5)
日常开发中,我们通常使用 16 级 作为常规业务错误的标准级别
6)
比如设置周日为第一天还是周一为第一天