news 2026/10/6 8:58:52

SQL查询入门:从SELECT到WHERE、排序与分页的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SQL查询入门:从SELECT到WHERE、排序与分页的完整指南

查数据这件事,说难不难,说简单也不简单。我见过不少刚接触数据库的朋友,建表、插数据都挺利索,一到写查询语句就卡壳,要么忘了加条件把全表捞出来,要么条件写错查出来一堆不对的东西。这篇是零基础系列的第八讲,前面咱们已经聊过安装、建库、建表、插入数据这些基础操作,今天就把最常用的查询语句一次讲透,学完你就能自己写SELECT查想要的数据了。

1. 项目概述:查询在数据库里的地位

1.1 这讲要解决什么问题

数据库的本质就是存数据和取数据,存了半天取不出来,或者取出来的不是自己想要的,前面所有操作都白搭。查询(SELECT)就是“取数据”的手段,也是日常开发里出现频率最高的一类SQL语句。CRUD四个操作里,增删改加起来都没查用得多。

这篇文章的核心目标是:让完全没写过SQL的读者,掌握基础查询的完整套路。我会从最简单的“把整张表捞出来看一眼”开始,一步步讲到条件筛选、排序、去重、限量取数,最后用一个完整的实操案例把知识点串起来。学完之后,面对“查一下成绩在80分以上的学生”“按时间倒序看最近10条记录”这类需求,你能顺手写出对应的SQL,而不是到处复制粘贴再瞎改。

1.2 SELECT的查询思路

SELECT语句的书写顺序和执行顺序是两个不同的东西,这个点很多人学了很久才反应过来。书写顺序是 SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY → LIMIT,一眼看上去很规整。但真正执行的时候,数据库是先定位到 FROM 后面的那张表,然后根据 WHERE 条件过滤掉不要的行,再做后续的排序、分组等操作,最后才决定 SELECT 后面要展示哪些列。

理解这个顺序非常重要。举个例子,你想查“名字叫张三的学生”,SQL写成了 SELECT 姓名 FROM 学生表 WHERE 姓名 = '张三',看起来没问题。但如果你以为数据库是先按 SELECT 把“姓名”这一列取出来再过滤,后面学 JOIN、子查询的时候就会越绕越晕。先有数据集合,后有列展示,这个观念建议现在就建立起来。

提示:零基础学查询,先别急着背全部语法。把“查哪张表、过滤什么条件、展示哪些列”这三个问题想清楚,SQL自然就写出来了。

2. 核心语法拆解:从最简单的SELECT开始

2.1 查整表和指定列

最简单的一条查询,就是不带任何条件把整张表的数据全部捞出来。语法长这样:

SELECT * FROM 表名;

星号(*)代表“所有列”。这条语句在数据量小的时候用起来特别爽,刚建完表想看看到底存了什么,一行命令全出来了。但我要提醒一句:生产环境里尽量不要用 SELECT *,原因有两个。第一,如果表有几十个字段,而你只需要其中两三个,把全部字段查出来会白白消耗网络带宽和数据库资源;第二,代码里用 SELECT * 一旦表结构变更,程序里拿到的字段可能对不上,排查起来非常痛苦。自己本地学习随便查,线上代码一定老老实实写列名。

指定列查询的写法就是 SELECT 后面列出你要的列名,用逗号分隔:

SELECT id, name, score FROM student;

这条语句和上面的区别在于,数据库只返回 id、name、score 这三列,其他字段一概不管。列的顺序是按你 SELECT 后面写的顺序来的,不是按表结构里的顺序。这一点可以用来调整展示逻辑,比如你想把成绩列放在名字前面,直接交换写就行了。

还有一个经常被忽略的小技巧:查询时给列起别名。别名的英文关键字是 AS,中文场景下用得很频繁:

SELECT id AS 学号, name AS 姓名, score AS 成绩 FROM student;

给列起别名之后,查询结果的头一行就会显示中文别名,比直接看英文列名直观得多。这个操作在实际开发里也很常见,尤其是数据要给前端展示,或者要导出报表的时候,列名直接变成人能看懂的标题,省去后处理。

