1. 为什么需要SQL Server语法速查手册
在数据库开发工作中,我们经常会遇到需要快速查询某个SQL语法细节的情况。比如突然记不清ALTER TABLE语句的具体写法,或者不确定窗口函数中PARTITION BY和ORDER BY的先后顺序。这时候如果手头有一份结构清晰、内容全面的语法速查手册,工作效率会大大提高。
我整理这份手册的初衷,就是希望能把SQL Server中最常用、最实用的语法集中在一起,按照开发场景分类整理,方便随时查阅。不同于官方文档的全面但冗长,这份手册更注重实战性,只收录实际工作中真正会用到的语法,并附上典型示例和注意事项。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. T-SQL基础语法速查
2.1 DDL语句
DDL(Data Definition Language)用于定义和管理数据库对象。以下是常用DDL语句:
sql复制-- 创建数据库
CREATE DATABASE MyDatabase
ON PRIMARY
(
NAME = MyDatabase_Data,
FILENAME = 'C:\Data\MyDatabase.mdf',
SIZE = 10MB,
MAXSIZE = 50MB,
FILEGROWTH = 5MB
)
LOG ON
(
NAME = MyDatabase_Log,
FILENAME = 'C:\Data\MyDatabase.ldf',
SIZE = 5MB,
MAXSIZE = 25MB,
FILEGROWTH = 5MB
);
-- 创建表
CREATE TABLE Employees (
EmployeeID INT PRIMARY KEY IDENTITY(1,1),
FirstName NVARCHAR(50) NOT NULL,
LastName NVARCHAR(50) NOT NULL,
HireDate DATE DEFAULT GETDATE(),
Salary DECIMAL(10,2) CHECK (Salary > 0),
DepartmentID INT FOREIGN KEY REFERENCES Departments(DepartmentID)
);
-- 修改表结构
ALTER TABLE Employees
ADD Email NVARCHAR(100) NULL;
ALTER TABLE Employees
ALTER COLUMN Email NVARCHAR(255);
ALTER TABLE Employees
DROP COLUMN Email;
注意:修改表结构在生产环境要谨慎,特别是删除列或修改数据类型可能导致数据丢失。
2.2 DML语句
DML(Data Manipulation Language)用于数据操作:
sql复制-- 插入数据
INSERT INTO Employees (FirstName, LastName, Salary, DepartmentID)
VALUES ('张', '三', 5000.00, 1),
('李', '四', 6000.00, 2);
-- 更新数据
UPDATE Employees
SET Salary = Salary * 1.1
WHERE DepartmentID = 1;
-- 删除数据
DELETE FROM Employees
WHERE EmployeeID = 5;
-- 合并数据(MERGE)
MERGE INTO TargetTable AS target
USING SourceTable AS source
ON target.ID = source.ID
WHEN MATCHED THEN
UPDATE SET target.Value = source.Value
WHEN NOT MATCHED THEN
INSERT (ID, Value) VALUES (source.ID, source.Value);
3. 查询语句进阶技巧
3.1 常用查询语法
sql复制-- 基础查询
SELECT FirstName, LastName, Salary
FROM Employees
WHERE DepartmentID = 1
ORDER BY Salary DESC;
-- 分组统计
SELECT DepartmentID, COUNT(*) AS EmployeeCount, AVG(Salary) AS AvgSalary
FROM Employees
GROUP BY DepartmentID
HAVING COUNT(*) > 5;
-- 多表连接
SELECT e.FirstName, e.LastName, d.DepartmentName
FROM Employees e
INNER JOIN Departments d ON e.DepartmentID = d.DepartmentID;
-- 子查询
SELECT FirstName, LastName
FROM Employees
WHERE Salary > (SELECT AVG(Salary) FROM Employees);
3.2 窗口函数
窗口函数是SQL Server中非常强大的功能:
sql复制-- 排名函数
SELECT
FirstName, LastName, Salary,
RANK() OVER (ORDER BY Salary DESC) AS SalaryRank,
DENSE_RANK() OVER (ORDER BY Salary DESC) AS DenseSalaryRank,
ROW_NUMBER() OVER (ORDER BY Salary DESC) AS RowNum
FROM Employees;
-- 分区计算
SELECT
DepartmentID, FirstName, LastName, Salary,
AVG(Salary) OVER (PARTITION BY DepartmentID) AS DeptAvgSalary,
Salary - AVG(Salary) OVER (PARTITION BY DepartmentID) AS DiffFromAvg
FROM Employees;
-- 移动平均
SELECT
OrderDate, SalesAmount,
AVG(SalesAmount) OVER (ORDER BY OrderDate ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS MovingAvg
FROM Sales;
4. 存储过程和函数
4.1 存储过程
sql复制CREATE PROCEDURE GetEmployeeByDepartment
@DepartmentID INT,
@MinSalary DECIMAL(10,2) = 0
AS
BEGIN
SET NOCOUNT ON;
SELECT FirstName, LastName, Salary
FROM Employees
WHERE DepartmentID = @DepartmentID
AND Salary >= @MinSalary
ORDER BY LastName, FirstName;
END;
-- 调用存储过程
EXEC GetEmployeeByDepartment @DepartmentID = 1, @MinSalary = 5000;
4.2 用户定义函数
sql复制-- 标量函数
CREATE FUNCTION dbo.GetFullName
(
@FirstName NVARCHAR(50),
@LastName NVARCHAR(50)
)
RETURNS NVARCHAR(101)
AS
BEGIN
RETURN @LastName + ' ' + @FirstName;
END;
-- 表值函数
CREATE FUNCTION dbo.GetEmployeesBySalaryRange
(
@MinSalary DECIMAL(10,2),
@MaxSalary DECIMAL(10,2)
)
RETURNS TABLE
AS
RETURN
(
SELECT EmployeeID, FirstName, LastName, Salary
FROM Employees
WHERE Salary BETWEEN @MinSalary AND @MaxSalary
);
5. 事务和错误处理
5.1 事务控制
sql复制BEGIN TRY
BEGIN TRANSACTION;
-- 业务操作
UPDATE Accounts SET Balance = Balance - 1000 WHERE AccountID = 1;
UPDATE Accounts SET Balance = Balance + 1000 WHERE AccountID = 2;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION;
-- 错误处理
DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE();
DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
DECLARE @ErrorState INT = ERROR_STATE();
RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
END CATCH;
5.2 常见错误处理模式
sql复制-- 检查存在性再操作
IF EXISTS (SELECT 1 FROM Employees WHERE EmployeeID = 10)
BEGIN
UPDATE Employees SET Salary = 8000 WHERE EmployeeID = 10;
END
ELSE
BEGIN
PRINT 'Employee not found';
END
-- 使用TRY_CONVERT避免转换错误
SELECT TRY_CONVERT(INT, 'ABC') AS ConversionResult; -- 返回NULL而不是报错
-- 使用TRY_PARSE处理日期
SELECT TRY_PARSE('2023-02-30' AS DATE) AS ValidDate; -- 返回NULL
6. 性能优化技巧
6.1 索引使用建议
sql复制-- 创建索引
CREATE INDEX IX_Employees_DepartmentID ON Employees(DepartmentID)
INCLUDE (Salary);
-- 查看索引使用情况
SELECT
OBJECT_NAME(i.object_id) AS TableName,
i.name AS IndexName,
s.user_seeks, s.user_scans, s.user_lookups,
s.user_updates
FROM sys.indexes i
LEFT JOIN sys.dm_db_index_usage_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
WHERE OBJECT_NAME(i.object_id) = 'Employees';
6.2 查询优化技巧
sql复制-- 使用EXISTS代替IN
SELECT *
FROM Orders o
WHERE EXISTS (
SELECT 1 FROM Customers c
WHERE c.CustomerID = o.CustomerID
AND c.Country = 'China'
);
-- 避免SELECT *
SELECT FirstName, LastName, DepartmentID
FROM Employees
WHERE DepartmentID = 1;
-- 使用表变量代替临时表
DECLARE @EmployeeList TABLE (EmployeeID INT);
INSERT INTO @EmployeeList
SELECT EmployeeID FROM Employees WHERE DepartmentID = 1;
SELECT e.* FROM Employees e
INNER JOIN @EmployeeList el ON e.EmployeeID = el.EmployeeID;
7. 高级特性
7.1 JSON支持
sql复制-- 查询结果转为JSON
SELECT EmployeeID, FirstName, LastName, Salary
FROM Employees
FOR JSON PATH;
-- 解析JSON数据
DECLARE @json NVARCHAR(MAX) = N'{
"EmployeeID": 1,
"FirstName": "张",
"LastName": "三",
"Salary": 5000.00
}';
SELECT *
FROM OPENJSON(@json)
WITH (
EmployeeID INT '$.EmployeeID',
FirstName NVARCHAR(50) '$.FirstName',
LastName NVARCHAR(50) '$.LastName',
Salary DECIMAL(10,2) '$.Salary'
);
7.2 时态表
sql复制-- 创建时态表
CREATE TABLE Employees_Temporal
(
EmployeeID INT PRIMARY KEY,
FirstName NVARCHAR(50) NOT NULL,
LastName NVARCHAR(50) NOT NULL,
ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START,
ValidTo DATETIME2 GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Employees_History));
-- 查询历史数据
SELECT * FROM Employees_Temporal
FOR SYSTEM_TIME BETWEEN '2023-01-01' AND '2023-02-01'
WHERE EmployeeID = 1;
8. 实用小技巧
8.1 动态SQL
sql复制DECLARE @TableName NVARCHAR(128) = 'Employees';
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'SELECT TOP 10 * FROM ' + QUOTENAME(@TableName);
EXEC sp_executesql @SQL;
8.2 常用系统函数
sql复制-- 获取当前日期时间
SELECT GETDATE() AS CurrentDateTime, SYSDATETIME() AS CurrentDateTimeHighPrecision;
-- 字符串处理
SELECT
CONCAT(FirstName, ' ', LastName) AS FullName,
LEFT(FirstName, 1) + LEFT(LastName, 1) AS Initials,
REPLACE(Email, '@company.com', '@newcompany.com') AS NewEmail
FROM Employees;
-- 数学计算
SELECT ROUND(Salary, 0) AS RoundedSalary, CEILING(Salary/1000)*1000 AS CeilingSalary
FROM Employees;
8.3 系统存储过程
sql复制-- 查看表结构
EXEC sp_help 'Employees';
-- 查看索引信息
EXEC sp_helpindex 'Employees';
-- 查看数据库空间使用
EXEC sp_spaceused;
9. 常见问题排查
9.1 连接问题
sql复制-- 查看当前连接
SELECT
session_id, login_time, host_name, program_name,
login_name, status
FROM sys.dm_exec_sessions
WHERE is_user_process = 1;
-- 终止连接
KILL 55; -- 替换为实际的session_id
9.2 性能问题
sql复制-- 查看长时间运行的查询
SELECT
session_id, start_time, status, command,
wait_type, wait_time, last_wait_type,
cpu_time, total_elapsed_time, reads, writes, logical_reads
FROM sys.dm_exec_requests
WHERE status = 'running';
-- 查看查询执行计划
SET SHOWPLAN_TEXT ON;
GO
SELECT * FROM Employees WHERE DepartmentID = 1;
GO
SET SHOWPLAN_TEXT OFF;
9.3 锁问题
sql复制-- 查看当前锁
SELECT
request_session_id,
resource_type,
request_mode,
resource_description,
request_status
FROM sys.dm_tran_locks;
-- 查看阻塞链
SELECT
blocking.session_id AS blocking_session_id,
blocked.session_id AS blocked_session_id,
wait.wait_type AS wait_type,
wait.wait_duration_ms AS wait_duration,
blocked.wait_resource AS blocked_resource
FROM sys.dm_exec_connections AS blocking
INNER JOIN sys.dm_exec_requests AS blocked ON blocking.session_id = blocked.blocking_session_id
INNER JOIN sys.dm_os_waiting_tasks AS wait ON blocked.session_id = wait.session_id;
10. 维护任务
10.1 备份与恢复
sql复制-- 完整备份
BACKUP DATABASE MyDatabase
TO DISK = 'C:\Backup\MyDatabase.bak'
WITH INIT, STATS = 10;
-- 差异备份
BACKUP DATABASE MyDatabase
TO DISK = 'C:\Backup\MyDatabase_Diff.bak'
WITH DIFFERENTIAL, STATS = 10;
-- 恢复数据库
RESTORE DATABASE MyDatabase
FROM DISK = 'C:\Backup\MyDatabase.bak'
WITH REPLACE, STATS = 10;
10.2 数据库维护
sql复制-- 更新统计信息
UPDATE STATISTICS Employees;
-- 重建索引
ALTER INDEX ALL ON Employees REBUILD;
-- 收缩数据库
DBCC SHRINKDATABASE(MyDatabase, 10); -- 10%空闲空间
