sqlserver

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SQL Server Core Knowledge

SQL Server 核心知识

Deep Knowledge: Use
mcp__documentation__fetch_docs
with technology:
sqlserver
for comprehensive documentation.
深度参考:使用
mcp__documentation__fetch_docs
工具并指定technology为
sqlserver
,可获取完整文档。

Data Types

数据类型

Numeric Types

数值类型

TypeDescriptionRange
BIT
Boolean (0/1)0, 1, NULL
TINYINT
1 byte integer0 to 255
SMALLINT
2 byte integer-32,768 to 32,767
INT
4 byte integer-2^31 to 2^31-1
BIGINT
8 byte integer-2^63 to 2^63-1
DECIMAL(p,s)
Fixed precisionp: 1-38 digits
NUMERIC(p,s)
Same as DECIMALp: 1-38 digits
FLOAT
8 byte float~15 digits precision
REAL
4 byte float~7 digits precision
MONEY
8 byte currency±922 trillion
SMALLMONEY
4 byte currency±214,748
类型描述范围
BIT
布尔值(0/1)0, 1, NULL
TINYINT
1字节整数0 到 255
SMALLINT
2字节整数-32,768 到 32,767
INT
4字节整数-2^31 到 2^31-1
BIGINT
8字节整数-2^63 到 2^63-1
DECIMAL(p,s)
固定精度数值p: 1-38位数字
NUMERIC(p,s)
与DECIMAL功能相同p: 1-38位数字
FLOAT
8字节浮点数约15位精度
REAL
4字节浮点数约7位精度
MONEY
8字节货币类型±922万亿
SMALLMONEY
4字节货币类型±214,748

String Types

字符串类型

TypeDescriptionMax Size
CHAR(n)
Fixed-length8,000 bytes
VARCHAR(n)
Variable-length8,000 bytes
VARCHAR(MAX)
Large variable2 GB
NCHAR(n)
Unicode fixed4,000 chars
NVARCHAR(n)
Unicode variable4,000 chars
NVARCHAR(MAX)
Unicode large1 GB
TEXT
Legacy large (deprecated)2 GB
NTEXT
Legacy Unicode (deprecated)1 GB
类型描述最大容量
CHAR(n)
固定长度字符串8,000字节
VARCHAR(n)
可变长度字符串8,000字节
VARCHAR(MAX)
大可变长度字符串2 GB
NCHAR(n)
Unicode固定长度字符串4,000字符
NVARCHAR(n)
Unicode可变长度字符串4,000字符
NVARCHAR(MAX)
Unicode大可变长度字符串1 GB
TEXT
旧版大文本类型(已废弃)2 GB
NTEXT
旧版Unicode大文本类型(已废弃)1 GB

Date/Time Types

日期/时间类型

TypeDescriptionRange
DATE
Date only0001-01-01 to 9999-12-31
TIME(n)
Time only (n=0-7 precision)00:00:00 to 23:59:59
DATETIME
Date + time1753-01-01 to 9999-12-31
DATETIME2(n)
Extended datetime0001-01-01 to 9999-12-31
DATETIMEOFFSET(n)
With timezoneSame + timezone
SMALLDATETIME
Less precision1900-01-01 to 2079-06-06
类型描述范围
DATE
仅日期0001-01-01 到 9999-12-31
TIME(n)
仅时间(n=0-7表示精度)00:00:00 到 23:59:59
DATETIME
日期+时间1753-01-01 到 9999-12-31
DATETIME2(n)
扩展日期时间类型0001-01-01 到 9999-12-31
DATETIMEOFFSET(n)
带时区的日期时间范围同上,附加时区信息
SMALLDATETIME
低精度日期时间1900-01-01 到 2079-06-06

Other Types

其他类型

