SQL 快速入门:题目单知识点精炼总结

最近刷了牛客网的 SQL 快速入门题,内容主要覆盖基础查询、条件筛选、聚合统计、多表连接、子查询、常用函数以及窗口函数。题目看似很多,但核心知识点比较集中。掌握下面这些语法,基本可以应对大部分入门和常见面试题。

说明:你提供的语雀页面目前需要登录,无法读取其中的"五十题"具体内容,下面的总结主要根据牛客公开的"SQL 快速入门"题单整理。

一、基础查询

最基本的查询语句由 SELECTFROM 组成。

复制代码
SELECT *
FROM user_profile;

查询指定列:

复制代码
SELECT device_id, gender, age
FROM user_profile;

* 表示查询全部列,但在实际开发中更推荐写出需要的字段,避免返回无用数据。

使用 DISTINCT 去重:

复制代码
SELECT DISTINCT university
FROM user_profile;

限制返回数量:

复制代码
SELECT *
FROM user_profile
LIMIT 5;

LIMIT 5 表示只返回前 5 行,也可以配合偏移量实现分页:

复制代码
SELECT *
FROM user_profile
LIMIT 10, 20;

表示跳过前 10 行,返回接下来的 20 行。

使用 AS 修改列名:

复制代码
SELECT
    device_id AS 用户编号,
    age AS 年龄
FROM user_profile;

AS 也可以给表设置别名:

复制代码
SELECT u.device_id, u.age
FROM user_profile AS u;

二、条件查询与排序

使用 WHERE 对数据进行筛选:

复制代码
SELECT *
FROM user_profile
WHERE university = '北京大学';

常见比较运算符有:

复制代码
=       等于
<> 或 != 不等于
>       大于
<       小于
>=      大于等于
<=      小于等于

例如查询年龄大于 24 岁的用户:

复制代码
SELECT *
FROM user_profile
WHERE age > 24;

查询年龄在 20 到 30 岁之间:

复制代码
SELECT *
FROM user_profile
WHERE age BETWEEN 20 AND 30;

BETWEEN 包含两个边界值。

多个条件可以使用 ANDOR

复制代码
SELECT *
FROM user_profile
WHERE age >= 20
  AND age <= 25
  AND gender = '男';

使用 IN 查询多个指定值:

复制代码
SELECT *
FROM user_profile
WHERE university IN ('北京大学', '复旦大学');

排除指定值:

复制代码
SELECT *
FROM user_profile
WHERE university NOT IN ('复旦大学');

判断空值时不能使用 = NULL,而应该使用 IS NULLIS NOT NULL

复制代码
SELECT *
FROM user_profile
WHERE age IS NULL;

SELECT *
FROM user_profile
WHERE age IS NOT NULL;

模糊查询使用 LIKE

复制代码
SELECT *
FROM user_profile
WHERE university LIKE '%北京%';

其中:

复制代码
% 代表任意长度的字符串
_ 代表一个字符

查询结果可以使用 ORDER BY 排序:

复制代码
SELECT *
FROM user_profile
ORDER BY age;

默认是升序排列,也可以明确写出 ASC

复制代码
ORDER BY age ASC;

降序排列使用 DESC

复制代码
SELECT *
FROM user_profile
ORDER BY age DESC;

多列排序时,先按照第一列排序,第一列相同时再按照第二列排序:

复制代码
SELECT *
FROM user_profile
ORDER BY university ASC, age DESC;

三、聚合函数与分组查询

SQL 中常见的聚合函数包括:

复制代码
COUNT()  统计数量
SUM()    求和
AVG()    平均值
MAX()    最大值
MIN()    最小值

统计用户数量:

复制代码
SELECT COUNT(*) AS user_count
FROM user_profile;

计算男性用户的平均 GPA:

复制代码
SELECT AVG(gpa) AS avg_gpa
FROM user_profile
WHERE gender = '男';

按照学校进行分组统计:

复制代码
SELECT
    university,
    COUNT(*) AS user_count
FROM user_profile
GROUP BY university;

GROUP BY 用于将相同字段值的数据划分到同一组。

统计每个学校的平均 GPA,并按照平均值降序排列:

复制代码
SELECT
    university,
    AVG(gpa) AS avg_gpa
FROM user_profile
GROUP BY university
ORDER BY avg_gpa DESC;

如果要对分组后的结果进行筛选,需要使用 HAVING,而不是 WHERE

复制代码
SELECT
    university,
    COUNT(*) AS user_count
FROM user_profile
GROUP BY university
HAVING COUNT(*) > 10;

两者的区别是:

复制代码
WHERE:分组前筛选原始数据
HAVING:分组后筛选统计结果

例如,查询年龄大于 20 岁且用户数量超过 5 人的学校:

复制代码
SELECT
    university,
    COUNT(*) AS user_count
FROM user_profile
WHERE age > 20
GROUP BY university
HAVING COUNT(*) > 5;

四、多表查询与连接

实际项目中的数据通常存储在多张表中。例如:

复制代码
user_profile       用户信息表
question_practice_detail  刷题记录表
question_detail    题目信息表

使用 JOIN 可以连接多张表。

查询用户及其刷题记录:

复制代码
SELECT
    u.device_id,
    u.university,
    q.question_id,
    q.result
FROM user_profile AS u
JOIN question_practice_detail AS q
    ON u.device_id = q.device_id;

JOIN 默认表示内连接,只保留两张表中能够匹配的数据。

左连接使用 LEFT JOIN

复制代码
SELECT
    u.device_id,
    q.question_id
FROM user_profile AS u
LEFT JOIN question_practice_detail AS q
    ON u.device_id = q.device_id;

左连接会保留左表的全部数据,即使右表中没有对应记录,也会显示为 NULL

常见连接类型:

复制代码
INNER JOIN:只保留匹配成功的数据
LEFT JOIN:保留左表全部数据
RIGHT JOIN:保留右表全部数据

统计每个学校答过题的用户数量:

复制代码
SELECT
    u.university,
    COUNT(DISTINCT q.device_id) AS user_count
FROM user_profile AS u
JOIN question_practice_detail AS q
    ON u.device_id = q.device_id
GROUP BY u.university;

这里使用 COUNT(DISTINCT device_id),避免同一用户刷多道题时被重复统计。

五、子查询与组合查询

子查询就是将一个查询结果作为另一个查询的条件。

查询 GPA 高于平均 GPA 的用户:

复制代码
SELECT *
FROM user_profile
WHERE gpa > (
    SELECT AVG(gpa)
    FROM user_profile
);

子查询也可以放在 FROM 后面,作为临时表:

复制代码
SELECT university, avg_gpa
FROM (
    SELECT
        university,
        AVG(gpa) AS avg_gpa
    FROM user_profile
    GROUP BY university
) AS t
WHERE avg_gpa > 3.0;

UNION 可以合并两个查询结果,并自动去重:

复制代码
SELECT device_id
FROM user_profile
WHERE university = '山东大学'

UNION

SELECT device_id
FROM user_profile
WHERE gender = '男';

如果不需要去重,可以使用 UNION ALL,性能通常更好:

复制代码
SELECT device_id
FROM user_profile
WHERE university = '山东大学'

UNION ALL

SELECT device_id
FROM user_profile
WHERE gender = '男';

六、常用条件函数

CASE WHEN 是 SQL 中非常重要的条件表达式。

统计 25 岁以上和以下的用户数量:

复制代码
SELECT
    SUM(CASE WHEN age >= 25 THEN 1 ELSE 0 END) AS over_25,
    SUM(CASE WHEN age < 25 THEN 1 ELSE 0 END) AS under_25
FROM user_profile;

也可以将年龄划分为不同区间:

复制代码
SELECT
    device_id,
    age,
    CASE
        WHEN age < 20 THEN '20岁以下'
        WHEN age BETWEEN 20 AND 25 THEN '20-25岁'
        ELSE '25岁以上'
    END AS age_group
FROM user_profile;

常见的空值处理函数是 IFNULL()

复制代码
SELECT
    device_id,
    IFNULL(gpa, 0) AS gpa
FROM user_profile;

如果 GPA 为空,就显示为 0。

七、日期函数

日期题在 SQL 面试中出现频率很高。常用函数包括:

复制代码
YEAR(date)       获取年份
MONTH(date)      获取月份
DAY(date)        获取日期
DATE(date)       提取日期部分
DATEDIFF(a, b)   计算日期差

统计 8 月每天的刷题数量:

复制代码
SELECT
    DATE(date) AS practice_day,
    COUNT(*) AS question_count
FROM question_practice_detail
WHERE MONTH(date) = 8
GROUP BY DATE(date)
ORDER BY practice_day;

也可以使用日期范围筛选:

复制代码
WHERE date >= '2021-08-01'
  AND date < '2021-09-01'

这种写法比对日期使用 LIKE 更准确,也更容易使用索引。

八、字符串函数与正则表达式

常见字符串函数包括:

复制代码
LENGTH()       字符串长度
SUBSTRING()    截取字符串
LEFT()         从左侧截取
RIGHT()        从右侧截取
CONCAT()       拼接字符串
LOWER()        转小写
UPPER()        转大写

例如从 URL 中提取用户名:

复制代码
SELECT
    SUBSTRING_INDEX(
        SUBSTRING_INDEX(blog_url, '/', -1),
        '.',
        1
    ) AS username
FROM user_profile;