2.2 条件过滤WHERE怎么用

光会查全表远远不够,真实需求永远是“给我看看某一部分数据”。这部分数据怎么界定?靠 WHERE 子句。

WHERE 后面跟的是过滤条件,只有满足条件的行才会出现在结果里。它的核心逻辑和“筛子”一模一样:数据库把表里的每一行数据拿过来,按条件判断,放行或拦截。

最基础的过滤是等值比较。比如查学号等于1001的学生:

SELECT * FROM student WHERE id = 1001;

这里要重点提一下等号的使用。在SQL里,判断两个值相等用的是单个等号(=),不是编程语言里的双等号(==)。这是新手最容易踩的坑之一,心里想着比较,手上一不小心写成两个等号,直接报语法错误。

除了等于,还有一整套比较运算符,用一个小表格列清楚:

运算符含义示例说明
=等于WHERE age = 20完全匹配某个值
!= 或 <>不等于WHERE age != 20排除某个值,两种写法都对
>大于WHERE score > 60注意不含等于
<小于WHERE score < 60注意不含等于
>=大于等于WHERE score >= 60含边界值
<=小于等于WHERE score <= 60含边界值

这六个运算符是最基础的,覆盖了绝大多数过滤需求。比如“查不及格的学生”就是 WHERE score < 60,“查非北京籍学生”就是 WHERE city != '北京'。

当你有多个条件要同时满足的时候,就需要用到逻辑运算符。最常见的是三个:AND(且)、OR(或)、NOT(非)。AND 表示前后两个条件都得成立,OR 表示满足其中一个就行,NOT 表示取反。组合起来可以写非常精确的过滤条件:

-- 查成绩大于60且小于90的学生 SELECT * FROM student WHERE score > 60 AND score < 90; -- 查班级为1班或者是女生 SELECT * FROM student WHERE class_id = 1 OR gender = '女'; -- 查不在北京市的学生 SELECT * FROM student WHERE NOT city = '北京';

用 AND 和 OR 组合多个条件时,有个非常经典的坑:优先级问题。AND 的优先级高于 OR,也就是说数据库会先处理 AND 两边的条件,再处理 OR。如果你想把 OR 的两部分作为一个整体,必须加括号:

-- 正确写法:查1班或2班的所有女生 SELECT * FROM student WHERE gender = '女' AND (class_id = 1 OR class_id = 2); -- 错误写法:查出来的是全体女生,加上1班的男生,完全不对 SELECT * FROM student WHERE gender = '女' AND class_id = 1 OR class_id = 2;

这种错误特别隐蔽,因为语句能正常执行、不报错,但结果就是不对。我的建议是:多条件组合的时候,不管有没有必要性,给每个逻辑组合都加上括号,既安全又清晰,别人读代码也省力。

2.3 模糊匹配与区间查询的实用技巧

精确匹配虽然常用,但现实需求里“模糊查一下”的情况更常见。比如你想找姓“张”的同学,不可能把所有张姓的名字都列出来再用等号匹配,这时候就要用 LIKE 模糊匹配。

LIKE 配合两个通配符使用,一个是百分号(%),代表任意长度的任意字符;一个是下划线(_),代表单个任意字符。我举个例子你就明白区别了:

-- 查所有姓张的学生:张后面跟什么都可以 SELECT * FROM student WHERE name LIKE '张%'; -- 查姓张且名字总共两个字的:张后面只能跟一个字 SELECT * FROM student WHERE name LIKE '张_'; -- 查名字里带“伟”的学生,不管伟在第几个位置 SELECT * FROM student WHERE name LIKE '%伟%';

百分号放的位置不同,效果完全不同。'张%' 是“开头必须是张”,'%伟%' 是“中间或者开头结尾有伟都行”,'%龙' 是“结尾必须是龙”。这是模糊匹配里最值得动手实践的三个模式,建议自己建个小表反复试几遍,把位置和结果的关系彻底搞清楚。