TypeDescription
UNIQUEIDENTIFIER
16-byte GUID
BINARY(n)
Fixed binary
VARBINARY(n)
Variable binary
VARBINARY(MAX)
Large binary (2 GB)
XML
XML data
JSON
JSON (stored as NVARCHAR)
GEOGRAPHY
Spatial data
GEOMETRY
Geometric data
HIERARCHYID
Hierarchy position
sql
CREATE TABLE example (
    id INT IDENTITY(1,1) PRIMARY KEY,
    uuid UNIQUEIDENTIFIER DEFAULT NEWID(),
    name NVARCHAR(100) NOT NULL,
    price DECIMAL(10,2),
    quantity INT DEFAULT 0,
    is_active BIT DEFAULT 1,
    created_at DATETIME2 DEFAULT SYSDATETIME(),
    metadata NVARCHAR(MAX),  -- For JSON
    document VARBINARY(MAX)  -- For files
);
类型描述
UNIQUEIDENTIFIER
16字节GUID
BINARY(n)
固定长度二进制数据
VARBINARY(n)
可变长度二进制数据
VARBINARY(MAX)
大二进制数据(2 GB)
XML
XML数据类型
JSON
JSON数据(存储为NVARCHAR类型)
GEOGRAPHY
空间地理数据类型
GEOMETRY
空间几何数据类型
HIERARCHYID
层级位置数据类型
sql
CREATE TABLE example (
    id INT IDENTITY(1,1) PRIMARY KEY,
    uuid UNIQUEIDENTIFIER DEFAULT NEWID(),
    name NVARCHAR(100) NOT NULL,
    price DECIMAL(10,2),
    quantity INT DEFAULT 0,
    is_active BIT DEFAULT 1,
    created_at DATETIME2 DEFAULT SYSDATETIME(),
    metadata NVARCHAR(MAX),  -- For JSON
    document VARBINARY(MAX)  -- For files
);

Identity Columns

标识列

sql
-- Auto-increment
CREATE TABLE employees (
    id INT IDENTITY(1,1) PRIMARY KEY,
    name NVARCHAR(100)
);

-- Get last identity
SELECT SCOPE_IDENTITY();      -- Current scope
SELECT @@IDENTITY;            -- Any scope (avoid)
SELECT IDENT_CURRENT('employees');  -- Specific table

-- Insert with identity off
SET IDENTITY_INSERT employees ON;
INSERT INTO employees (id, name) VALUES (100, 'Admin');
SET IDENTITY_INSERT employees OFF;

-- Reseed identity
DBCC CHECKIDENT ('employees', RESEED, 0);
sql
-- 自动递增
CREATE TABLE employees (
    id INT IDENTITY(1,1) PRIMARY KEY,
    name NVARCHAR(100)
);

-- 获取最后生成的标识值
SELECT SCOPE_IDENTITY();      -- 当前作用域内的标识值
SELECT @@IDENTITY;            -- 任意作用域的标识值(不推荐使用)
SELECT IDENT_CURRENT('employees');  -- 指定表的标识值

-- 关闭标识插入后插入数据
SET IDENTITY_INSERT employees ON;
INSERT INTO employees (id, name) VALUES (100, 'Admin');
SET IDENTITY_INSERT employees OFF;

-- 重置标识种子
DBCC CHECKIDENT ('employees', RESEED, 0);

Sequences (2012+)

序列(2012及以上版本)

sql
-- Create sequence
CREATE SEQUENCE dbo.OrderSeq
    AS INT
    START WITH 1
    INCREMENT BY 1
    MINVALUE 1
    NO MAXVALUE
    NO CYCLE
    CACHE 20;

-- Use sequence
INSERT INTO orders (id, customer_id)
VALUES (NEXT VALUE FOR dbo.OrderSeq, 1);

-- In DEFAULT
ALTER TABLE orders
ADD CONSTRAINT df_order_id DEFAULT (NEXT VALUE FOR dbo.OrderSeq) FOR id;

-- Get current without incrementing
SELECT current_value FROM sys.sequences WHERE name = 'OrderSeq';

-- Reset sequence
ALTER SEQUENCE dbo.OrderSeq RESTART WITH 1;
sql
-- 创建序列
CREATE SEQUENCE dbo.OrderSeq
    AS INT
    START WITH 1
    INCREMENT BY 1
    MINVALUE 1
    NO MAXVALUE
    NO CYCLE
    CACHE 20;

-- 使用序列
INSERT INTO orders (id, customer_id)
VALUES (NEXT VALUE FOR dbo.OrderSeq, 1);

-- 设置默认值为序列
ALTER TABLE orders
ADD CONSTRAINT df_order_id DEFAULT (NEXT VALUE FOR dbo.OrderSeq) FOR id;

-- 获取当前序列值(不递增)
SELECT current_value FROM sys.sequences WHERE name = 'OrderSeq';

-- 重置序列
ALTER SEQUENCE dbo.OrderSeq RESTART WITH 1;

Date/Time Functions

日期/时间函数

