基础查询
基础查询是 SQL 的根基。所有的复杂查询都是由简单的 SELECT、WHERE、ORDER BY 等基础语句组合而成。掌握好基础查询,不仅是应对面试的第一步,更是写出高质量 SQL 的前提。
SELECT 语句的核心概念
SELECT 语句是 SQL 中最基本的查询语句,用于从数据库表中检索数据。理解 SELECT 的执行过程对于编写正确的查询至关重要。
基本语法:
SELECT [DISTINCT] 列名1, 列名2, ...
FROM 表名
[WHERE 条件]
[ORDER BY 列名 [ASC|DESC]]
[LIMIT 数量];
关键点理解:
- 列选择:
SELECT后面指定要查询的列,使用*表示所有列 - 去重:
DISTINCT关键字用于去除重复行 - 别名:使用
AS关键字为列或表指定别名,提高可读性 - 条件过滤:
WHERE子句用于筛选满足条件的行 - 排序:
ORDER BY用于对结果排序,默认升序(ASC) - 限制数量:
LIMIT用于限制返回的行数
1757. 可回收且低脂的产品 (Recyclable and Low Fat Products)
题目描述
你有一张 Products 表,包含产品的信息:
product_id: 产品 ID,这是该表的主键。low_fats: 枚举类型 ('Y', 'N'),表示产品是否低脂。recyclable: 枚举类型 ('Y', 'N'),表示产品是否可回收。
请编写一个解决方案,找出所有 既是低脂又是可回收 的产品 ID。
解题思路
这道题考查的是多条件组合过滤,需要同时满足两个条件。
分析过程:
- 理解需求:需要找出同时满足"低脂"和"可回收"的产品,这是一个"且"的关系
- 确定条件:
low_fats = 'Y'表示低脂recyclable = 'Y'表示可回收
- 组合条件:使用
AND操作符连接两个条件
为什么用 AND 而不是 OR?
这是一个常见的混淆点。AND 表示"同时满足",OR 表示"满足其一即可"。题目要求"既是...又是...",这明确表示两个条件都要满足,所以使用 AND。
SQL 实现 (MySQL)
-- 方法:使用 AND 连接多个条件
SELECT product_id
FROM Products
WHERE low_fats = 'Y' AND recyclable = 'Y';
代码解析:
SELECT product_id:只需要返回产品 ID,不需要其他字段FROM Products:指定查询的表WHERE low_fats = 'Y' AND recyclable = 'Y':过滤条件,两个字段的值都必须是 'Y'
584. 寻找用户推荐人 (Find Customer Referee)
题目描述
Customer 表保存了每一位客户的 ID、姓名以及推荐他们的人 ID:
id: 客户 ID,主键。name: 客户姓名。referee_id: 推荐人的 ID。
请编写一个解决方案,查询所有 不是 由 ID 为 2 的客户推荐的客户姓名。
解题思路
这道题的核心考点是 NULL 值的处理,这是 SQL 中最容易出错的地方之一。
理解 SQL 的三值逻辑:
在 SQL 中,逻辑表达式的结果不仅有 TRUE 和 FALSE,还有第三个值 UNKNOWN(未知)。当涉及到 NULL 值时,就会产生 UNKNOWN。
为什么 referee_id != 2 不够?
当 referee_id 为 NULL 时:
NULL != 2的结果是UNKNOWN,不是TRUEWHERE子句只保留结果为TRUE的行- 因此
NULL != 2的记录会被过滤掉
解决方案:
需要显式处理 NULL 的情况,有两种常见方法:
- 使用
OR referee_id IS NULL - 使用
IFNULL(referee_id, 0) != 2(将 NULL 替换为非 2 的值)
SQL 实现 (MySQL)
-- 方法一:显式处理 NULL(推荐)
SELECT name
FROM Customer
WHERE referee_id != 2 OR referee_id IS NULL;
-- 方法二:使用 IFNULL 函数
SELECT name
FROM Customer
WHERE IFNULL(referee_id, 0) != 2;
代码解析:
referee_id != 2:找出推荐人不是 2 的客户OR referee_id IS NULL:额外包含没有推荐人的客户(referee_id 为 NULL)- 这两个条件是"或"的关系,满足任一即可
关于 NULL 的重要规则:
-- 这些都是错误的 NULL 判断方式
WHERE referee_id = NULL -- 错误!永远不会返回结果
WHERE referee_id != NULL -- 错误!永远不会返回结果
-- 正确的 NULL 判断方式
WHERE referee_id IS NULL -- 判断是否为 NULL
WHERE referee_id IS NOT NULL -- 判断是否不为 NULL
595. 大的国家 (Big Countries)
题目描述
World 表记录了各个国家的面积、人口等信息:
name: 国家名称。population: 人口数量。area: 面积。
一个国家如果满足以下 任意一个 条件,则被认为是 "大的国家":
- 它的面积至少为 300 万平方千米(3,000,000 km²)。
- 它的人口至少为 2500 万(25,000,000)。
编写解决方案,查询所有 "大的国家" 的 国家名称、人口 和 面积。
解题思路
这道题考查的是多条件"或"关系的处理。
分析过程:
- 理解需求:满足面积大或人口多任一条件即可,这是"或"的关系
- 确定条件:
area >= 3000000population >= 25000000
- 组合条件:使用
OR操作符
AND vs OR 的选择:
| 场景 | 关键词 | 操作符 |
|---|---|---|
| 同时满足多个条件 | "既是...又是..."、"并且" | AND |
| 满足任一条件即可 | "或者"、"至少满足一个" | OR |
SQL 实现 (MySQL)
-- 方法:使用 OR 连接多个条件
SELECT name, population, area
FROM World
WHERE area >= 3000000 OR population >= 25000000;
-- 方法二:使用 UNION(性能可能较差,但逻辑清晰)
SELECT name, population, area FROM World WHERE area >= 3000000
UNION
SELECT name, population, area FROM World WHERE population >= 25000000;
代码解析:
SELECT name, population, area:选择需要返回的三个字段WHERE area >= 3000000 OR population >= 25000000:满足任一条件即可- 使用
OR时注意条件的顺序对性能有影响,通常将过滤掉更多行的条件放前面
1148. 文章浏览 I (Article Views I)
题目描述
Views 表记录了每篇文章的浏览记录:
article_id: 文章 ID。author_id: 作者 ID。viewer_id: 浏览者 ID。view_date: 浏览日期。
注意:该表中存在同一个浏览者多次浏览同一篇文章的情况。 请编写一个解决方案,找出所有 浏览过自己文章 的作者。结果需要按作者 ID 升序排列。
解题思路
这道题考查三个知识点:条件匹配、去重、排序。
分析过程:
- 条件匹配:什么时候算"浏览自己的文章"?当
author_id = viewer_id时 - 去重:一个作者可能多次浏览自己的文章,需要使用
DISTINCT - 排序:按作者 ID 升序排列
为什么需要 DISTINCT?
假设某个作者浏览了自己文章 3 次,不使用 DISTINCT 的话,结果中会出现 3 次该作者的 ID。题目要求找出"所有浏览过自己文章的作者",每个作者只需要出现一次。
SQL 实现 (MySQL)
-- 方法:条件匹配 + 去重 + 排序
SELECT DISTINCT author_id AS id
FROM Views
WHERE author_id = viewer_id
ORDER BY id ASC;
代码解析:
DISTINCT:去除重复的作者 IDauthor_id AS id:为列指定别名,使结果更清晰WHERE author_id = viewer_id:找出浏览自己文章的记录ORDER BY id ASC:按 ID 升序排序(ASC 可省略,默认就是升序)
1683. 无效的推文 (Invalid Tweets)
题目描述
Tweets 表保存了每一条推文的 ID 和内容:
tweet_id: 推文 ID,主键。content: 推文内容。
查询所有 无效的推文 的 ID。如果推文内容中的 字符数 严格大于 15,则认为它是无效的。
解题思路
这道题考查的是字符串长度函数的使用。
关键区别:LENGTH vs CHAR_LENGTH
在 MySQL 中,有两个常用的字符串长度函数:
| 函数 | 说明 | 示例 |
|---|---|---|
LENGTH() | 返回字符串的字节数 | LENGTH('你好') → 6(UTF-8 编码每个中文 3 字节) |
CHAR_LENGTH() | 返回字符串的字符数 | CHAR_LENGTH('你好') → 2 |
为什么题目要用 CHAR_LENGTH?
题目说的是"字符数",而不是"字节数"。对于包含中文、表情等字符的推文:
LENGTH()会返回字节数,可能大于实际字符数CHAR_LENGTH()返回真正的字符数,符合题意
不同数据库的字符串长度函数:
| 数据库 | 字符数函数 | 字节数函数 |
|---|---|---|
| MySQL | CHAR_LENGTH() | LENGTH() |
| PostgreSQL | CHAR_LENGTH() 或 LENGTH() | OCTET_LENGTH() |
| SQL Server | LEN() | DATALENGTH() |
| Oracle | LENGTH() | LENGTHB() |
SQL 实现 (MySQL)
-- 方法:使用 CHAR_LENGTH 计算字符数
SELECT tweet_id
FROM Tweets
WHERE CHAR_LENGTH(content) > 15;
代码解析:
CHAR_LENGTH(content):计算推文内容的字符数> 15:严格大于 15 的推文被认为无效
扩展:如果推文为 NULL 怎么办?
如果 content 可能为 NULL,需要额外处理:
SELECT tweet_id
FROM Tweets
WHERE content IS NOT NULL AND CHAR_LENGTH(content) > 15;
知识点总结
WHERE 子句常用操作符
| 类型 | 操作符 | 说明 | 示例 |
|---|---|---|---|
| 比较 | =, <>, !=, >, <, >=, <= | 值比较 | WHERE age > 18 |
| 范围 | BETWEEN ... AND ... | 范围查询 | WHERE age BETWEEN 18 AND 30 |
| 列表 | IN (...) | 列表匹配 | WHERE id IN (1, 2, 3) |
| 模糊 | LIKE | 模糊匹配 | WHERE name LIKE '张%' |
| 空值 | IS NULL, IS NOT NULL | NULL 判断 | WHERE bonus IS NULL |
| 逻辑 | AND, OR, NOT | 逻辑组合 | WHERE a > 1 AND b < 10 |
LIKE 通配符
| 通配符 | 说明 | 示例 |
|---|---|---|
% | 匹配任意多个字符 | LIKE '张%' 匹配所有姓张的 |
_ | 匹配单个字符 | LIKE '_明' 匹配第二个字是明的 |
常见错误
- NULL 判断错误:使用
=或!=判断 NULL - AND/OR 混淆:不清楚题目要求"且"还是"或"
- 忘记去重:需要唯一值时忘记使用
DISTINCT - 长度函数误用:字符数和字节数概念混淆