除了模糊匹配,区间查询也经常碰到。“查价格在100到200之间的商品”“查日期在某个月内的订单”——这类需求用比较运算符加 AND 能写,但有更简洁的写法:BETWEEN AND。

-- 等价写法一:WHERE score >= 60 AND score <= 90 -- 等价写法二:BETWEEN 是包含边界值的 SELECT * FROM student WHERE score BETWEEN 60 AND 90;

注意 BETWEEN 是包含两端边界值的,上面的写法等价于 >= 60 AND <= 90。如果你想排除边界,比如只要60到90之间不含60和90,就不能用 BETWEEN,得老老实实写成 score > 60 AND score < 90。

还有一个常用的 IN 关键字。当你需要匹配一组值中的任意一个,比如“查北京、上海、广州三个城市的学生”,用 OR 写是三个条件串起来,又长又容易漏括号。IN 写法则非常清爽:

SELECT * FROM student WHERE city IN ('北京', '上海', '广州');

这个写法的效果等同于 city='北京' OR city='上海' OR city='广州',但可读性和扩展性好太多了。如果以后要加一个城市,直接在括号里加一个值就行,不用改整个条件结构。

3. 排序、去重与限量:让结果真正可读

3.1 ORDER BY排序的细节

查询出来的数据默认是按照存储顺序排列的,说人话就是“乱序”——你无法预测它按什么规则排。想要让结果按某个字段从大到小或者从小到大排列,就要用 ORDER BY。

排序的关键字是 ORDER BY,后面跟列名,再加上排序方向:ASC(ascending,升序,从小到大)或者 DESC(descending,降序,从大到小)。注意,ASC 可以省略,默认就是升序;DESC 必须明确写出来,不写的话数据库就给你按升序排。

-- 按成绩从小到大排序(升序) SELECT * FROM student ORDER BY score ASC; -- 按成绩从大到小排序(降序) SELECT * FROM student ORDER BY score DESC;

排序还可以指定多个列,规则是“先按第一个列排,如果第一个列值相同,再按第二个列排”。比如先按班级排,同一个班级内再按成绩从高到低:

SELECT * FROM student ORDER BY class_id ASC, score DESC;

这条语句的逻辑是:先把所有学生按班级从小到大排好,同一个班级里的学生按成绩从高到低排。多列排序在真实场景里用得非常频繁,“先按某个维度分组,组内再按另一个维度排序”这种需求到处都是。

有个容易忽略但实际很常见的需求:按中文排序。默认情况下,MySQL对中文字符串排序用的是字符编码的顺序,不是拼音顺序。如果你非要按拼音排,得额外指定排序规则(collation),这里不展开。对零基础来说,只需要知道“中文字段排序结果可能不是你想要的拼音顺序,需要另做处理”就足够了,真遇到这个问题再查资料。

3.2 DISTINCT去重

查询结果里经常会有重复值。比如你想知道“学生表里都来自哪些城市”,直接用 SELECT city FROM student 会把每个学生的城市都列一遍,出现几十个北京、几十个上海,完全没法看。这时候就要用 DISTINCT 去重。

SELECT DISTINCT city FROM student;

这条语句会把城市字段里的重复值合并,北京只显示一次,上海只显示一次。注意,DISTINCT 修饰的是它后面所有列的组合,不是只修饰第一个列。比如:

SELECT DISTINCT class_id, city FROM student;

这里去重的是“班级+城市”这个组合。只有当两条记录的 class_id 和 city 完全相同,才会被合并成一条。如果你只想对 class_id 去重,又想把 city 也显示出来,用 DISTINCT 是做不到的,这属于更高级的 GROUP BY 处理范畴,零基础阶段先清楚这个限定就行。

还有一个零基础容易踩的坑:DISTINCT 和 ORDER BY 一起用的时候,排序的字段必须出现在 SELECT 的列表里。比如:

-- 这样写可以,city在SELECT里 SELECT DISTINCT city FROM student ORDER BY city DESC; -- 这样写会报错或表现异常,因为age没在SELECT里 SELECT DISTINCT city FROM student ORDER BY age DESC;