sql
-- Current date/time
SELECT GETDATE();           -- DATETIME
SELECT SYSDATETIME();       -- DATETIME2 (more precise)
SELECT GETUTCDATE();        -- UTC datetime
SELECT SYSUTCDATETIME();    -- UTC datetime2
SELECT SYSDATETIMEOFFSET(); -- With timezone

-- Date parts
SELECT YEAR(GETDATE());
SELECT MONTH(GETDATE());
SELECT DAY(GETDATE());
SELECT DATEPART(QUARTER, GETDATE());
SELECT DATENAME(WEEKDAY, GETDATE());  -- 'Monday'

-- Date arithmetic
SELECT DATEADD(DAY, 7, GETDATE());     -- Add 7 days
SELECT DATEADD(MONTH, -1, GETDATE());  -- Subtract 1 month
SELECT DATEDIFF(DAY, '2024-01-01', GETDATE());  -- Days between

-- Format (2012+)
SELECT FORMAT(GETDATE(), 'yyyy-MM-dd');
SELECT FORMAT(GETDATE(), 'dd/MM/yyyy HH:mm:ss');

-- Parse
SELECT CAST('2024-01-15' AS DATE);
SELECT CONVERT(DATETIME, '01/15/2024', 101);  -- US format
SELECT PARSE('15 January 2024' AS DATE);

-- First/last of month
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0);  -- First of month
SELECT EOMONTH(GETDATE());  -- Last of month (2012+)
sql
-- 获取当前日期/时间
SELECT GETDATE();           -- 返回DATETIME类型
SELECT SYSDATETIME();       -- 返回DATETIME2类型(精度更高)
SELECT GETUTCDATE();        -- 返回UTC时间(DATETIME类型)
SELECT SYSUTCDATETIME();    -- 返回UTC时间(DATETIME2类型)
SELECT SYSDATETIMEOFFSET(); -- 返回带时区的日期时间

-- 提取日期部分
SELECT YEAR(GETDATE());
SELECT MONTH(GETDATE());
SELECT DAY(GETDATE());
SELECT DATEPART(QUARTER, GETDATE());
SELECT DATENAME(WEEKDAY, GETDATE());  -- 返回星期名称,如'Monday'

-- 日期运算
SELECT DATEADD(DAY, 7, GETDATE());     -- 加7天
SELECT DATEADD(MONTH, -1, GETDATE());  -- 减1个月
SELECT DATEDIFF(DAY, '2024-01-01', GETDATE());  -- 计算两个日期的天数差

-- 格式化日期(2012及以上版本)
SELECT FORMAT(GETDATE(), 'yyyy-MM-dd');
SELECT FORMAT(GETDATE(), 'dd/MM/yyyy HH:mm:ss');

-- 解析字符串为日期
SELECT CAST('2024-01-15' AS DATE);
SELECT CONVERT(DATETIME, '01/15/2024', 101);  -- 按美国格式解析
SELECT PARSE('15 January 2024' AS DATE);

-- 获取当月第一天和最后一天
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0);  -- 当月第一天
SELECT EOMONTH(GETDATE());  -- 当月最后一天(2012及以上版本)

String Functions

字符串函数

sql
-- Concatenation
SELECT 'Hello' + ' ' + 'World';
SELECT CONCAT('Hello', ' ', 'World');
SELECT CONCAT_WS(' ', 'Hello', 'World', NULL);  -- With separator, ignores NULL

-- Substring
SELECT SUBSTRING('Hello World', 1, 5);  -- 'Hello'
SELECT LEFT('Hello World', 5);          -- 'Hello'
SELECT RIGHT('Hello World', 5);         -- 'World'

-- Length
SELECT LEN('Hello');     -- 5 (chars, trims trailing spaces)
SELECT DATALENGTH('Hello');  -- 5 (bytes)

-- Case
SELECT UPPER('hello');
SELECT LOWER('HELLO');

-- Trim
SELECT TRIM('  hello  ');
SELECT LTRIM('  hello');
SELECT RTRIM('hello  ');
SELECT TRIM('x' FROM 'xxxhelloxxx');  -- 2017+

-- Replace
SELECT REPLACE('hello', 'l', 'L');
SELECT STUFF('Hello World', 7, 5, 'SQL');  -- 'Hello SQL'

-- Position
SELECT CHARINDEX('o', 'Hello World');      -- 5
SELECT CHARINDEX('o', 'Hello World', 6);   -- 8 (start from 6)