SUBSTRING_INDEX(str, delimiter, count) 可以按照指定分隔符截取字符串。

正则表达式使用 REGEXP

复制代码
SELECT *
FROM user_profile
WHERE phone REGEXP '^1[3-9][0-9]{9}$';

这个表达式用于匹配 11 位手机号码,且第一位为 1,第二位为 3 到 9。

九、窗口函数

窗口函数可以在不改变原始行数的情况下进行分组统计,常用于排名、组内比较和累计计算。

查找每个学校 GPA 最低的用户:

复制代码
SELECT *
FROM (
    SELECT
        device_id,
        university,
        gpa,
        ROW_NUMBER() OVER (
            PARTITION BY university
            ORDER BY gpa
        ) AS rn
    FROM user_profile
) AS t
WHERE rn = 1;

PARTITION BY university 表示按照学校分组,ORDER BY gpa 表示组内按照 GPA 升序排列。

常见排名函数:

复制代码
ROW_NUMBER():每行都有唯一排名
RANK():并列时排名相同,后面的排名会跳过
DENSE_RANK():并列时排名相同,但后续排名不跳过

计算累计利润:

复制代码
SELECT
    date,
    profit,
    SUM(profit) OVER (
        ORDER BY date
        ROWS BETWEEN UNBOUNDED PRECEDING
        AND CURRENT ROW
    ) AS total_profit
FROM daily_profit;

计算每个用户相对于前一天的数据,可以使用 LAG()

复制代码
SELECT
    device_id,
    date,
    LAG(date) OVER (
        PARTITION BY device_id
        ORDER BY date
    ) AS previous_date
FROM question_practice_detail;

十、刷题时容易出错的地方

第一,空值不能使用 = NULL 判断,必须使用 IS NULL

第二,聚合函数和普通字段一起查询时,普通字段通常需要出现在 GROUP BY 中。

第三,WHERE 不能直接筛选聚合结果,聚合结果需要使用 HAVING

第四,多表连接时要确认连接条件,否则容易产生笛卡尔积,导致统计数量严重偏大。

第五,统计用户数量时,要根据题意判断是否需要 DISTINCT

第六,日期筛选尽量使用范围条件,例如:

复制代码
WHERE date >= '2021-08-01'
  AND date < '2021-09-01'

第七,窗口函数不能直接写在 WHERE 中,通常需要先放在子查询中,再在外层筛选。

总结

牛客 SQL 快速入门题主要围绕以下知识点展开:

复制代码
SELECT、WHERE、ORDER BY、LIMIT
DISTINCT、LIKE、IN、BETWEEN
IS NULL、聚合函数、GROUP BY、HAVING
JOIN、LEFT JOIN、子查询、UNION
CASE WHEN、IFNULL、日期函数、字符串函数
REGEXP、窗口函数、排名、累计统计

刷题时可以按照"先筛选,再分组,后排序"的思路分析:

复制代码
FROM/JOIN
→ WHERE
→ GROUP BY
→ HAVING
→ SELECT
→ ORDER BY
→ LIMIT

掌握这些常用语法后,再结合具体业务理解题目要求,SQL 查询题基本就能形成稳定的解题思路。真正需要重点练习的,不是死记每道题的答案,而是判断题目到底属于筛选、分组、连接、子查询还是窗口函数问题。

相关推荐
AI人工智能+电脑小能手22 分钟前
大白话说Java设计模式-40-备忘录模式(业务实战篇)
java·设计模式·事务回滚·备忘录模式·状态保存·spring transactional·购物车快照
SimonKing23 分钟前
白嫖国产多模态大模型:商汤 SenseNova 接入指南
java·后端·程序员
小江的记录本23 分钟前
【ORM框架】MyBatis核心原理、ORM思想、MyBatis vs JPA
java·数据库·后端·spring·spring cloud·oracle·mybatis
zgl_2005377928 分钟前
源代码:跨数据库通用“字段级”数据血缘解析与图形化(2/3:标注信息的拆解、检验、保存)
大数据·数据库·数据仓库·sql·数据挖掘·etl·嵌入式实时数据库
_明月34 分钟前
汇川技术股份有限公司面试--Java外包岗
java·面试·职场和发展
BD_Marathon35 分钟前
Hadoop常用端口号
java·大数据·hadoop
青石路42 分钟前
好好的OceanBase官方驱动你不用,非要用第三方驱动,ArrayIndexOutOfBoundsException了吧
java·后端
BugShare43 分钟前
告别来回切换,Navop:一站式整合数据库、SSH、终端与 AI 的开发运维工作台
运维·数据库·ssh
长谷深风11144 分钟前
读懂 MCP:能力、传输与多 Server 连接
java·大数据·ai·ai agent·mcp·streamable http·agent设计