☰
SQL查询所有列:SELECT *里的星号管列,不管行
2026/10/6 12:09:47 网站建设 项目流程

原题是牛客:查询所有列。运营想查看用户信息表中的全部数据,答案只有一行:

SELECT * FROM user_profile;

这行 SQL 并不难。但如果把它记成“星号表示所有用户”,下一题只取两列、只查一个学校时,就容易分不清是谁控制什么。

1. 先把表看成两个方向

表有列,也有行。列是每条记录包含哪些信息,行是有哪些记录。

选择哪些列 <------------> id device_id age ... ^ 1 2138 21 选择哪些行 | 2 3214 NULL v 3 6543 20

SELECT后的列表决定返回哪些列;FROM指定从哪里取;WHERE决定留下哪些行。

在这道单表题里,*选择所有列。没有WHERE,才是没有额外筛选行的原因。二者碰巧同时出现,不代表是同一件事。

2. 用完整数据跑一次

下面是依照原题样例整理的可复现实验,使用独立测试表,不在业务数据库执行建表。

CREATE TABLE user_profile ( id INTEGER PRIMARY KEY, device_id INTEGER, gender VARCHAR(10), age INTEGER, university VARCHAR(30), province VARCHAR(20) ); INSERT INTO user_profile (id, device_id, gender, age, university, province) VALUES (1, 2138, 'male', 21, '北京大学', 'Beijing'), (2, 3214, 'male', NULL, '复旦大学', 'Shanghai'), (3, 6543, 'female', 20, '北京大学', 'Beijing'), (4, 2315, 'female', 23, '浙江大学', 'ZheJiang'), (5, 5432, 'male', 25, '山东大学', 'Shandong');

为了让本地输出便于逐行核对,实验显式按唯一的id排序:

SELECT * FROM user_profile ORDER BY id;
iddevice_idgenderageuniversityprovince
12138male21北京大学Beijing
23214maleNULL复旦大学Shanghai
36543female20北京大学Beijing
42315female23浙江大学ZheJiang
55432male25山东大学Shandong

原题没有排序要求,最前面的一行答案即可。这里加ORDER BY是实验约定,不能从一次没排序的输出推断数据库永远按插入顺序返回。

第二行age是NULL,这一行仍在结果里。查询全部记录不要求每个字段都有值,也不会自动补零或去重。

原笔记的运行结果保留如下,它只代表当时平台提交,不是本轮实验的截图:

3. 把列选择和行筛选分开试

只要用户编号与学校,但仍然取所有行:

SELECT device_id, university FROM user_profile ORDER BY id;

仍是5行,但只有2列。返回列的顺序就是这里写出的顺序。

反过来,保留所有列,但只取北京大学的用户:

SELECT * FROM user_profile WHERE university = '北京大学' ORDER BY id;

现在是2行、6列,对应id = 1和id = 3。所以“所有列”不等于“所有行”。

再故意写一个没有匹配记录的条件:

SELECT * FROM user_profile WHERE id = -1;

结果是0行,不是“有一行且所有值都是NULL”。客户端仍可获知这次查询的6个结果列;结果结构与实际有几条记录,是两个问题。

4. 一个更实际的问题:表加字段后,星号会不会变?

先运行上面的查询,再在测试表新增一个普通字段:

ALTER TABLE user_profile ADD COLUMN nickname VARCHAR(30);

重新运行SELECT * FROM user_profile ORDER BY id;,本地实验返回7列,新增的nickname在已有行上为NULL。前面的显式两列查询仍然返回2列。

变更前:SELECT * -> 6列 变更后:SELECT * -> 7列 变更后:SELECT device_id, university -> 2列

这才是长期使用*值得注意的地方:代码没有改,结果结构却跟着表变了。

例如调用方认为最后一列永远是province,增加字段后这个约定就不成立了。按位置解包、CSV导出字段数、固定响应格式,都可能受影响。

临时排查、初学练习中,*很方便;长期接口只需要几个字段时,明确写出字段,更容易看出输出约定。它也不能代替授权和数据脱敏,选列少不等于访问控制已经做好。

这里的“全部”还有版本和表定义边界:MySQL支持不可见列,普通SELECT *不包含不可见列,需要显式指定。上面的实验只新增普通列,没有在SQLite中模拟MySQL的不可见列机制。见MySQL不可见列文档。

也不能反过来背成“用了星号就一定慢”。是否多读了不需要的数据、是否能利用覆盖索引等,要看具体查询和执行计划;本文没有跑性能基准。

5. 这篇怎么核对结果?

本地使用Python标准库的SQLite内存数据库,直接执行本文SQL代码块,而不是另写一份差不多的查询。核对原题5行6列、列名顺序、NULL保留、显式两列、筛选结果、空结果,以及加字段后的6列变7列。

还检查错误改写:COUNT(*)得到的是一行统计值,不是原表全部记录;省掉FROM写SELECT *,在该实验数据库中会报错。

SQLite实验用于验证这些基础查询的结果结构,不代表实测了MySQL的权限、排序规则、索引计划或不可见列。语法范围另外参照MySQL SELECT文档。

这道题可以只交一行答案,理解时却要保留两个方向:先问要哪些列,再问要哪些行。后面的查询题基本都在这两个方向上加条件。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询