-- Padding
SELECT RIGHT('0000000000' + '123', 10);    -- '0000000123'
SELECT FORMAT(123, '0000000000');          -- 2012+

-- Split (2016+)
SELECT value FROM STRING_SPLIT('a,b,c', ',');

-- Aggregate strings (2017+)
SELECT STRING_AGG(name, ', ') FROM employees;
SELECT STRING_AGG(name, ', ') WITHIN GROUP (ORDER BY name) FROM employees;
sql
-- 字符串拼接
SELECT 'Hello' + ' ' + 'World';
SELECT CONCAT('Hello', ' ', 'World');
SELECT CONCAT_WS(' ', 'Hello', 'World', NULL);  -- 使用分隔符拼接,自动忽略NULL

-- 子字符串
SELECT SUBSTRING('Hello World', 1, 5);  -- 返回'Hello'
SELECT LEFT('Hello World', 5);          -- 返回'Hello'
SELECT RIGHT('Hello World', 5);         -- 返回'World'

-- 长度计算
SELECT LEN('Hello');     -- 返回5(字符数,自动忽略末尾空格)
SELECT DATALENGTH('Hello');  -- 返回5(字节数)

-- 大小写转换
SELECT UPPER('hello');
SELECT LOWER('HELLO');

-- 去除空格
SELECT TRIM('  hello  ');
SELECT LTRIM('  hello');
SELECT RTRIM('hello  ');
SELECT TRIM('x' FROM 'xxxhelloxxx');  -- 2017及以上版本支持

-- 替换字符串
SELECT REPLACE('hello', 'l', 'L');
SELECT STUFF('Hello World', 7, 5, 'SQL');  -- 返回'Hello SQL'

-- 查找字符串位置
SELECT CHARINDEX('o', 'Hello World');      -- 返回5
SELECT CHARINDEX('o', 'Hello World', 6);   -- 从第6位开始查找,返回8

-- 补位操作
SELECT RIGHT('0000000000' + '123', 10);    -- 返回'0000000123'
SELECT FORMAT(123, '0000000000');          -- 2012及以上版本支持

-- 拆分字符串(2016及以上版本)
SELECT value FROM STRING_SPLIT('a,b,c', ',');

-- 字符串聚合(2017及以上版本)
SELECT STRING_AGG(name, ', ') FROM employees;
SELECT STRING_AGG(name, ', ') WITHIN GROUP (ORDER BY name) FROM employees;

JSON Support

JSON支持

sql
-- JSON functions (2016+)
DECLARE @json NVARCHAR(MAX) = '{"name":"John","age":30,"address":{"city":"NYC"}}';

-- Extract values
SELECT JSON_VALUE(@json, '$.name');           -- 'John'
SELECT JSON_VALUE(@json, '$.address.city');   -- 'NYC'
SELECT JSON_QUERY(@json, '$.address');        -- '{"city":"NYC"}'

-- Check if valid JSON
SELECT ISJSON(@json);  -- 1

-- Modify JSON
SELECT JSON_MODIFY(@json, '$.age', 31);
SELECT JSON_MODIFY(@json, '$.email', 'john@example.com');

-- Parse JSON array
DECLARE @arr NVARCHAR(MAX) = '[{"id":1,"name":"A"},{"id":2,"name":"B"}]';
SELECT * FROM OPENJSON(@arr) WITH (id INT, name NVARCHAR(50));

-- Generate JSON
SELECT id, name, email
FROM employees
FOR JSON AUTO;  -- Auto-structure

SELECT id, name, email
FROM employees
FOR JSON PATH, ROOT('employees');  -- Custom structure
sql
-- JSON函数(2016及以上版本)
DECLARE @json NVARCHAR(MAX) = '{"name":"John","age":30,"address":{"city":"NYC"}}';

-- 提取JSON值
SELECT JSON_VALUE(@json, '$.name');           -- 返回'John'
SELECT JSON_VALUE(@json, '$.address.city');   -- 返回'NYC'
SELECT JSON_QUERY(@json, '$.address');        -- 返回'{"city":"NYC"}'

-- 检查是否为有效JSON
SELECT ISJSON(@json);  -- 有效返回1

-- 修改JSON
SELECT JSON_MODIFY(@json, '$.age', 31);
SELECT JSON_MODIFY(@json, '$.email', 'john@example.com');