背后的原因是,去重之后 city 相同的记录已经被合并了,age 这个字段到底取哪一条完全不确定,数据库不允许这种语义模糊的操作。

3.3 LIMIT取前N条

数据量大起来之后,“想看看表里有什么”不能一页全捞出来,得只取前几条。LIMIT 就是干这个的。

LIMIT 有两种常见用法。第一种是数字参数,取前N条:

-- 取前10条记录 SELECT * FROM student LIMIT 10;

第二种是双参数,实现分页效果:第一个参数是偏移量(从哪里开始),第二个参数是取多少条。偏移量从0开始计数,0代表第一条。

-- 从第6条开始取10条,也就是第6到第15条 SELECT * FROM student LIMIT 5, 10;

这里有个零基础特别容易算错的点:LIMIT 5, 10 不是跳过5条再取10条吗?实际上它跳过了前5条记录,从第6条开始取,取10条。如果你要实现常见的分页公式,每页显示10条,查第3页的数据:

  • 第1页:LIMIT 0, 10(跳过0条,取10条,即第1-10条)
  • 第2页:LIMIT 10, 10(跳过10条,取10条,即第11-20条)
  • 第3页:LIMIT 20, 10(跳过20条,取10条,即第21-30条)

规律就是:偏移量 = (页码 - 1) × 每页条数。这个公式建议抄在小本子上,后面做分页功能会反复用。

LIMIT 和 ORDER BY 的组合是最经典的高频搭配:“按时间倒序取最近10条记录”:

SELECT * FROM student ORDER BY create_time DESC LIMIT 10;

这条语句的执行逻辑是:先把所有记录按时间从新到旧排好,然后取排在最前面的10条。非常简单直观,但执行效率在大表上会有问题,因为要先全表排序再取前N条。零基础阶段先不用关心性能,知道这个组合能实现“取最大的几个”这个需求就够了。

注意:LIMIT 的偏移量如果大于表里的记录总数,不会报错,只是返回空结果集。比如表里有5条数据,你写 LIMIT 10, 10,返回的就是空表。

4. 实操案例:从建表到查询一次跑通

4.1 准备测试数据

讲再多理论都不如亲手跑一遍。下面我带大家从头到尾建一张成绩表,插入几条测试数据,然后跑各种查询。先把环境准备一下:假设你已经能在MySQL命令行或者图形化工具里执行SQL语句了。

第一步,建一张学生的考试成绩表:

CREATE TABLE student_score ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20), class_id INT, gender VARCHAR(4), score INT, city VARCHAR(20), create_time DATETIME );

建完表之后插入几条测试数据:

INSERT INTO student_score (name, class_id, gender, score, city, create_time) VALUES ('张伟', 1, '男', 85, '北京', '2024-01-05 08:30:00'), ('李娜', 1, '女', 92, '上海', '2024-01-05 09:00:00'), ('王强', 2, '男', 78, '北京', '2024-01-06 10:00:00'), ('刘敏', 2, '女', 65, '广州', '2024-01-07 11:30:00'), ('陈晨', 1, '男', 59, '上海', '2024-01-08 14:00:00'), ('杨静', 3, '女', 88, '深圳', '2024-01-09 16:20:00'), ('赵磊', 3, '男', 73, '北京', '2024-01-10 09:10:00'), ('孙丽', 2, '女', 96, '广州', '2024-01-11 10:45:00');

插完之后先跑一条最基础的查询确认数据进去了没有:

SELECT * FROM student_score;

这时候你看到的应该是8条完整的记录,每一条的所有字段都在。第一遍学到这里,强烈建议养成“插入后先查一遍”的习惯,后面所有查询操作都是建立在这个表之上的,确保数据正确是前提。

4.2 完成常用查询需求

数据准备好了,接下来就直接上手。假设产品经理一口气提了6个查询需求,我们逐个实现,把前面讲的知识点全部用上。

需求一:查所有成绩大于等于80分的学生,只需要姓名和成绩两列。

SELECT name, score FROM student_score WHERE score >= 80;

