DML —— 检索、插入与更新数据
SELECT
SELECT FirstName, LastName FROM Employees
SQL 中最核心的数据检索命令。指定具体的列能节省服务器资源,并只返回你需要的精确数据。
FROM
SELECT City FROM Customers
把 SQL 引擎指向数据源——要搜索哪张表、视图或哪一组表。没有它,查询就没有方向。
INSERT INTO
INSERT INTO Customers (Name, City) VALUES ('Dan', 'Haifa')用于向表中插入新行。重要:列的顺序必须与 VALUES 中值的顺序完全对应。
UPDATE
UPDATE Products SET Price = 150 WHERE ID = 1
用于编辑现有数据。关键:务必使用 WHERE——否则你会覆盖表中的每一行!
DELETE
DELETE FROM Orders WHERE Status = 'Canceled'
永久删除行。如果忘记 WHERE,有大规模删除的风险。
DISTINCT
SELECT DISTINCT City FROM Customers
清除重复,只返回唯一值的列表。
SELECT INTO
SELECT * INTO BackupTable FROM OriginalTable
创建一张新表并同时把数据复制进去。适合快速备份和临时工作。
INSERT INTO SELECT
INSERT INTO Archive SELECT * FROM Orders WHERE Year = 2020
从一张表读取并推入一张已有的表。适合归档和数据迁移流程。
MERGE
MERGE Target t USING Source s ON t.ID = s.ID WHEN MATCHED THEN UPDATE...
“Upsert”——找到匹配:更新它;没找到:插入它。省去复杂的逻辑。
AS (Alias)
SELECT FirstName AS Name FROM Employees e
列或表的临时名称。让标题更清晰,并在 JOIN 中缩短冗长的名称。
筛选与逻辑运算符
WHERE
SELECT * FROM Products WHERE Price > 100
主要的筛选引擎。它检查每一行,只放行条件为真的记录。
AND
WHERE Category = 'Toys' AND Price < 50
要求所有条件同时成立。只有全部满足的行才会显示。
OR
WHERE City = 'Haifa' OR City = 'Eilat'
只要其中一个条件成立即可。与 AND 组合时务必使用括号。
NOT
WHERE NOT Category = 'Food'
对条件取反。当定义“你不想要什么”更容易时很有用。
IN
WHERE Department IN ('HR', 'Sales', 'IT')一连串 OR 的简洁替代。接受一组值,检查值是否匹配其中之一。
NOT IN
WHERE Country NOT IN ('USA', 'UK')确保值不在列表中。用于过滤掉并排除一组 ID。
BETWEEN
WHERE OrderDate BETWEEN '2023-01-01' AND '2023-12-31'
一个连续的筛选范围,包含边界值。常用于日期和价格范围。
NOT BETWEEN
WHERE Age NOT BETWEEN 20 AND 30
检索范围之外的数据。用于查找统计上的离群值。
LIKE
WHERE Email LIKE '%@gmail.com'
灵活的字符串搜索。% = 任意字符序列。_ = 单个字符。
NOT LIKE
WHERE Address NOT LIKE '%PO Box%'
过滤掉包含某种模式的记录。用于数据清理。
IS NULL
WHERE DeliveryDate IS NULL
NULL = “数据不存在”。你不能用 = 来比较它。IS NULL 能找到空单元格。
IS NOT NULL
WHERE PhoneNumber IS NOT NULL
查找包含某些内容的行。用于清理报表和分析完整的数据。
= equals
WHERE Status = 'Active'
基本的比较运算符。要求完全匹配。
<> / != not equal
WHERE Role <> 'Admin'
这两种写法完全相同。显示所有不等于指定值的内容。
> greater than
WHERE Amount > 1000
高于参考点的值。不包含该值本身。
< less than
WHERE InventoryLevel < 10
低于参考点的值。用于对即将耗尽的库存发出警报。
>= greater than or equal
WHERE Age >= 18
包含阈值本身。定义最低门槛的正确方式。
<= less than or equal
WHERE Discount <= 0.5
设定上限。折扣最多 50%(含)的产品。
EXISTS
WHERE EXISTS (SELECT 1 FROM Orders o WHERE o.CustID = c.ID)
检查“是否存在?”。非常快——它在第一个匹配处就停止。在许多情况下优于 JOIN。
NOT EXISTS
WHERE NOT EXISTS (SELECT 1 FROM Orders o WHERE o.CustID = c.ID)
在另一张表中没有任何踪迹的实体。在性能上通常优于 NOT IN。
ANY
WHERE Price > ANY (SELECT Price FROM Competitors)
针对一组结果进行比较。只要条件对至少一个值成立即可。
ALL
WHERE Price > ALL (SELECT Price FROM Competitors)
更严格——条件必须对列表中的每一个值都成立,无一例外。
排序、分组与输出格式化
ORDER BY
ORDER BY LastName, FirstName
按逻辑顺序组织结果。没有 ORDER BY,SQL 会以任意顺序返回行。
ASC
ORDER BY Price ASC
升序排序——从小到大、A 到 Z。这是默认值,可以省略。
DESC
ORDER BY OrderDate DESC
降序排序。把最新、最赚钱或最高的排在最前面。
TOP
SELECT TOP 10 * FROM Customers ORDER BY Score DESC
只取前 X 行(SQL Server)。配合 ORDER BY DESC——就是“前 10 名”。
LIMIT
SELECT * FROM Customers ORDER BY Score DESC LIMIT 10
MySQL/PostgreSQL 中相当于 TOP。始终放在查询的末尾。
OFFSET
ORDER BY ID OFFSET 20 ROWS
跳过 X 行。分页机制的一部分——翻阅结果页。
FETCH NEXT
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
与 OFFSET 配合。定义跳过之后要取多少行。
GROUP BY
SELECT Category, COUNT(*) FROM Products GROUP BY Category
把具有相同值的记录归为一组,并支持按组进行聚合计算。
HAVING
GROUP BY Category HAVING COUNT(*) > 50
“针对组的 WHERE”。它在计算完成之后筛选。使用聚合函数时必须用它。
ROLLUP
GROUP BY ROLLUP (Department)
自动在底部添加一行“总计”。省去单独的计算。
CUBE
GROUP BY CUBE (Department, JobTitle)
为每一种可能的组合创建汇总行。用于分析型矩阵报表。
GROUPING SETS
GROUP BY GROUPING SETS ((Dept), (Title), ())
精确控制——准确指定要生成哪些汇总层级。比 CUBE 更高效。
聚合函数
COUNT(col)
SELECT COUNT(Email) FROM Customers
统计某一列中的值。忽略 NULL 行。10 行中有 8 个邮箱 → 返回 8。
COUNT(*)
SELECT COUNT(*) FROM Orders
统计物理行数,包括 NULL。快速知道“一共有多少条记录?”的方式。
SUM()
SELECT SUM(Amount) FROM Sales WHERE Year = 2023
把数值加总。财务报表跳动的心脏。
AVG()
SELECT AVG(Salary) FROM Employees
忽略 NULL 的算术平均值。用于平均工资、等待时间、年龄等等。
MIN()
SELECT MIN(Price) FROM Products
最小值。也用于最早的日期或按字母排序的第一个名字。
MAX()
SELECT MAX(OrderDate) FROM Orders
最大值。用于最赚钱的交易或最近的时间戳。
连接与集合运算
INNER JOIN
SELECT c.Name, o.Amount FROM Customers c INNER JOIN Orders o ON c.ID = o.CustID
只取两边都完全匹配的行。报告活跃交易时最安全的选择。
LEFT JOIN
SELECT c.Name, o.Amount FROM Customers c LEFT JOIN Orders o ON c.ID = o.CustID
左表中的所有行,即使没有匹配(右侧为 NULL)。用于查找没有订单的客户。
RIGHT JOIN
SELECT c.Name, o.Amount FROM Customers c RIGHT JOIN Orders o ON c.ID = o.CustID
右表中的所有行。通常更好的做法是交换顺序并使用 LEFT。
FULL OUTER JOIN
SELECT c.Name, o.Amount FROM Customers c FULL OUTER JOIN Orders o ON c.ID = o.CustID
来自各方的一切——匹配项加上两侧的缺口。用于审计和查找不匹配。
CROSS JOIN
SELECT Colors.Name, Sizes.Name FROM Colors CROSS JOIN Sizes
笛卡尔积——每一行 × 每一行。3 种颜色 × 3 种尺码 = 9 行。
SELF JOIN
SELECT e1.Name AS Emp, e2.Name AS Mgr FROM Employees e1 JOIN Employees e2 ON e1.MgrID = e2.ID
把一张表连接到它自己。用于在同一张表中处理经理—员工层级。
ON
JOIN Orders o ON c.ID = o.CustomerID
定义连接条件——哪些列在两张表中代表相同的信息。
USING
JOIN Orders USING (CustomerID)
当连接列在两张表中同名时,作为 ON 的简写。
UNION
SELECT City FROM Customers UNION SELECT City FROM Suppliers
把查询纵向堆叠并去除重复。两者必须具有相同的列结构。
UNION ALL
SELECT City FROM Customers UNION ALL SELECT City FROM Suppliers
不去除重复的合并。更快——在没有重叠时更可取。
INTERSECT
SELECT ProductID FROM Sales2023 INTERSECT SELECT ProductID FROM Sales2024
交集——只取在两个查询中都出现的行。用于两年都购买的忠实客户。
EXCEPT / MINUS
SELECT ProductID FROM Sales2023 EXCEPT SELECT ProductID FROM Sales2024
相减——在第一个查询中而不在第二个查询中的行。仅在 2023 年售出的产品。
DDL —— 定义结构与基础架构
CREATE DATABASE
CREATE DATABASE CompanyCRM
创建一个新数据库。在服务器上分配空间、文件和日志。
DROP DATABASE
DROP DATABASE CompanyCRM
删除整个数据库——包括所有表和数据。没有备份就无法恢复!
CREATE TABLE
CREATE TABLE Users (ID INT, Name VARCHAR(50))
创建一张新表并定义其列结构和数据类型。
ALTER TABLE
ALTER TABLE Users ADD Email VARCHAR(100)
对现有表的结构性更改——添加列、删除、更改数据类型。
DROP TABLE
DROP TABLE Users
彻底删除——数据和结构都被移除。你需要从头 CREATE。
TRUNCATE TABLE
TRUNCATE TABLE Logs
快速清空内容。结构保留。比 DELETE 更快——用于重置系统。
CREATE INDEX
CREATE INDEX idx_ln ON Employees (LastName)
列的“目录”。让你直接跳到某条记录,而不必扫描全部。
DROP INDEX
DROP INDEX idx_ln ON Employees
删除一个索引。索引会拖慢写入——删除未使用的索引能提升性能。
CREATE VIEW
CREATE VIEW ActiveUsers AS SELECT * FROM Users WHERE Status = 'Active'
一张“虚拟表”——把复杂查询以一个名称保存。对用户隐藏逻辑。
DROP VIEW
DROP VIEW ActiveUsers
删除一个视图。底层数据保持不变。
CREATE PROCEDURE
CREATE PROCEDURE GetUser (@ID INT) AS BEGIN SELECT * FROM Users WHERE ID=@ID END
存储在数据库中的小程序。提升安全性并防止 SQL 注入。
DROP PROCEDURE
DROP PROCEDURE GetUser
删除一个存储过程。用于版本升级和清理旧代码。
CREATE FUNCTION
CREATE FUNCTION CalcTax (@V DECIMAL) RETURNS DECIMAL AS BEGIN RETURN @V * 1.17 END
用于重复计算的自定义函数。返回一个干净的值,并在查询内部使用。
PRIMARY KEY
CREATE TABLE Users (ID INT PRIMARY KEY, Name VARCHAR(50))
每一行唯一的“身份证”。防止重复并要求必须有值。
FOREIGN KEY
CONSTRAINT FK_User FOREIGN KEY (UserID) REFERENCES Users(ID)
在表之间建立严格的关联。防止录入不存在的虚构 ID。
UNIQUE
CREATE TABLE Users (Email VARCHAR(100) UNIQUE)
列中的所有值必须互不相同。用于唯一的邮箱和电话号码。
NOT NULL
CREATE TABLE Users (Name VARCHAR(50) NOT NULL)
要求列中必须有值。防止创建没有名字的客户或没有价格的产品。
CHECK
CREATE TABLE Products (Price DECIMAL CHECK (Price > 0))
检查值是否符合业务规则。不允许出现负价格。
DEFAULT
CREATE TABLE Users (Status VARCHAR(20) DEFAULT 'Pending')
如果用户没有输入,则自动填入一个值。而不是让单元格留为 NULL。
IDENTITY / AUTO_INCREMENT
CREATE TABLE Users (ID INT IDENTITY(1,1) PRIMARY KEY)
自动递增的计数器(1,2,3……)。每一行新行都获得唯一的 ID。
文本处理函数
CONCAT()
SELECT CONCAT(FirstName, ' ', LastName) FROM Employees
连接字段和文本。优雅地处理 NULL——它会忽略它们。
CONCAT_WS()
SELECT CONCAT_WS(', ', City, State, Country) FROM Addresses“带分隔符的连接”。定义一个分隔符,自动把所有内容连接起来。
SUBSTRING()
SELECT SUBSTRING(IDNumber, 1, 4) FROM Customers
按位置裁剪文本:列名、起始字符、多少个字符。
LEN() / LENGTH()
WHERE LEN(Password) < 8
统计文本中有多少个字符。用于检查过短的密码和验证数据。
UPPER()
SELECT UPPER(CountryCode) FROM Countries
转换为大写。用于规范化比较——两边都转 UPPER = 一致的搜索。
LOWER()
SELECT LOWER(Email) FROM Users
转换为小写。处理邮箱的常见约定。
TRIM()
SELECT TRIM(Username) FROM Accounts
去除开头和结尾的空格。用于清理复制粘贴带来的“杂质”。
LTRIM()
SELECT LTRIM(Comment) FROM Feedback
只去除左侧的空格。
RTRIM()
SELECT RTRIM(Comment) FROM Feedback
只去除字符串末尾的空格。
REPLACE()
SELECT REPLACE(Phone, '-', '') FROM Customers
替换某个模式的每一次出现。用于移除电话号码中的短横线。
REVERSE()
SELECT REVERSE(StringCol) FROM Strings
反转字符的顺序。一个用于查找最后一个字符位置的技巧。
LEFT()
SELECT LEFT(OrderNum, 2) FROM Orders
从左侧取 X 个字符。从开头提取时比 SUBSTRING 更简短。
RIGHT()
SELECT RIGHT(CreditCard, 4) FROM Payments
从右侧取 X 个字符。用于信用卡的后 4 位。
CHARINDEX()
SELECT CHARINDEX('@', Email) FROM Users搜索某个字符/单词并返回数字位置。用于裁剪长度不一的邮箱。
PATINDEX()
SELECT PATINDEX('%[0-9]%', Address) FROM Customers查找智能模式(SQL Server)。用于定位地址中第一个数字的位置。
FORMAT()
SELECT FORMAT(Price, 'C', 'en-US') FROM Products
把值格式化成漂亮的文本——百万中的逗号、货币符号、日期格式。
日期与时间函数
GETDATE() / NOW()
SELECT GETDATE()
精确到毫秒的当前日期和时间。新记录的自动时间戳。
CURRENT_DATE
SELECT CURRENT_DATE
只有今天的日期,不含时间。用于只关心日期的条件。
CURRENT_TIME
SELECT CURRENT_TIME
不含日期的当前时间。用于效率报表和每日负载。
DATEADD()
SELECT DATEADD(day, 30, OrderDate) AS DueDate FROM Orders
给日期加上(或加负号减去)时间。用于计算到期日。
DATEDIFF()
SELECT DATEDIFF(day, OrderDate, ShipDate) FROM Orders
两个日期之间的间隔。用于响应时间、客户年龄、距发货的天数。
DATEPART()
SELECT DATEPART(quarter, OrderDate) FROM Sales
把某个特定元素提取为数字(quarter = 1-4)。按季度进行 GROUP BY 时必不可少。
YEAR()
SELECT YEAR(OrderDate) FROM Sales
隔离出年份。用于年度营收报表(2021、2022、2023……)。
MONTH()
SELECT MONTH(OrderDate) FROM Sales
月份编号(1-12)。用于跨年份的季节性分析。
DAY()
SELECT DAY(BirthDate) FROM Customers
当月的第几天(1-31)。用于生日和每月的信用卡还款。
EOMONTH()
SELECT EOMONTH(OrderDate) AS EndOfMonth FROM Sales
跳到当月的最后一天。解决“这个月有多少天”的问题。用于财务结账。
ISDATE()
SELECT * FROM Import WHERE ISDATE(RawText) = 1
检查文本是否为有效日期。防范来自表单的坏数据。
数学函数
ROUND()
SELECT ROUND(Price, 2) FROM Products
四舍五入到 X 位小数。用于精确的发票。
CEILING()
SELECT CEILING(4.1) -- Returns 5
把任何小数向上取整到下一个整数。4.1 辆公交车 → 你必须租 5 辆。
FLOOR()
SELECT FLOOR(4.9) -- Returns 4
向下截断到较小的整数。4.9 包 → 你只能装 4 包。
ABS()
SELECT ABS(Income - Expense) FROM Books
绝对值——负数变正数。用于计算差距的大小。
POWER()
SELECT POWER(Radius, 2) FROM Shapes
求幂。用于复利和面积计算。
SQRT()
SELECT SQRT(Area) FROM Squares
平方根。用于距离计算和标准差。
RAND()
SELECT RAND()
0 到 1 之间的随机数。用于抽奖和随机抽样。
SIGN()
SELECT SIGN(NetProfit) FROM Reports
1(正)、-1(负)、0。用于快速的盈亏指示。
PI()
SELECT PI() * POWER(Radius, 2) AS Area
内置的 π 常量。用于精确的几何计算。
MOD() / %
WHERE EmployeeID % 2 = 0
除法的余数。用于查找偶数行,以及把列表平均分到几个通道。
智能条件与 NULL 处理
CASE
SELECT CASE WHEN Score > 90 THEN 'A' ELSE 'F' END FROM Tests
查询内部的分支逻辑。构建一个实时对数据进行分类的计算列。
WHEN / THEN
CASE WHEN condition THEN result END
CASE 的核心。WHEN = 要测试的条件,THEN = 条件为真时的输出。
COALESCE()
SELECT COALESCE(Mobile, HomePhone, 'No Phone') FROM Contacts
返回第一个不为 NULL 的值。处理缺失数据的“优先级瀑布”。
ISNULL() / IFNULL()
SELECT ISNULL(Discount, 0) FROM Sales
如果为 NULL,则返回一个回退值。在计算中必不可少——NULL 会破坏数学运算。
NULLIF()
SELECT Amount / NULLIF(Quantity, 0) FROM Inventory
如果两个值相同 → 返回 NULL。防止除以零的崩溃。
数据类型转换与提升
IIF()
SELECT IIF(Stock > 0, 'In Stock', 'Out of Stock') FROM Products
用于两种状态的简写 CASE。SQL Server。三个输入:条件、真、假。
CAST()
SELECT CAST(Price AS INT) FROM Products
转换数据类型的标准工具。数字转文本以便拼接,文本转数字以便相加。
CONVERT()
SELECT CONVERT(VARCHAR(10), OrderDate, 103) FROM Orders
CAST 的兄弟,带有格式化能力。它可以在转换时格式化日期。
TRY_CAST()
SELECT TRY_CAST(StringVal AS INT) FROM DirtyData
一种安全的转换。乱码 → NULL 而不是崩溃。查询继续运行。
TRY_CONVERT()
SELECT TRY_CONVERT(DATE, StringDate) FROM DirtyData
一种安全的 CONVERT。用于从不可靠的外部源摄取数据。
窗口函数
OVER()
SELECT Name, SUM(Salary) OVER() AS Total FROM Employees
通往窗口函数的大门。无需 GROUP BY 就能对每条记录进行聚合计算。工资 + 公司总薪资一起显示。
PARTITION BY
SUM(Salary) OVER(PARTITION BY Department)
把窗口拆分成子组。部门薪资而不是整个公司。对每一组重置。
ROW_NUMBER()
ROW_NUMBER() OVER(ORDER BY Salary DESC)
唯一的连续编号(1,2,3……)。忽略并列。用于强制排序和去除重复。
RANK()
RANK() OVER(ORDER BY Salary DESC)
竞赛式排名。并列 → 两者都得第 2 名。下一个 → 跳到 4(跳过 3)。
DENSE_RANK()
DENSE_RANK() OVER(ORDER BY Salary DESC)
密集排名。在第 2 名并列之后,下一个得 3(而不是 4)。用于信用评级和订阅等级。
NTILE()
NTILE(4) OVER(ORDER BY Salary)
拆分成 X 个相等的组。NTILE(4) = 四个四分位。用于营销细分。
LEAD()
LEAD(Revenue) OVER(ORDER BY Month)
从下一行取一个值。把下个月的营收与当前月并排显示——无需 JOIN。
LAG()
LAG(Revenue) OVER(ORDER BY Month)
从上一行取一个值。把昨天和今天并排——在单个查询中计算 % 增长。
FIRST_VALUE()
FIRST_VALUE(Name) OVER(ORDER BY HireDate)
窗口中的第一条记录,对每一行都有效。把最资深的员工与每位员工并排显示。
LAST_VALUE()
LAST_VALUE(Name) OVER(ORDER BY HireDate)
窗口中的最后一条记录。把订单的最终阶段与所有中间阶段并排显示。
高级结构与架构
WITH (CTE)
WITH HighVal AS (SELECT * FROM Orders WHERE Amount > 1000) SELECT * FROM HighVal
一张贯穿整个查询的临时工作表。把复杂的代码变成可读的步骤。
PIVOT
PIVOT(SUM(Amount) FOR Year IN ([2022], [2023])) AS pvt
把行转成列。用于 Excel 式的报表——把一年中的各月作为列。
UNPIVOT
UNPIVOT (Amount FOR Year IN ([2022], [2023])) AS unpvt
把列转回行。用于规范化来自外部源的矩阵。
EXEC / EXECUTE
EXEC GetUser @UserID = 5
运行存储过程。也用于执行在运行时以文本构建的动态代码。
DECLARE
DECLARE @Year INT = 2023; SELECT * FROM Sales WHERE Year = @Year
在脚本中创建变量。改动顶部的一个值会影响下面的所有代码。
JSON 与 XML —— 半结构化数据
FOR JSON
SELECT Name, Age FROM Users FOR JSON AUTO
把 SQL 结果转成 JSON 格式。让 Web 开发者无需进一步转换就能在 JavaScript 中直接使用数据。
OPENJSON()
SELECT * FROM OPENJSON(@JsonString)
把 JSON 字符串转成带行和列的常规表。用于处理来自外部 API 的数据。
JSON_VALUE()
SELECT JSON_VALUE(JsonCol, '$.Address.City') FROM Customers
按路径从 JSON 中提取单个值。用于从大型 JSON 列中取出特定字段。
JSON_QUERY()
SELECT JSON_QUERY(JsonCol, '$.Hobbies') FROM Customers
从 JSON 中提取复杂的对象或数组。与返回简单值的 JSON_VALUE 不同。
JSON_MODIFY()
UPDATE Users SET JsonCol = JSON_MODIFY(JsonCol, '$.Status', 'VIP')
在不重写整个文档的情况下,编辑 JSON 内部的某个特定值。
ISJSON()
SELECT * FROM Logs WHERE ISJSON(RawData) = 1
检查字符串是否为有效的 JSON。有效返回 1,格式错误返回 0。用于过滤掉坏数据。
FOR XML
SELECT Name FROM Users FOR XML PATH('User')把表结果转成 XML 格式。在银行、政府和遗留系统中仍然常见。
OPENXML()
SELECT * FROM OPENXML(@doc, '/Users/User')
把 XML 字符串转成关系表。用于处理来自旧 XML 接口的数据。
高级字符串函数
STRING_AGG()
SELECT Dept, STRING_AGG(Name, ', ') FROM Employees GROUP BY Dept
用分隔符把多行合并成一个字符串。“5 名员工” → “Dan, Yael, Ron, Michal, Noa”。
STRING_SPLIT()
SELECT value FROM STRING_SPLIT('Apple,Banana,Orange', ',')用分隔符把字符串拆成单独的行。与 STRING_AGG 相反。
REPLICATE()
SELECT REPLICATE('0', 5) + OrderNumber FROM Orders把字符重复 X 次。用于给数字补前导零(000045)。
SPACE()
SELECT FirstName + SPACE(5) + LastName FROM Users
生成 X 个空格。比手动敲空格更易读。
SOUNDEX()
WHERE SOUNDEX(Name) = SOUNDEX('Smith')把单词转成语音(发音)编码。用于查找拼写错误的名字——“Smythe” = “Smith”。
DIFFERENCE()
SELECT DIFFERENCE(Name, 'Michael') FROM Users
两个单词语音相似度的 0-4 评分。4 = 发音完全相同。用于“你是不是想找……?”引擎。
QUOTENAME()
SELECT QUOTENAME(TableName) FROM Sys.Tables
用方括号把对象名称包起来。防止带空格名称出错,并防范 SQL 注入。
TRANSLATE()
SELECT TRANSLATE(Phone, '()-', ' ') FROM Contacts
一次替换多个字符。用于在单个查询中清理电话号码里的标点。
ASCII()
SELECT ASCII(LEFT(Password, 1)) FROM Logins
返回第一个字符的 ASCII 码。用于检查密码是否以大写字母开头。
CHAR()
SELECT 'Hello' + CHAR(13) + 'World'
把数字编码转成字符。CHAR(13) = 换行,CHAR(9) = Tab。用于无法直接输入的字符。
系统函数与标识符
DB_NAME()
SELECT DB_NAME()
返回当前数据库的名称。用于在拥有多个数据库的服务器上识别代码在哪里运行。
OBJECT_ID()
IF OBJECT_ID('TempTable') IS NOT NULL DROP TABLE TempTable检查某个表/对象是否存在。在 DROP 之前防止“表不存在”的错误。
OBJECT_NAME()
SELECT OBJECT_NAME(1234567)
把内部 ID 转成可读的名称。用于分析系统表和跟踪性能。
@@VERSION
SELECT @@VERSION
返回 SQL Server 和操作系统的版本。用于在运行代码前检查兼容性。
@@ROWCOUNT
UPDATE Users SET Status=1; SELECT @@ROWCOUNT
上一条命令影响的行数。用于指示 UPDATE/DELETE 的成功/失败。
@@ERROR
IF @@ERROR <> 0 PRINT 'Error occurred'
上一条命令的错误代码。0 = 成功。大多已被 TRY...CATCH 取代。
@@IDENTITY
INSERT INTO Orders(Amt) VALUES(50); SELECT @@IDENTITY
最后一个自动生成的 ID。用于在 INSERT 之后获取订单号。
SCOPE_IDENTITY()
SELECT SCOPE_IDENTITY()
类似 @@IDENTITY 但更安全——只返回当前作用域的 ID,不包括触发器产生的。
IDENT_CURRENT()
SELECT IDENT_CURRENT('Orders')某张特定表中的最后一个 ID——来自任何连接。用于监控表增长的速度。
HOST_NAME()
SELECT HOST_NAME()
连接来源机器的名称。用于审计系统跟踪谁从哪里访问。
SUSER_SNAME()
SELECT SUSER_SNAME()
当前用户的名称。用于构建行级安全——每位员工只看到自己的数据。
@@SERVERNAME
SELECT @@SERVERNAME
SQL 服务器的名称。用于需要知道连到哪一台的多服务器应用。
错误处理与流程控制
TRY...CATCH
BEGIN TRY ... END TRY BEGIN CATCH ... END CATCH
一种错误处理机制。TRY 中失败的代码会转到 CATCH 而不是崩溃。过程中最重要的工具。
THROW
BEGIN CATCH THROW; END CATCH
把错误重新抛给调用方应用。用于在数据库中记录错误,同时仍向用户显示一个错误。
RAISERROR
RAISERROR('Out of stock', 16, 1)引发一个自定义的、故意的错误。用于在出现业务问题(库存 = 0)时中止流程,即使没有 SQL 错误。
ERROR_MESSAGE()
INSERT INTO Logs VALUES (ERROR_MESSAGE())
CATCH 内部的完整错误文本。用于把错误详情保存到日志表。
ERROR_NUMBER()
IF ERROR_NUMBER() = 2627 PRINT 'Duplicate'
数字错误代码。用于按类型分别处理错误——重复 vs 权限 vs 连接。
ERROR_LINE()
SELECT ERROR_LINE() AS FailedAtRow
出错的代码行。在冗长的过程中节省数小时的调试时间。
WHILE
WHILE @Counter < 10 BEGIN ... SET @Counter = @Counter + 1 END
SQL 中的循环。用于在无法进行基于集合的操作时逐步处理数据。
BREAK
IF @Value = 0 BREAK
立即停止 WHILE 循环。用于发现错误时从循环中紧急退出。
CONTINUE
IF @Skip = 1 CONTINUE
跳到循环的下一次迭代。用于跳过无关记录而不中止一切。
RETURN
IF @User IS NULL RETURN
停止整个过程。一个“守门员”——如果输入无效,立即退出。
WAITFOR DELAY
WAITFOR DELAY '00:00:10'
延迟 X 时间。用于分批处理数据并加入停顿,以免拖垮服务器。
WAITFOR TIME
WAITFOR TIME '02:00:00'
等到某个特定时间。用于运行夜间维护任务。
高级安全权限
CREATE LOGIN
CREATE LOGIN JohnDoe WITH PASSWORD = 'Pass1'
创建对 SQL 服务器的访问。第一步——“进入大楼”。它还不授予对数据的访问。
CREATE USER
CREATE USER JohnDoeUser FOR LOGIN JohnDoe
把一个登录名关联到某个特定数据库。进入大楼之后的“某个房间的员工门禁”。
ALTER LOGIN / USER
ALTER LOGIN JohnDoe DISABLE
编辑或冻结一个用户。用于员工离职时立即撤销访问,而不删除其历史。
CREATE ROLE
CREATE ROLE DataAnalysts
创建一个权限组。管理一个组而不是逐个管理用户——可扩展又清晰。
DENY
DENY DELETE ON Orders TO DataAnalysts
强力封锁。它会覆盖任何其他 GRANT——即使对管理员组的成员也是如此。
EXECUTE AS
EXECUTE AS USER = 'AdminUser'
模拟另一个用户来测试权限。无需该用户的密码。
REVERT
REVERT
取消 EXECUTE AS 并恢复到原来的身份。无需断开重连。
维护与优化
WITH (NOLOCK)
SELECT * FROM MassiveTable WITH (NOLOCK)
不等待锁就读取。更快,但它可能返回正在更新中的数据(脏读)。
OPTION (RECOMPILE)
SELECT * FROM Users WHERE ID = @Var OPTION (RECOMPILE)
强制重新计算执行计划。用于服务器“记住”了一个糟糕计划的慢查询。
OPTION (MAXDOP)
SELECT * FROM HugeTable OPTION (MAXDOP 1)
限制查询使用多少个 CPU 核心。防止一个查询拖垮整台服务器。
SET NOCOUNT ON
SET NOCOUNT ON; UPDATE Users SET Name='X'
静默“受影响行数”消息。在拥有数千次操作的过程中减少带宽负载。
DBCC CHECKDB
DBCC CHECKDB('MyDatabase')扫描磁盘上所有数据的完整性。查找文件损坏(corruption)。每周运行一次。
UPDATE STATISTICS
UPDATE STATISTICS Customers
更新数据的统计图谱。加速已经开始变慢的查询。
ALTER INDEX REBUILD
ALTER INDEX ALL ON Customers REBUILD
从头重建索引。消除碎片并恢复“第一天”的速度。期间表会被锁定。
ALTER INDEX REORGANIZE
ALTER INDEX idx_name ON Customers REORGANIZE
不加锁地重新整理。比 REBUILD 更温和。用于安静的日常维护。
DBCC FREEPROCCACHE
DBCC FREEPROCCACHE
清除所有执行计划内存。用于重置因计划嗅探(plan sniffing)而变慢的服务器。
DBCC SHRINKDATABASE
DBCC SHRINKDATABASE('MyDB')收缩数据库并把磁盘空间归还给操作系统。在删除大量数据之后使用。
高级日期与时区
DATEFROMPARTS()
SELECT DATEFROMPARTS(2023, 10, 31)
用 3 个独立的数字(年、月、日)构建一个日期。用于合并来自应用的独立字段。
TIMEFROMPARTS()
SELECT TIMEFROMPARTS(14, 30, 0, 0, 0)
用 5 个数字构建一个时间。用于带独立时/分字段的打卡系统。
DATETIME2FROMPARTS()
SELECT DATETIME2FROMPARTS(2023,1,1,12,0,0,0,0)
以高精度构建完整的 DATETIME2(年+月+日+时+分+秒)。
SYSUTCDATETIME()
SELECT SYSUTCDATETIME()
通用 UTC 的当前时间。对面向全球用户的应用是必备。
AT TIME ZONE
SELECT OrderDate AT TIME ZONE 'Israel Standard Time'
把日期转换到某个特定时区,包含夏令时。无需手动计算。
SWITCHOFFSET()
SELECT SWITCHOFFSET(OrderDate, '+03:00')
手动移动时区偏移。用于以用户的本地时间显示日期。
TODATETIMEOFFSET()
SELECT TODATETIMEOFFSET(GETDATE(), '+02:00')
把一个普通日期变成带时区身份的 DateTimeOffset。用于全球计算。
DATENAME()
SELECT DATENAME(month, GETDATE())
返回一个文本名称(January、Monday)。与返回数字的 DATEPART 不同。
临时表、GUID 与序列
CREATE TABLE #Temp
CREATE TABLE #UserStats (ID INT, Score INT)
一张本地临时表——它只存在于当前连接中。用于中间计算而不污染数据库。
CREATE TABLE ##Temp
CREATE TABLE ##GlobalCache (Data VARCHAR(100))
一张全局临时表——所有连接都可访问。用于在用户之间共享缓存数据。
DECLARE @Table TABLE
DECLARE @MyList TABLE (EmpID INT)
仅在 RAM 中的表。对少量数据非常快——不写入磁盘。
NEWID()
INSERT INTO Users (ID) VALUES (NEWID())
生成一个全局唯一的 GUID。用于安全、不可猜测的 ID,以及跨服务器合并数据。
NEWSEQUENTIALID()
DEFAULT NEWSEQUENTIALID()
一个按升序运行的 GUID。解决 NEWID 的性能问题——保持索引有序。
CREATE SEQUENCE
CREATE SEQUENCE InvoiceSeq AS INT START WITH 1
一个不绑定到表的独立计数器。多张表可以共享的递增编号。
NEXT VALUE FOR
INSERT INTO Invoices (ID) VALUES (NEXT VALUE FOR InvoiceSeq)
从 SEQUENCE 取下一个编号。用于无重复的编号发票。
FORMATMESSAGE()
FORMATMESSAGE('Welcome %s, code: %i', 'Dan', 123)把变量注入文本模板。用于构建可读、集中管理的错误消息。
高级窗口函数
PERCENT_RANK()
PERCENT_RANK() OVER(ORDER BY Score)
以百分比表示的相对排名(0-1)。“高于全班的 85%”——无需知道班级人数。
CUME_DIST()
CUME_DIST() OVER(ORDER BY Score)
累积分布——数据中小于或等于当前值的比例。用于钟形曲线。
PERCENTILE_CONT()
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY Salary) OVER()
带插值的百分位数。如果没有精确的中间值,则返回两个值的平均。
PERCENTILE_DISC()
PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY Salary) OVER()
精确的百分位数——只返回数据中确实存在的值。不做插值。
GROUPING()
SELECT Dept, GROUPING(Dept), SUM(Salary) GROUP BY ROLLUP(Dept)
对 ROLLUP 汇总行返回 1。用于区分真正的 NULL 和“总计”行。
GROUPING_ID()
GROUPING_ID(Dep, Job) GROUP BY CUBE(Dep, Job)
在 CUBE 中标识分组类型的二进制代码。用于对多维矩阵的行排序。
CHOOSE()
SELECT CHOOSE(MonthNum, 'Jan', 'Feb', 'Mar'...) FROM Sales
按索引从列表中挑选一个值。CHOOSE(2,...) = 第二项。CASE 的简短替代。
ANY_VALUE()
SELECT Category, ANY_VALUE(ManagerName) FROM Items GROUP BY Category
返回组中的某个值。当它们全部相同时——比把 MAX(Name) 当作间接技巧更快。
NULLS FIRST / LAST
ORDER BY DeliveryDate ASC NULLS LAST
控制 NULL 在排序中出现的位置。防止空白跳到报表顶部。支持:Postgres/MySQL。
Dynamic PIVOT
EXEC(@DynamicPivotQuery)
一个根据数据动态构建自身的 PIVOT。用于列事先未知的透视表。
数据复制与表操作(高级 DML)
SELECT TOP WITH TIES
SELECT TOP 3 WITH TIES * FROM Orders ORDER BY Amount DESC
返回前 N 名,包括并列。如果有 4 行并列第 3——它们全部返回。
INSERT OR IGNORE
INSERT OR IGNORE INTO Users VALUES(1, 'Dan')
添加一行,如果它已存在——则静默忽略,不报错。SQLite/MySQL。
INSERT OR REPLACE
INSERT OR REPLACE INTO Users VALUES(1, 'Dan')
添加一行,如果它已存在——则替换它。SQLite 中 upsert 的捷径。
UPDATE FROM (JOIN)
UPDATE t SET t.Price = s.NewPrice FROM Products t JOIN Source s ON t.ID = s.ID
通过 JOIN 用另一张表的数据更新一张表。用于从外部源同步价格。
DELETE WITH JOIN
DELETE t FROM Orders t JOIN Cancelled c ON t.ID = c.ID
按条件从一张被连接的表中删除行。比 NOT IN 更精确。
OUTPUT (SQL Server)
DELETE FROM Orders OUTPUT DELETED.* WHERE Status='Old'
返回在操作期间被删除/更新的行。用于文档记录和变更日志。
RETURNING (PostgreSQL)
INSERT INTO Users(Name) VALUES('Dan') RETURNING ID返回所创建行的值。PostgreSQL 中相当于 OUTPUT——用于获取新的 ID。
EXCEPT ALL
SELECT ID FROM A EXCEPT ALL SELECT ID FROM B
带重复的相减——不从结果中去除重复。比普通的 EXCEPT 更快。
INTERSECT ALL
SELECT ID FROM A INTERSECT ALL SELECT ID FROM B
带重复的交集——保留所有出现。PostgreSQL/高级引擎。
TABLESAMPLE
SELECT * FROM Customers TABLESAMPLE (10 PERCENT)
返回表中 X 百分比的随机样本。用于在巨型表上快速测试。
高级数据分析(Analytics)
RATIO_TO_REPORT()
RATIO_TO_REPORT(Amount) OVER()
占总数的百分比。每一行除以总计——用于某项销售占公司总额的份额。
SUM OVER (Running Total)
SUM(Amount) OVER(ORDER BY Date ROWS UNBOUNDED PRECEDING)
累计总和——每一行都把它之前的全部加起来。
AVG OVER (Moving Avg)
AVG(Amount) OVER(ORDER BY Date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)
7 天移动平均。用于平滑销售数据中的季节性和趋势。
MIN/MAX OVER (Running)
MAX(Price) OVER(ORDER BY Date ROWS UNBOUNDED PRECEDING)
累计的最大/最小值——在每个时间点回答“到目前为止的峰值是多少?”。
COUNT DISTINCT (Approx)
APPROX_COUNT_DISTINCT(CustomerID)
近似的去重计数(约 2% 误差)。在大数据上比 COUNT DISTINCT 快 10 倍。
LISTAGG() / GROUP_CONCAT
LISTAGG(Name, ', ') WITHIN GROUP (ORDER BY Name)
把行合并成一个有序列表。Oracle/PostgreSQL——带内部排序的 STRING_AGG。
PIVOT with SUM/COUNT/AVG
SUM(Amount) FOR Quarter IN ([Q1],[Q2],[Q3],[Q4])
带多种函数的透视——不只是 SUM。用于灵活的多维报表。
CROSS APPLY
SELECT * FROM Customers c CROSS APPLY (SELECT TOP 3 * FROM Orders o WHERE o.CustID=c.ID) t
为每一行运行一个子查询。像 JOIN 但带相关性——用于每位客户的 TOP N。
OUTER APPLY
SELECT * FROM Customers c OUTER APPLY (...) t
像 CROSS APPLY,但也返回没有匹配的行(类似 LEFT JOIN)。
GENERATE_SERIES()
SELECT * FROM GENERATE_SERIES(1, 12)
生成一串数字/日期序列。用于日历和在缺失日期上没有“空洞”的报表。
全文搜索与文本检索
CONTAINS()
SELECT * FROM Articles WHERE CONTAINS(Body, 'SQL AND performance')
高级全文搜索。因为使用文本索引,所以比 LIKE 更快。支持 AND/OR/NOT。
FREETEXT()
SELECT * FROM Docs WHERE FREETEXT(Content, 'database optimization')
自由形式的搜索——也能找到词形变化和相关词。比 CONTAINS 不够精确但更灵活。
CONTAINSTABLE()
SELECT k.RANK, t.* FROM Docs t JOIN CONTAINSTABLE(Docs,*,'SQL') k ON t.ID=k.[KEY]
像 CONTAINS,但返回相关性排名。用于带匹配评分的搜索引擎。
FREETEXTTABLE()
JOIN FREETEXTTABLE(Docs,*,'query') k ON t.ID=k.[KEY]
带排名的 FREETEXT。用于 Google 式搜索——返回按相关性排序的结果。
MATCH...AGAINST (MySQL)
WHERE MATCH(title, body) AGAINST('SQL performance')MySQL 中的全文搜索。需要在列上建立 FULLTEXT 索引。比 LIKE 快得多。
LIKE with Escape
WHERE Name LIKE '100\%' ESCAPE '\'
搜索字面的 % 字符(不是通配符)。用于把 “100%” 当作字面文本来搜索。
REGEXP / RLIKE (MySQL)
WHERE Email REGEXP '^[a-zA-Z]+@'
用正则表达式进行搜索。用于验证复杂格式——邮箱、电话、产品代码。
SIMILAR TO (PostgreSQL)
WHERE Code SIMILAR TO '[A-Z]{3}-[0-9]+'SQL 标准风格的正则表达式。在 PostgreSQL 中——介于 LIKE 和 REGEXP 之间。
高级索引与优化
CREATE FILTERED INDEX
CREATE INDEX idx_active ON Users(Name) WHERE Status='Active'
只针对一个子集的索引。更小更快——用于总是按固定条件筛选的查询。
CREATE COLUMNSTORE INDEX
CREATE COLUMNSTORE INDEX idx_col ON Sales(Date, Amount)
用于分析的列式索引。在数据仓库的 GROUP BY/SUM 上快 10-100 倍。
CREATE COVERING INDEX
CREATE INDEX idx_cov ON Orders(CustID) INCLUDE(Amount, Date)
一个在 INCLUDE 中带额外列的索引。避免读取表本身——查询更快。
EXPLAIN / EXECUTION PLAN
EXPLAIN SELECT * FROM Users WHERE ID=1
显示查询的执行计划。用于发现不必要的全表扫描和缺失的索引。
SET STATISTICS IO ON
SET STATISTICS IO ON; SELECT ...
显示读取了多少个磁盘页。用于查找导致变慢的高 I/O 查询。
SET STATISTICS TIME ON
SET STATISTICS TIME ON; SELECT ...
显示 CPU 和解析时间。用于对慢查询进行精确的性能分析。
WITH (FORCESCAN)
SELECT * FROM T WITH (FORCESCAN)
即使存在索引也强制全表扫描。用于全扫描更快的情况(小表)。
WITH (FORCESEEK)
SELECT * FROM T WITH (FORCESEEK)
强制使用某个索引。当引擎判断失误而选择扫描时——FORCESEEK 能修正它。
sp_updatestats
EXEC sp_updatestats
更新数据库中所有表的统计信息。在大量数据加载之后使用。
高级存储过程与函数
CREATE OR ALTER PROCEDURE
CREATE OR ALTER PROCEDURE GetOrders AS ...
用单个命令创建一个过程,或替换一个已有的过程。无需单独的 DROP-CREATE。
Procedure with OUTPUT
CREATE PROCEDURE Calc (@In INT, @Out INT OUTPUT) AS SET @Out = @In * 2
一个通过 OUTPUT 参数返回值的过程。用于需要返回多个值的计算。
Procedure with DEFAULT
CREATE PROCEDURE GetData (@Days INT = 30) AS ...
一个带默认值的参数。你可以不带参数调用它——它会自动取 30 天。
Inline Table-Valued Function
CREATE FUNCTION GetOrders(@ID INT) RETURNS TABLE AS RETURN (SELECT * FROM Orders WHERE CustID=@ID)
一个返回表的函数。你可以像对普通表一样对它做 JOIN。非常快。
Multi-Statement TVF
CREATE FUNCTION GetData() RETURNS @t TABLE(...) AS BEGIN INSERT INTO @t ... RETURN END
一个带复杂逻辑、返回表的函数。比内联式更灵活但更慢。
EXEC with variables
EXEC (@SQL)
从字符串运行动态 SQL。用于在运行时构建灵活的查询。
sp_executesql
EXEC sp_executesql @SQL, '@ID INT', @ID=5
带参数的动态 SQL。比普通的 EXEC 更安全——防止 SQL 注入。
sys.procedures
SELECT * FROM sys.procedures
数据库中所有过程的列表。用于文档记录和审查现有代码。
触发器
CREATE TRIGGER (AFTER INSERT)
CREATE TRIGGER trg_ins ON Orders AFTER INSERT AS ...
一个在 INSERT 之后自动运行的触发器。用于自动事件——发送邮件、更新日志。
CREATE TRIGGER (INSTEAD OF)
CREATE TRIGGER trg_v ON MyView INSTEAD OF INSERT AS ...
替换另一个操作。用于允许在原本不直接支持的视图上做 INSERT。
INSERTED / DELETED tables
SELECT * FROM INSERTED; SELECT * FROM DELETED
触发器内部保存被插入/删除数据的虚拟表。用于保存旧值。
DISABLE TRIGGER
DISABLE TRIGGER trg_ins ON Orders
临时禁用一个触发器。用于批量数据导入而不触发自动逻辑。
DDL TRIGGER
CREATE TRIGGER trg_ddl ON DATABASE FOR DROP_TABLE AS ...
针对 DROP TABLE 等 DDL 操作的触发器。用于防止生产环境中的意外删除。
分区 —— 拆分表
CREATE PARTITION FUNCTION
CREATE PARTITION FUNCTION pf_year(INT) AS RANGE RIGHT FOR VALUES(2021,2022,2023)
为分区定义范围。用于按年/月把一张巨型表拆分成多个部分。
CREATE PARTITION SCHEME
CREATE PARTITION SCHEME ps_year AS PARTITION pf_year ALL TO ([PRIMARY])
给每个分区分配文件组。创建分区表的第二步。
CREATE TABLE ON Partition
CREATE TABLE Sales(Date INT) ON ps_year(Date)
创建一张分区表。SQL 会根据行的值自动管理它存储在哪里。
Partition Elimination
SELECT * FROM Sales WHERE Year=2023
SQL 只读取相关的分区,跳过其余的。在巨型表上快 10 倍以上。
ALTER TABLE SWITCH PARTITION
ALTER TABLE Sales SWITCH PARTITION 1 TO SalesArchive
以 O(1) 在表之间移动整个分区。用于即时归档旧数据。
时态表 —— 带历史记录的表
CREATE SYSTEM-VERSIONED TABLE
CREATE TABLE Products(ID INT, Price DECIMAL, ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START, ValidTo DATETIME2 GENERATED ALWAYS AS ROW END, PERIOD FOR SYSTEM_TIME(ValidFrom,ValidTo)) WITH (SYSTEM_VERSIONING=ON)
一张自动管理历史的表。SQL 会自动保留每一个旧版本。
FOR SYSTEM_TIME AS OF
SELECT * FROM Products FOR SYSTEM_TIME AS OF '2023-01-01'
返回数据在某个给定日期时的样子。“时间旅行”——看到数据库过去的样子。
FOR SYSTEM_TIME BETWEEN
FOR SYSTEM_TIME BETWEEN '2022-01-01' AND '2023-01-01'
某个日期范围内的所有更改。用于审计和跟踪数据随时间的变化。
FOR SYSTEM_TIME ALL
SELECT * FROM Products FOR SYSTEM_TIME ALL
每一行有史以来的每一个版本。用于显示完整的变更时间线。
ALTER TABLE OFF System Versioning
ALTER TABLE Products SET (SYSTEM_VERSIONING=OFF)
关闭历史管理。用于清理历史数据和结构性更改。
图数据库与层级结构
CREATE NODE TABLE
CREATE TABLE Person(ID INT) AS NODE
一张节点表(SQL Graph)。用于表示社交网络、图和依赖关系。
CREATE EDGE TABLE
CREATE TABLE Knows AS EDGE
图中的一张边表。连接两个节点——Person KNOWS Person。
MATCH (Graph Query)
SELECT p1.Name, p2.Name FROM Person p1, Knows, Person p2 WHERE MATCH(p1-(Knows)->p2)
一个图查询——谁认识谁。用于分析社交网络和依赖图。
Recursive CTE - Tree
WITH RECURSIVE tree AS(SELECT ID, ParentID, 0 lvl FROM Cats WHERE ParentID IS NULL UNION ALL SELECT c.ID, c.ParentID, t.lvl+1 FROM Cats c JOIN tree t ON c.ParentID=t.ID)
一棵递归的层级树。用于嵌套类别、组织架构图和产品 BOM 树。
PATH with CTE
'' AS path ... t.path+'/'+c.Name
在树中构建完整路径(Root/Branch/Leaf)。用于显示面包屑和分析树的深度。
行级安全与动态脱敏
CREATE SECURITY POLICY
CREATE SECURITY POLICY SalesFilter ADD FILTER PREDICATE dbo.fn_filter(SalesRep) ON Orders
行级安全——每位员工只看到自己的行。自动且对应用透明。
CREATE FUNCTION (RLS Predicate)
CREATE FUNCTION fn_filter(@User nvarchar(50)) RETURNS TABLE AS RETURN SELECT 1 r WHERE @User=USER_NAME()
RLS 的筛选函数。对每一行返回 1(允许)或 0(阻止)。
Dynamic Data Masking
Email VARCHAR(100) MASKED WITH (FUNCTION='email()')
自动对敏感数据脱敏:a***@***.com。分析师看到掩码,DBA 看到全部。
ADD MASK
ALTER TABLE Customers ALTER COLUMN Phone ADD MASKED WITH (FUNCTION='partial(0,"XXX-XXX-",4)')
给一个现有列添加掩码。XXX-XXX-1234——只显示后 4 位。
GRANT UNMASK
GRANT UNMASK TO AdminUser
让某个特定用户看到真实数据。用于“按需知情”策略。
Always Encrypted 与透明数据加密
Always Encrypted
SSN ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY=CEK, ENCRYPTION_TYPE=Deterministic)
列级加密。即使是 DBA 也看不到数据——只有应用可以。
Transparent Data Encryption
ALTER DATABASE MyDB SET ENCRYPTION ON
加密磁盘上所有的数据库文件。防范文件被人从服务器物理盗取。
BACKUP ENCRYPTION
BACKUP DATABASE MyDB TO DISK='backup.bak' WITH ENCRYPTION
加密备份文件。没有密钥,备份对攻击者毫无价值。
OPEN SYMMETRIC KEY
OPEN SYMMETRIC KEY MyKey DECRYPTION BY PASSWORD='pass'
打开一个加密密钥以供使用。在手动加密/解密数据之前。
ENCRYPTBYKEY / DECRYPTBYKEY
ENCRYPTBYKEY(KEY_GUID('MyKey'), CreditCard)对一个字段进行手动加密和解密。用于按需恢复的加密存储。
高可用性与复制
ALTER DATABASE SET RECOVERY FULL
ALTER DATABASE MyDB SET RECOVERY FULL
完整恢复模式——保留整个操作日志。对高 SLA 的生产环境是必备。
BACKUP LOG
BACKUP LOG MyDB TO DISK='log.bak'
一份事务日志备份。支持恢复到精确的时间点——时间点恢复(Point-in-Time Recovery)。
RESTORE DATABASE WITH STANDBY
RESTORE DATABASE MyDB WITH STANDBY='undo.bak'
以只读模式恢复,并可选择继续。用于可供读取的备份服务器。
RESTORE WITH NORECOVERY
RESTORE DATABASE MyDB WITH NORECOVERY
一种允许继续应用后续备份的恢复。用于来自多份备份的恢复链。
sys.dm_exec_requests
SELECT * FROM sys.dm_exec_requests
服务器上当前正在运行的所有查询。用于查找卡住的查询和阻塞。
云 SQL 与现代特性
EXTERNAL DATA SOURCE
CREATE EXTERNAL DATA SOURCE BlobStorage WITH (TYPE=BLOB_STORAGE, LOCATION='https://...')
定义一个外部数据源(Azure Blob、S3)。用于在 SQL 中直接读取云端文件。
OPENROWSET (Blob)
SELECT * FROM OPENROWSET(BULK 'data.csv', DATA_SOURCE='BlobStorage', FORMAT='CSV') t
直接从云端读取 CSV/Parquet。在 Azure Synapse 和 SQL Server 2019+ 中。
PolyBase
SELECT * FROM ExternalTable
像查询常规 SQL 表一样查询 Hadoop、Azure 和 S3。用于大数据分析。
OPENDATASOURCE
SELECT * FROM OPENDATASOURCE('SQLNCLI', 'server=OtherServer;uid=sa;pwd=p').DB.dbo.Table无需链接服务器即可一次性访问另一台 SQL 服务器。用于罕见的跨服务器查询。
LINKED SERVER
EXEC sp_addlinkedserver @server='OtherServer'
到外部服务器的永久连接。用于跨服务器和不同数据库的常规查询。