-- 解析JSON数组
DECLARE @arr NVARCHAR(MAX) = '[{"id":1,"name":"A"},{"id":2,"name":"B"}]';
SELECT * FROM OPENJSON(@arr) WITH (id INT, name NVARCHAR(50));

-- 生成JSON
SELECT id, name, email
FROM employees
FOR JSON AUTO;  -- 自动生成结构

SELECT id, name, email
FROM employees
FOR JSON PATH, ROOT('employees');  -- 自定义结构

Index Types

索引类型

sql
-- Clustered index (one per table, defines physical order)
CREATE CLUSTERED INDEX IX_emp_id ON employees(id);

-- Non-clustered index
CREATE NONCLUSTERED INDEX IX_emp_email ON employees(email);

-- Unique index
CREATE UNIQUE INDEX IX_emp_email ON employees(email);

-- Composite index
CREATE INDEX IX_emp_dept_name ON employees(department_id, last_name);

-- Included columns (covering index)
CREATE INDEX IX_emp_email ON employees(email)
INCLUDE (first_name, last_name, phone);

-- Filtered index
CREATE INDEX IX_active_emp ON employees(email)
WHERE is_active = 1;

-- Columnstore index (analytics)
CREATE COLUMNSTORE INDEX IX_sales_cs ON sales(product_id, amount, sale_date);
-- Or clustered columnstore
CREATE CLUSTERED COLUMNSTORE INDEX IX_sales_ccs ON sales;

-- Full-text index
CREATE FULLTEXT CATALOG ft_catalog;
CREATE FULLTEXT INDEX ON documents(content) KEY INDEX PK_documents;
sql
-- 聚集索引(每个表仅一个,定义物理存储顺序)
CREATE CLUSTERED INDEX IX_emp_id ON employees(id);

-- 非聚集索引
CREATE NONCLUSTERED INDEX IX_emp_email ON employees(email);

-- 唯一索引
CREATE UNIQUE INDEX IX_emp_email ON employees(email);

-- 复合索引
CREATE INDEX IX_emp_dept_name ON employees(department_id, last_name);

-- 包含列索引(覆盖索引)
CREATE INDEX IX_emp_email ON employees(email)
INCLUDE (first_name, last_name, phone);

-- 筛选索引
CREATE INDEX IX_active_emp ON employees(email)
WHERE is_active = 1;

-- 列存储索引(用于分析场景)
CREATE COLUMNSTORE INDEX IX_sales_cs ON sales(product_id, amount, sale_date);
-- 或聚集列存储索引
CREATE CLUSTERED COLUMNSTORE INDEX IX_sales_ccs ON sales;

-- 全文索引
CREATE FULLTEXT CATALOG ft_catalog;
CREATE FULLTEXT INDEX ON documents(content) KEY INDEX PK_documents;

Table Partitioning

表分区

sql
-- 1. Create partition function
CREATE PARTITION FUNCTION pf_sales_date (DATE)
AS RANGE RIGHT FOR VALUES ('2022-01-01', '2023-01-01', '2024-01-01');

-- 2. Create partition scheme
CREATE PARTITION SCHEME ps_sales_date
AS PARTITION pf_sales_date
TO (fg_2021, fg_2022, fg_2023, fg_2024);

-- 3. Create partitioned table
CREATE TABLE sales (
    id INT IDENTITY(1,1),
    sale_date DATE,
    amount DECIMAL(10,2),
    CONSTRAINT PK_sales PRIMARY KEY (id, sale_date)
) ON ps_sales_date(sale_date);

-- View partitions
SELECT
    $PARTITION.pf_sales_date(sale_date) AS partition_number,
    COUNT(*) AS row_count
FROM sales
GROUP BY $PARTITION.pf_sales_date(sale_date);

-- Split partition (add new)
ALTER PARTITION SCHEME ps_sales_date NEXT USED fg_2025;
ALTER PARTITION FUNCTION pf_sales_date() SPLIT RANGE ('2025-01-01');

-- Merge partitions
ALTER PARTITION FUNCTION pf_sales_date() MERGE RANGE ('2022-01-01');

-- Switch partition (instant move)
ALTER TABLE sales SWITCH PARTITION 1 TO sales_archive;
sql
-- 1. 创建分区函数
CREATE PARTITION FUNCTION pf_sales_date (DATE)
AS RANGE RIGHT FOR VALUES ('2022-01-01', '2023-01-01', '2024-01-01');