需求二:查1班或者2班的女学生。这个需求用到了 AND 和括号的组合,注意括号不能少。

SELECT * FROM student_score WHERE gender = '女' AND (class_id = 1 OR class_id = 2);

需求三:查所有姓“张”、“王”或“孙”的学生,用模糊匹配加 IN 组合处理。先看一下每个人名的姓氏分布:张伟、王强、孙丽共三个人符合要求。

SELECT * FROM student_score WHERE name LIKE '张%' OR name LIKE '王%' OR name LIKE '孙%';

需求四:查成绩在60到90之间的学生,按成绩从高到低排序。

SELECT * FROM student_score WHERE score BETWEEN 60 AND 90 ORDER BY score DESC;

这里执行结果应该包含张伟85、王强78、刘敏65、赵磊73四个人,不包含李娜92(超过90)也不包含陈晨59(低于60),因为 BETWEEN 是包含边界的。

需求五:统计所有学生来自哪些城市,去掉重复值。

SELECT DISTINCT city FROM student_score;

需求六:查成绩最高的前三条记录。

SELECT * FROM student_score ORDER BY score DESC LIMIT 3;

跑完这6个需求,你会发现每个查询本质上都是“选哪张表、用什么条件过滤、按什么顺序排、取多少条”。把需求翻译成这套逻辑,写SQL就没那么神秘了。

5. 常见问题与排查速查

5.1 查询结果不对怎么排查

查询写完了,结果不对,这几乎是每一位初学者每天都会遇到的事。结果不对通常分两种情况:报错了,或者没报错但数据不对。第二种更让人头疼,因为调起来没头绪。

先说“没报错但数据不对”。最常见的根因是条件写错了方向,比如大于写成了小于,等于写成了不等于。我的排查习惯是先看 WHERE 条到底过滤了什么,把条件单独拎出来验证。你可以把 SELECT 后面的列改成 *,看看返回的每一条记录是不是真的满足条件。比如查成绩大于等于80,出来的记录里有一条 score 是70,那多半是条件写错了,或者数据本身有更新但你没注意到。

第二个根因是 AND 和 OR 的优先级问题,这个在前面已经反复强调过。一旦发现查询结果比预期多或者比预期少,先检查条件里的括号有没有加对。比如预期是“1班或2班的女学生”,结果查出了大批1班的男生和2班的女学生,十有八九是缺了括号。

第三个根因是 NULL 值,这个是零基础最容易忽视的点。NULL 在SQL里表示“没有值”,它不是空字符串,也不是数字0。如果你用 score = NULL 去查询,一条结果都查不出来,因为 NULL 不能和任何值做等值比较。正确写法是 IS NULL 或 IS NOT NULL:

-- 正确:查没有填写成绩的学生 SELECT * FROM student_score WHERE score IS NULL; -- 错误:查不到任何结果,因为NULL无法用等号比较 SELECT * FROM student_score WHERE score = NULL;

这一点多说一嘴:设计表的时候尽量给字段设定 DEFAULT 值,而不是放任 NULL。比如成绩字段默认给0,城市字段默认给空字符串,这样查询和理解都会省很多麻烦。

5.2 错误信息怎么看

MySQL报错会给你错误码和错误信息,但很多零基础学员一看到红色报错就慌,其实大部分错误都是小问题。常见的几种错误整理成表格,直接对照查:

错误现象常见原因解决方法
ERROR 1064 (42000) SQL语法错误语句拼写错误、关键字写错、少了逗号或括号仔细检查整条语句,逐个词对照学习资料
ERROR 1054 (42S22) Unknown column列名写错,表里根本没这个字段用 DESC 表名 查看实际字段名
ERROR 1146 (42S02) Table doesn't exist表名写错,尤其容易忽略大小写确认表名拼写,注意数据库上下文
中文都显示为问号客户端字符集不对执行 SET NAMES utf8mb4; 再查询

排查语法错误有个笨但有效的方法:如果你用的是命令行,一条查询语句出错了,把语句拆开一段一段执行。先只写 SELECT * FROM 表名,通过了再加 WHERE,每加一段就验证一次,出错的点一下子就缩小了。

