牛客 SQL5要求查看前两个用户的设备 ID,并把结果列名改为 user_infos_example。
我原来的笔记只说“用了 AS 和 LIMIT”,还没有把两个动作讲清楚。这里其实是两个独立要求:取多少行,与结果叫什么名字。
1. 把题目翻译成 SQL
按原题练习写法:
SELECT device_id AS user_infos_example FROM user_profile LIMIT 2;| 部分 | 负责什么 | 不负责什么 |
|---|---|---|
| SELECT device_id | 选出设备 ID | 不选所有字段 |
| AS user_infos_example | 给结果列起名字 | 不修改原表字段 |
| LIMIT 2 | 最多返回两行 | 不定义哪两行排在前面 |
原题示例给出 2138 和 3214,但从一般 SQL 语义看,没有 ORDER BY 就不能保证顺序。若业务明确要“按用户 id 从小到大的前两条”,应把这个规则写出来:
SELECT device_id AS user_infos_example FROM user_profile ORDER BY id LIMIT 2;这要求 id 能确定顺序;若排序键有重复而且要稳定挑行,还需要补足排序条件。不要把 AS 当成会同时排序的关键字。
2. 用一张小表看清“只改结果表头”
下面使用独立实验表,在自己的练习数据库运行;表名已存在时换一个名字。
CREATE TABLE sql5_alias_demo ( id INT NOT NULL PRIMARY KEY, device_id INT NOT NULL ); INSERT INTO sql5_alias_demo VALUES (3,6543),(1,2138),(2,3214);故意不按 id 顺序插入。真正定义输出顺序的,是查询中的 ORDER BY,不是插入先后。
SELECT device_id AS user_infos_example FROM sql5_alias_demo ORDER BY id LIMIT 2;| user_infos_example |
|---|
| 2138 |
| 3214 |
再执行不带别名的查询:
SELECT device_id FROM sql5_alias_demo ORDER BY id LIMIT 2;值相同,表头仍叫 device_id。别名不是迁移,也不是 ALTER TABLE,只给这次查询结果命名。
原表字段:device_id | +-- 本次查询 AS user_infos_example -> 结果列 user_infos_example | +-- 下次查询 device_id -> 结果列 device_id这个小区别在代码里也重要:程序若按结果列名取值,带别名后应使用 user_infos_example,而不是以为原表已经多出同名字段。
3. 别名能在哪里使用?别把数据库混在一起
MySQL 允许在 ORDER BY 等位置引用 SELECT 别名。例如:
SELECT device_id AS user_infos_example FROM sql5_alias_demo ORDER BY user_infos_example DESC LIMIT 2;这里按设备 ID 降序,结果是 6543、3214。和“按用户 id 取前两条”是不同需求。
但在 MySQL 同一层查询的 WHERE 中,不能直接用 SELECT 产生的别名替代源字段。可以仍然用源字段写筛选:
SELECT device_id AS user_infos_example FROM sql5_alias_demo WHERE device_id > 3000 ORDER BY id;也可以先形成一个派生表,外层再使用这个结果列名:
SELECT user_infos_example FROM ( SELECT id, device_id AS user_infos_example FROM sql5_alias_demo ) AS q WHERE user_infos_example > 3000 ORDER BY id;两种写法都得到 3214、6543。对本题来说第一种更直接,没必要为了用别名而增加一层。
这是名字的作用域规则,不能当成优化器一定按文字顺序执行的证明。SQLite 对 WHERE 别名有扩展,不能因为 SQLite 接受,就说 MySQL 也接受。MySQL 官方列别名说明。
4. 验证时不只看数值,还要看列名
本次把上面的可运行实验查询放进 SQLite 内存数据库,核对行值和返回对象的键名,并检查空表、只有一行时 LIMIT 2 的行为。MySQL 的别名作用域按官方文档核对;没有运行 MySQL,也不把 SQLite 的扩展用作 MySQL 证据。
| 检查项 | 应当得到什么 |
|---|---|
| 带 AS 的查询 | 列名 user_infos_example,值 2138、3214 |
| 不带 AS 的查询 | 列名 device_id,相同两项值 |
| 按别名降序 | 6543、3214 |
| 筛选与派生表写法 | 都返回 3214、6543 |
| 空表、单行表 | 分别返回 0 行、1 行,不会凑出两行 |
回到原题,AS 解决名字,LIMIT 解决数量,ORDER BY 才解决顺序。把这三件事分开,短短一行 SQL 也就不只是背答案。