-- 2. 创建分区方案
CREATE PARTITION SCHEME ps_sales_date
AS PARTITION pf_sales_date
TO (fg_2021, fg_2022, fg_2023, fg_2024);

-- 3. 创建分区表
CREATE TABLE sales (
    id INT IDENTITY(1,1),
    sale_date DATE,
    amount DECIMAL(10,2),
    CONSTRAINT PK_sales PRIMARY KEY (id, sale_date)
) ON ps_sales_date(sale_date);

-- 查看分区情况
SELECT
    $PARTITION.pf_sales_date(sale_date) AS partition_number,
    COUNT(*) AS row_count
FROM sales
GROUP BY $PARTITION.pf_sales_date(sale_date);

-- 拆分分区(新增分区)
ALTER PARTITION SCHEME ps_sales_date NEXT USED fg_2025;
ALTER PARTITION FUNCTION pf_sales_date() SPLIT RANGE ('2025-01-01');

-- 合并分区
ALTER PARTITION FUNCTION pf_sales_date() MERGE RANGE ('2022-01-01');

-- 切换分区(快速移动数据)
ALTER TABLE sales SWITCH PARTITION 1 TO sales_archive;

Temporal Tables (2016+)

时态表(2016及以上版本)

sql
-- Create temporal table
CREATE TABLE employees (
    id INT PRIMARY KEY,
    name NVARCHAR(100),
    salary DECIMAL(10,2),
    -- System time columns
    valid_from DATETIME2 GENERATED ALWAYS AS ROW START,
    valid_to DATETIME2 GENERATED ALWAYS AS ROW END,
    PERIOD FOR SYSTEM_TIME (valid_from, valid_to)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.employees_history));

-- Query historical data
SELECT * FROM employees FOR SYSTEM_TIME AS OF '2024-01-01';
SELECT * FROM employees FOR SYSTEM_TIME BETWEEN '2024-01-01' AND '2024-06-01';
SELECT * FROM employees FOR SYSTEM_TIME ALL;

-- Disable versioning for maintenance
ALTER TABLE employees SET (SYSTEM_VERSIONING = OFF);
-- ... maintenance ...
ALTER TABLE employees SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.employees_history));
sql
-- 创建时态表
CREATE TABLE employees (
    id INT PRIMARY KEY,
    name NVARCHAR(100),
    salary DECIMAL(10,2),
    -- 系统时间列
    valid_from DATETIME2 GENERATED ALWAYS AS ROW START,
    valid_to DATETIME2 GENERATED ALWAYS AS ROW END,
    PERIOD FOR SYSTEM_TIME (valid_from, valid_to)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.employees_history));

-- 查询历史数据
SELECT * FROM employees FOR SYSTEM_TIME AS OF '2024-01-01';
SELECT * FROM employees FOR SYSTEM_TIME BETWEEN '2024-01-01' AND '2024-06-01';
SELECT * FROM employees FOR SYSTEM_TIME ALL;

-- 为维护操作禁用版本控制
ALTER TABLE employees SET (SYSTEM_VERSIONING = OFF);
-- ... 执行维护操作 ...
ALTER TABLE employees SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.employees_history));

Common Table Expressions

通用表表达式(CTE)

sql
-- Basic CTE
;WITH emp_stats AS (
    SELECT department_id, COUNT(*) AS emp_count, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department_id
)
SELECT d.name, es.emp_count, es.avg_salary
FROM departments d
JOIN emp_stats es ON d.id = es.department_id;

-- Recursive CTE
;WITH hierarchy AS (
    -- Anchor
    SELECT id, name, manager_id, 0 AS level
    FROM employees WHERE manager_id IS NULL
    UNION ALL
    -- Recursive
    SELECT e.id, e.name, e.manager_id, h.level + 1
    FROM employees e
    JOIN hierarchy h ON e.manager_id = h.id
)
SELECT * FROM hierarchy OPTION (MAXRECURSION 100);
sql
-- 基础CTE
;WITH emp_stats AS (
    SELECT department_id, COUNT(*) AS emp_count, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department_id
)
SELECT d.name, es.emp_count, es.avg_salary
FROM departments d
JOIN emp_stats es ON d.id = es.department_id;

-- 递归CTE
;WITH hierarchy AS (
    -- 锚点查询
    SELECT id, name, manager_id, 0 AS level
    FROM employees WHERE manager_id IS NULL
    UNION ALL
    -- 递归查询
    SELECT e.id, e.name, e.manager_id, h.level + 1
    FROM employees e
    JOIN hierarchy h ON e.manager_id = h.id
)
SELECT * FROM hierarchy OPTION (MAXRECURSION 100);