还有一个容易被忽略的问题:关键字冲突。如果你的列名或者表名恰好和MySQL的保留字相同,比如你有一个字段叫 order(订单),直接查 SELECT order FROM ... 会报错。解决办法是给这个字段加上反引号:

-- 反引号包裹关键字 SELECT `order` FROM 订单表;

建表的时候尽量避开 order、group、select、where 这类保留字当字段名,不然后面每一次查询都得加反引号,非常烦人。

最后分享一个实战里特别有效的小习惯:在查询语句前加 EXPLAIN 关键字可以查看数据库是如何执行这条语句的,但零基础阶段用不上,知道有这么回事就行。现阶段只需要做到:一看出错信息,二查字段名,三检查括号和引号,90%的问题都能自己解决。SQL这个东西,写到后来拼的其实就是细心和熟练度。把一篇基础查询掌握扎实,后面学聚合函数、多表连接就会顺畅得多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/6 8:58:16

SQL数据过滤从入门到实战:WHERE、NULL、索引与安全防护全解析

说实话&#xff0c;写了这么多年SQL&#xff0c;数据过滤是我见过最容易被低估的话题。很多人觉得WHERE后面加条件谁不会&#xff0c;可真到线上调慢查询、抠数据正确性、或者被面试官追问三值逻辑的时候&#xff0c;才发现自己以前写过的过滤条件到处都是雷。这一篇是SQL大师之…

作者头像 李华
网站建设 2026/10/6 8:58:03

Linux压力测试工具详解:用stress模拟CPU、内存与磁盘高负载

简介&#xff1a;这是Linux平台上一款经典的压力测试工具stress的完整源码与文档包&#xff0c;面向系统管理员、运维工程师和性能测试开发者&#xff0c;可通过模拟CPU、内存的高负载场景&#xff0c;检验服务器在多任务并发下的稳定性、散热表现与极限吞吐能力&#xff0c;可…

作者头像 李华
网站建设 2026/10/6 8:57:56

Snowflake三层解耦架构:存储计算分离如何重构大数据数仓

运维自建大数据平台的人&#xff0c;应该都有过这种深夜体验&#xff1a;线上报表凌晨三点还没跑完&#xff0c;集群里几十个节点忙个不停&#xff0c;你能做的只有加机器、调参数&#xff0c;或者干等。大数据领域这些年一直在谈数据架构&#xff0c;但“架构”这个词常常停留…

作者头像 李华
网站建设 2026/10/6 8:56:56

基于Python与SnowNLP的旅游评论情感分析可视化系统

1. 项目概述1.1 核心需求解析先说结论&#xff1a;这个项目本质上是做了一套“旅游评论的情感分析流水线”&#xff0c;从数据采集、文本清洗、情感打分到可视化大屏展示&#xff0c;一整套闭环。对于计算机类毕业设计来说&#xff0c;它的亮点在于覆盖面广——爬虫、自然语言处…

作者头像 李华
网站建设 2026/10/6 8:55:53

Qt多线程入门:从界面卡死到线程方案选型与实战

写Qt多线程最怕什么&#xff1f;绝大多数小伙伴第一次遇到“界面假死”的时候&#xff0c;都以为是自己代码写崩了&#xff0c;其实是把耗时任务直接丢到了GUI线程里跑。我这个系列打算把Qt多线程的使用从头捋一遍&#xff0c;今天先讲最基础也最核心的东西——线程到底是什么、…

作者头像 李华
网站建设 2026/10/6 8:55:28

鸿蒙应用移植自动签名实战:HAP/HSP打包与hap-sign-tool排错指南

1. 移植Windows/Linux应用时被签名卡住的那一下1.1 IDE签名模式在批量移植场景下为什么不够用鸿蒙PC版出来之后&#xff0c;很多团队第一件事就是把手头Windows、Linux上的工具软件往这个系统搬。搬的方式无非两种&#xff1a;源码重新适配编译&#xff0c;或者通过兼容层直接拉…

作者头像 李华