SQL Server基础查询 #
一、SELECT语句概述 #
1.1 基本语法 #
sql
SELECT [ALL | DISTINCT] column_list
[INTO new_table]
FROM table_source
[WHERE search_condition]
[GROUP BY group_by_expression]
[HAVING search_condition]
[ORDER BY order_expression [ASC | DESC]]
[OFFSET offset_row_count {ROW | ROWS}
[FETCH {FIRST | NEXT} fetch_row_count {ROW | ROWS} ONLY]];
1.2 示例表结构 #
sql
-- 创建示例表
CREATE TABLE users (
id INT PRIMARY KEY IDENTITY(1,1),
name NVARCHAR(50),
email VARCHAR(100),
age INT,
status BIT DEFAULT 1,
salary DECIMAL(10,2),
department_id INT,
created_at DATETIME2 DEFAULT SYSDATETIME()
);
INSERT INTO users (name, email, age, status, salary, department_id) VALUES
('John', 'john@example.com', 25, 1, 5000.00, 1),
('Jane', 'jane@example.com', 30, 1, 6000.00, 1),
('Bob', 'bob@example.com', 28, 0, 4500.00, 2),
('Alice', 'alice@example.com', 22, 1, 4000.00, 2),
('Charlie', 'charlie@example.com', 35, 0, 7000.00, 1),
('David', 'david@example.com', 32, 1, 5500.00, 2),
('Eve', 'eve@example.com', 27, 1, 4800.00, 1);
二、基本查询 #
2.1 查询所有列 #
sql
-- 查询所有列
SELECT * FROM users;
-- 结果
id | name | email | age | status | salary | department_id | created_at
---|---------|--------------------|-----|--------|---------|---------------|--------------------
1 | John | john@example.com | 25 | 1 | 5000.00 | 1 | 2024-01-15 10:00:00
2 | Jane | jane@example.com | 30 | 1 | 6000.00 | 1 | 2024-01-15 11:00:00
...
2.2 查询指定列 #
sql
-- 查询指定列
SELECT name, age, email FROM users;
-- 结果
name | age | email
--------|-----|--------------------
John | 25 | john@example.com
Jane | 30 | jane@example.com
...
2.3 列别名 #
sql
-- 使用AS关键字
SELECT
name AS user_name,
age AS user_age,
email AS user_email
FROM users;
-- 省略AS关键字
SELECT name user_name, age user_age FROM users;
-- 使用引号(包含空格或特殊字符)
SELECT name AS '用户名', age AS '年龄' FROM users;
-- 使用等号(SQL Server特有)
SELECT
user_name = name,
user_age = age
FROM users;
2.4 表别名 #
sql
-- 使用表别名
SELECT u.name, u.age, u.email
FROM users AS u;
-- 省略AS
SELECT u.name, u.age FROM users u;
-- 多表查询时使用别名
SELECT u.name, d.department_name
FROM users u
INNER JOIN departments d ON u.department_id = d.id;
三、DISTINCT去重 #
3.1 基本用法 #
sql
-- 查询所有年龄(包含重复)
SELECT age FROM users;
-- 查询不重复的年龄
SELECT DISTINCT age FROM users;
-- 结果
age
----
22
25
27
28
30
32
35
3.2 多列去重 #
sql
-- 多列组合去重
SELECT DISTINCT age, status FROM users;
-- 结果
age | status
----|--------
22 | 1
25 | 1
27 | 1
28 | 0
30 | 1
32 | 1
35 | 0
3.3 统计去重数量 #
sql
-- 统计不同年龄的数量
SELECT COUNT(DISTINCT age) AS distinct_ages FROM users;
-- 统计不同年龄和状态组合的数量
SELECT COUNT(DISTINCT CONCAT(age, '-', status)) AS distinct_combinations
FROM users;
四、WHERE条件 #
4.1 比较运算符 #
sql
-- 等于
SELECT * FROM users WHERE age = 25;
-- 不等于
SELECT * FROM users WHERE age != 25;
SELECT * FROM users WHERE age <> 25;
-- 大于
SELECT * FROM users WHERE age > 25;
-- 小于
SELECT * FROM users WHERE age < 25;
-- 大于等于
SELECT * FROM users WHERE age >= 25;
-- 小于等于
SELECT * FROM users WHERE age <= 25;
4.2 逻辑运算符 #
sql
-- AND:同时满足多个条件
SELECT * FROM users WHERE age > 25 AND status = 1;
-- OR:满足任一条件
SELECT * FROM users WHERE age < 25 OR age > 30;
-- NOT:取反
SELECT * FROM users WHERE NOT status = 0;
-- 组合使用(注意优先级)
SELECT * FROM users
WHERE (age < 25 OR age > 30) AND status = 1;
4.3 BETWEEN…AND #
sql
-- 范围查询(包含边界)
SELECT * FROM users WHERE age BETWEEN 25 AND 30;
-- 等价于
SELECT * FROM users WHERE age >= 25 AND age <= 30;
-- NOT BETWEEN
SELECT * FROM users WHERE age NOT BETWEEN 25 AND 30;
-- 日期范围
SELECT * FROM users
WHERE created_at BETWEEN '2024-01-01' AND '2024-01-31';
4.4 IN #
sql
-- 列表匹配
SELECT * FROM users WHERE age IN (25, 30, 35);
-- 等价于
SELECT * FROM users WHERE age = 25 OR age = 30 OR age = 35;
-- NOT IN
SELECT * FROM users WHERE age NOT IN (25, 30, 35);
-- 子查询
SELECT * FROM users WHERE department_id IN (
SELECT id FROM departments WHERE location = 'Beijing'
);
4.5 LIKE模糊匹配 #
sql
-- % 匹配任意多个字符
SELECT * FROM users WHERE name LIKE 'J%'; -- 以J开头
SELECT * FROM users WHERE name LIKE '%n'; -- 以n结尾
SELECT * FROM users WHERE name LIKE '%oh%'; -- 包含oh
-- _ 匹配单个字符
SELECT * FROM users WHERE name LIKE 'J_hn'; -- John
-- [] 匹配字符集
SELECT * FROM users WHERE name LIKE '[ABC]%'; -- 以A、B或C开头
SELECT * FROM users WHERE name LIKE '[A-D]%'; -- 以A到D开头
-- [^] 不匹配字符集
SELECT * FROM users WHERE name LIKE '[^ABC]%'; -- 不以A、B或C开头
-- NOT LIKE
SELECT * FROM users WHERE name NOT LIKE 'J%';
-- ESCAPE转义
SELECT * FROM users WHERE email LIKE '%@%' ESCAPE '@';
4.6 NULL值判断 #
sql
-- IS NULL
SELECT * FROM users WHERE email IS NULL;
-- IS NOT NULL
SELECT * FROM users WHERE email IS NOT NULL;
-- 错误写法
SELECT * FROM users WHERE email = NULL; -- 不会返回结果
SELECT * FROM users WHERE email != NULL; -- 不会返回结果
五、ORDER BY排序 #
5.1 升序排序 #
sql
-- 默认升序(ASC)
SELECT * FROM users ORDER BY age;
SELECT * FROM users ORDER BY age ASC;
5.2 降序排序 #
sql
-- 降序(DESC)
SELECT * FROM users ORDER BY age DESC;
5.3 多列排序 #
sql
-- 先按status排序,再按age排序
SELECT * FROM users ORDER BY status ASC, age DESC;
-- 结果
id | name | age | status
---|---------|-----|--------
2 | Jane | 30 | 1
6 | David | 32 | 1
1 | John | 25 | 1
7 | Eve | 27 | 1
4 | Alice | 22 | 1
5 | Charlie | 35 | 0
3 | Bob | 28 | 0
5.4 按表达式排序 #
sql
-- 按计算结果排序
SELECT name, age, age * 2 AS double_age
FROM users
ORDER BY double_age;
-- 按函数结果排序
SELECT * FROM users ORDER BY LEN(name);
-- 按列位置排序
SELECT name, age FROM users ORDER BY 2; -- 按第二列(age)排序
5.5 自定义排序 #
sql
-- 使用CASE WHEN
SELECT * FROM users
ORDER BY CASE status
WHEN 1 THEN 1
WHEN 0 THEN 2
ELSE 3
END;
-- 使用CHARINDEX
SELECT * FROM users
ORDER BY CHARINDEX(name, 'John,Jane,Bob');
5.6 NULL值排序 #
sql
-- NULL值排在最后
SELECT * FROM users ORDER BY email DESC;
-- NULL值排在最前(SQL Server 2022+)
SELECT * FROM users ORDER BY email NULLS FIRST;
-- 使用ISNULL处理
SELECT * FROM users ORDER BY ISNULL(email, 'zzz');
六、TOP分页 #
6.1 TOP限制 #
sql
-- 返回前3条
SELECT TOP 3 * FROM users;
-- 使用百分比
SELECT TOP 50 PERCENT * FROM users;
-- WITH TIES(包含并列值)
SELECT TOP 3 WITH TIES * FROM users ORDER BY salary DESC;
-- 结果可能超过3条,因为salary相同的都会返回
6.2 OFFSET FETCH分页 #
sql
-- SQL Server 2012+ 推荐分页方式
-- OFFSET offset ROWS FETCH NEXT count ROWS ONLY
-- 第1页(每页3条)
SELECT * FROM users
ORDER BY id
OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY;
-- 第2页
SELECT * FROM users
ORDER BY id
OFFSET 3 ROWS FETCH NEXT 3 ROWS ONLY;
-- 第3页
SELECT * FROM users
ORDER BY id
OFFSET 6 ROWS FETCH NEXT 3 ROWS ONLY;
6.3 分页公式 #
sql
-- 第n页,每页m条
-- offset = (n - 1) * m
DECLARE @page INT = 2;
DECLARE @pageSize INT = 3;
SELECT * FROM users
ORDER BY id
OFFSET (@page - 1) * @pageSize ROWS
FETCH NEXT @pageSize ROWS ONLY;
6.4 使用ROW_NUMBER分页 #
sql
-- 传统分页方式(SQL Server 2005+)
WITH numbered_users AS (
SELECT
*,
ROW_NUMBER() OVER (ORDER BY id) AS row_num
FROM users
)
SELECT * FROM numbered_users
WHERE row_num BETWEEN 4 AND 6; -- 第2页,每页3条
七、聚合函数 #
7.1 常用聚合函数 #
| 函数 | 说明 |
|---|---|
| COUNT() | 计数 |
| SUM() | 求和 |
| AVG() | 平均值 |
| MAX() | 最大值 |
| MIN() | 最小值 |
| STDEV() | 标准差 |
| VAR() | 方差 |
7.2 COUNT函数 #
sql
-- 统计行数
SELECT COUNT(*) AS total FROM users;
-- 统计非NULL值数量
SELECT COUNT(email) AS email_count FROM users;
-- 统计不重复值的数量
SELECT COUNT(DISTINCT age) AS distinct_ages FROM users;
7.3 SUM函数 #
sql
-- 求和
SELECT SUM(salary) AS total_salary FROM users;
-- 条件求和
SELECT SUM(CASE WHEN status = 1 THEN salary ELSE 0 END) AS active_salary
FROM users;
7.4 AVG函数 #
sql
-- 平均值
SELECT AVG(salary) AS avg_salary FROM users;
-- 保留小数位
SELECT ROUND(AVG(salary), 2) AS avg_salary FROM users;
-- 条件平均
SELECT AVG(CASE WHEN status = 1 THEN salary END) AS avg_active_salary
FROM users;
7.5 MAX和MIN函数 #
sql
-- 最大值
SELECT MAX(salary) AS max_salary FROM users;
-- 最小值
SELECT MIN(salary) AS min_salary FROM users;
-- 同时获取
SELECT
MAX(salary) AS max_salary,
MIN(salary) AS min_salary,
MAX(salary) - MIN(salary) AS salary_range
FROM users;
7.6 组合使用 #
sql
SELECT
COUNT(*) AS total,
SUM(salary) AS total_salary,
AVG(salary) AS avg_salary,
MAX(salary) AS max_salary,
MIN(salary) AS min_salary,
STDEV(salary) AS salary_stdev
FROM users;
八、GROUP BY分组 #
8.1 基本分组 #
sql
-- 按状态分组统计
SELECT status, COUNT(*) AS count
FROM users
GROUP BY status;
-- 结果
status | count
-------|-------
0 | 2
1 | 5
8.2 多列分组 #
sql
-- 按多列分组
SELECT
department_id,
status,
COUNT(*) AS count,
AVG(salary) AS avg_salary
FROM users
GROUP BY department_id, status;
8.3 GROUP BY与聚合函数 #
sql
SELECT
department_id,
COUNT(*) AS employee_count,
SUM(salary) AS total_salary,
AVG(salary) AS avg_salary,
MAX(salary) AS max_salary,
MIN(salary) AS min_salary
FROM users
GROUP BY department_id;
8.4 GROUPING SETS #
sql
-- 多个分组集合
SELECT
department_id,
status,
COUNT(*) AS count,
SUM(salary) AS total_salary
FROM users
GROUP BY GROUPING SETS (
(department_id, status),
(department_id),
(status),
()
);
-- 等价于多个GROUP BY UNION ALL
8.5 ROLLUP和CUBE #
sql
-- ROLLUP:层次分组
SELECT
department_id,
status,
COUNT(*) AS count
FROM users
GROUP BY ROLLUP (department_id, status);
-- CUBE:所有组合
SELECT
department_id,
status,
COUNT(*) AS count
FROM users
GROUP BY CUBE (department_id, status);
九、HAVING过滤 #
9.1 HAVING与WHERE区别 #
sql
-- WHERE:过滤行,在分组前执行
SELECT status, COUNT(*) AS count
FROM users
WHERE age > 25
GROUP BY status;
-- HAVING:过滤分组,在分组后执行
SELECT status, COUNT(*) AS count
FROM users
GROUP BY status
HAVING COUNT(*) > 1;
9.2 HAVING使用聚合函数 #
sql
-- 筛选平均工资大于5000的部门
SELECT department_id, AVG(salary) AS avg_salary
FROM users
GROUP BY department_id
HAVING AVG(salary) > 5000;
-- 筛选人数大于2的部门
SELECT department_id, COUNT(*) AS count
FROM users
GROUP BY department_id
HAVING COUNT(*) > 2;
9.3 组合使用 #
sql
SELECT
department_id,
COUNT(*) AS count,
AVG(salary) AS avg_salary
FROM users
WHERE age >= 20
GROUP BY department_id
HAVING COUNT(*) > 1 AND AVG(salary) > 4500
ORDER BY avg_salary DESC;
十、SELECT执行顺序 #
10.1 完整语法 #
sql
SELECT DISTINCT column_list
INTO new_table
FROM table_source
JOIN another_table ON condition
WHERE row_condition
GROUP BY column_list
HAVING group_condition
ORDER BY column_list
OFFSET offset ROWS FETCH NEXT count ROWS ONLY;
10.2 执行顺序 #
text
1. FROM → 确定数据来源
2. JOIN → 连接表
3. ON → 连接条件
4. WHERE → 过滤行
5. GROUP BY → 分组
6. HAVING → 过滤分组
7. SELECT → 选择列
8. DISTINCT → 去重
9. ORDER BY → 排序
10. OFFSET/FETCH → 分页
10.3 示例说明 #
sql
SELECT department_id, COUNT(*) AS count, AVG(salary) AS avg_salary
FROM users
WHERE age >= 20
GROUP BY department_id
HAVING count > 1
ORDER BY avg_salary DESC
OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY;
-- 执行顺序:
-- 1. FROM users → 获取users表数据
-- 2. WHERE age >= 20 → 过滤年龄>=20的行
-- 3. GROUP BY department_id → 按department_id分组
-- 4. HAVING count > 1 → 过滤分组
-- 5. SELECT ... → 选择列并计算聚合
-- 6. ORDER BY avg_salary → 排序
-- 7. OFFSET/FETCH → 分页
十一、查询提示 #
11.1 锁提示 #
sql
-- NOLOCK(脏读)
SELECT * FROM users WITH (NOLOCK);
-- UPDLOCK(更新锁)
SELECT * FROM users WITH (UPDLOCK) WHERE id = 1;
-- XLOCK(排他锁)
SELECT * FROM users WITH (XLOCK) WHERE id = 1;
11.2 索引提示 #
sql
-- 强制使用索引
SELECT * FROM users WITH (INDEX(ix_users_email))
WHERE email = 'john@example.com';
-- 强制扫描
SELECT * FROM users WITH (INDEX(0));
十二、总结 #
查询要点:
| 子句 | 说明 | 示例 |
|---|---|---|
| SELECT | 选择列 | SELECT name, age |
| FROM | 指定表 | FROM users |
| WHERE | 过滤行 | WHERE age > 20 |
| GROUP BY | 分组 | GROUP BY status |
| HAVING | 过滤分组 | HAVING COUNT(*) > 1 |
| ORDER BY | 排序 | ORDER BY age DESC |
| OFFSET/FETCH | 分页 | OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY |
最佳实践:
- 只查询需要的列,避免SELECT *
- 使用索引优化WHERE条件
- 大表查询使用TOP或分页
- 合理使用聚合函数和分组
- 使用OFFSET FETCH替代ROW_NUMBER分页
下一步,让我们学习高级查询!
最后更新:2026-03-27