跳到主要内容

基础查询

基础查询是 SQL 的根基。所有的复杂查询都是由简单的 SELECTWHEREORDER BY 等基础语句组合而成。掌握好基础查询,不仅是应对面试的第一步,更是写出高质量 SQL 的前提。

SELECT 语句的核心概念

SELECT 语句是 SQL 中最基本的查询语句,用于从数据库表中检索数据。理解 SELECT 的执行过程对于编写正确的查询至关重要。

基本语法

SELECT [DISTINCT] 列名1, 列名2, ...
FROM 表名
[WHERE 条件]
[ORDER BY 列名 [ASC|DESC]]
[LIMIT 数量];

关键点理解

  1. 列选择SELECT 后面指定要查询的列,使用 * 表示所有列
  2. 去重DISTINCT 关键字用于去除重复行
  3. 别名:使用 AS 关键字为列或表指定别名,提高可读性
  4. 条件过滤WHERE 子句用于筛选满足条件的行
  5. 排序ORDER BY 用于对结果排序,默认升序(ASC)
  6. 限制数量LIMIT 用于限制返回的行数

1757. 可回收且低脂的产品 (Recyclable and Low Fat Products)

题目描述

你有一张 Products 表,包含产品的信息:

  • product_id: 产品 ID,这是该表的主键。
  • low_fats: 枚举类型 ('Y', 'N'),表示产品是否低脂。
  • recyclable: 枚举类型 ('Y', 'N'),表示产品是否可回收。

请编写一个解决方案,找出所有 既是低脂又是可回收 的产品 ID。

解题思路

这道题考查的是多条件组合过滤,需要同时满足两个条件。

分析过程

  1. 理解需求:需要找出同时满足"低脂"和"可回收"的产品,这是一个"且"的关系
  2. 确定条件
    • low_fats = 'Y' 表示低脂
    • recyclable = 'Y' 表示可回收
  3. 组合条件:使用 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 中,逻辑表达式的结果不仅有 TRUEFALSE,还有第三个值 UNKNOWN(未知)。当涉及到 NULL 值时,就会产生 UNKNOWN

为什么 referee_id != 2 不够?

referee_idNULL 时:

  • NULL != 2 的结果是 UNKNOWN,不是 TRUE
  • WHERE 子句只保留结果为 TRUE 的行
  • 因此 NULL != 2 的记录会被过滤掉

解决方案

需要显式处理 NULL 的情况,有两种常见方法:

  1. 使用 OR referee_id IS NULL
  2. 使用 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: 面积。

一个国家如果满足以下 任意一个 条件,则被认为是 "大的国家":

  1. 它的面积至少为 300 万平方千米(3,000,000 km²)。
  2. 它的人口至少为 2500 万(25,000,000)。

编写解决方案,查询所有 "大的国家" 的 国家名称人口面积

解题思路

这道题考查的是多条件"或"关系的处理。

分析过程

  1. 理解需求:满足面积大或人口多任一条件即可,这是"或"的关系
  2. 确定条件
    • area >= 3000000
    • population >= 25000000
  3. 组合条件:使用 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 升序排列。

解题思路

这道题考查三个知识点:条件匹配去重排序

分析过程

  1. 条件匹配:什么时候算"浏览自己的文章"?当 author_id = viewer_id
  2. 去重:一个作者可能多次浏览自己的文章,需要使用 DISTINCT
  3. 排序:按作者 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:去除重复的作者 ID
  • author_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() 返回真正的字符数,符合题意

不同数据库的字符串长度函数

数据库字符数函数字节数函数
MySQLCHAR_LENGTH()LENGTH()
PostgreSQLCHAR_LENGTH()LENGTH()OCTET_LENGTH()
SQL ServerLEN()DATALENGTH()
OracleLENGTH()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 NULLNULL 判断WHERE bonus IS NULL
逻辑AND, OR, NOT逻辑组合WHERE a > 1 AND b < 10

LIKE 通配符

通配符说明示例
%匹配任意多个字符LIKE '张%' 匹配所有姓张的
_匹配单个字符LIKE '_明' 匹配第二个字是明的

常见错误

  1. NULL 判断错误:使用 =!= 判断 NULL
  2. AND/OR 混淆:不清楚题目要求"且"还是"或"
  3. 忘记去重:需要唯一值时忘记使用 DISTINCT
  4. 长度函数误用:字符数和字节数概念混淆