Pagination

分页查询

sql
-- OFFSET-FETCH (2012+)
SELECT id, name, email
FROM employees
ORDER BY id
OFFSET 20 ROWS
FETCH NEXT 10 ROWS ONLY;

-- With variable
DECLARE @PageNum INT = 3, @PageSize INT = 10;
SELECT id, name, email
FROM employees
ORDER BY id
OFFSET (@PageNum - 1) * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY;

-- ROW_NUMBER (older method)
;WITH numbered AS (
    SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS rn
    FROM employees
)
SELECT * FROM numbered WHERE rn BETWEEN 21 AND 30;
sql
-- OFFSET-FETCH方式(2012及以上版本)
SELECT id, name, email
FROM employees
ORDER BY id
OFFSET 20 ROWS
FETCH NEXT 10 ROWS ONLY;

-- 结合变量使用
DECLARE @PageNum INT = 3, @PageSize INT = 10;
SELECT id, name, email
FROM employees
ORDER BY id
OFFSET (@PageNum - 1) * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY;

-- ROW_NUMBER方式(旧版本兼容)
;WITH numbered AS (
    SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS rn
    FROM employees
)
SELECT * FROM numbered WHERE rn BETWEEN 21 AND 30;

When NOT to Use This Skill

不适用该技能的场景

  • T-SQL programming - Use
    tsql
    skill for stored procedures, functions, triggers
  • PostgreSQL - Use
    postgresql
    skill for PostgreSQL-specific features
  • Oracle - Use
    oracle
    skill for Oracle features
  • Basic SQL - Use
    sql-fundamentals
    for ANSI SQL basics
  • T-SQL编程 - 存储过程、函数、触发器相关内容请使用
    tsql
    技能
  • PostgreSQL - PostgreSQL专属功能请使用
    postgresql
    技能
  • Oracle - Oracle专属功能请使用
    oracle
    技能
  • 基础SQL - ANSI SQL基础内容请使用
    sql-fundamentals
    技能

Anti-Patterns

反模式

Anti-PatternProblemSolution
Not using SET NOCOUNT ONNetwork overheadAdd to all stored procedures
Using cursorsSlow performanceUse set-based operations
Missing clustered indexHeap scansAdd clustered index
Not using INCLUDE in indexesKey lookupsUse covering indexes
Using deprecated TEXT/NTEXTCompatibility issuesUse VARCHAR(MAX)/NVARCHAR(MAX)
@@IDENTITY instead of SCOPE_IDENTITYWrong identity valueUse SCOPE_IDENTITY()
反模式问题解决方案
未使用SET NOCOUNT ON产生网络开销在所有存储过程中添加该语句
使用游标性能缓慢使用基于集合的操作替代
缺少聚集索引导致堆表扫描添加聚集索引
未在索引中使用INCLUDE产生键查找使用覆盖索引
使用已废弃的TEXT/NTEXT类型兼容性问题使用VARCHAR(MAX)/NVARCHAR(MAX)替代
使用@@IDENTITY而非SCOPE_IDENTITY可能获取错误的标识值使用SCOPE_IDENTITY()

Quick Troubleshooting

快速故障排查

ProblemDiagnosticFix
Slow queries
SET STATISTICS IO ON
Add indexes, check execution plan
Blocking
sp_who2
or Activity Monitor
Kill blocking process, optimize
DeadlocksExtended Events, trace flag 1222Consistent access order, shorter transactions
Identity issues
DBCC CHECKIDENT
Reseed or use SCOPE_IDENTITY
TempDB contentionCheck wait statsAdd TempDB files, optimize queries
问题诊断方法解决方式
查询缓慢执行
SET STATISTICS IO ON
添加索引,检查执行计划
阻塞问题使用
sp_who2
或活动监视器
终止阻塞进程,优化查询
死锁问题使用扩展事件、跟踪标志1222统一访问顺序,缩短事务时长
标识列异常执行
DBCC CHECKIDENT
重置种子或使用SCOPE_IDENTITY
TempDB争用检查等待统计信息添加TempDB文件,优化查询

Reference Documentation

参考文档

  • Data Types
  • Indexes
  • Partitioning
  • 数据类型
  • 索引
  • 分区