牛客 SQL6要求筛选北京大学的学生,返回设备 ID 和学校。原稿答案是正确的:
SELECT device_id, university FROM user_profile WHERE university = '北京大学';但“WHERE 用来筛选”只是第一步。更值得问的是:筛选条件表达的业务范围是什么?是不是名字包含北京大学就算?是不是同一所学校只留一行?这两件事都不是原题要求。
1. 筛的是行,返回的是两列
每一行 -> 检查 university 的条件 -> 符合就返回 device_id、universitySELECT 决定返回哪些列,WHERE 决定保留哪些行。原题里 2138 和 6543 两个设备都来自北京大学,要保留两条,而不是因为学校相同就合并。
2. 只用标准校名的例子,不容易发现条件写宽了
在自己的练习数据库建立独立表,表名存在时换名:
CREATE TABLE sql6_school_demo ( device_id INT NOT NULL PRIMARY KEY, university VARCHAR(64) ); INSERT INTO sql6_school_demo VALUES (1,'北京大学'), (2,'北京大学'), (3,'北京大学医学部'), (4,'某学校:北京大学'), (5,'北京工业大学'), (6,NULL);SELECT device_id, university FROM sql6_school_demo WHERE university = '北京大学' ORDER BY device_id;本实验返回设备 1、2。相同学校的两个设备仍各自保留。
这里刻意允许 NULL,原题学校列是 NOT NULL。NULL 行用于观察扩展边界,不是修改原题约束。
3. LIKE 是另一种需求,不是更聪明的等号
SELECT device_id, university FROM sql6_school_demo WHERE university LIKE '%北京大学%' ORDER BY device_id;返回设备 1、2、3、4。百分号表示任意长度的字符序列;这是包含模式匹配,不是对前一句的等价优化。MySQL 模式匹配说明。
| 条件 | 实验命中设备 | 表达的意思 |
|---|---|---|
| = '北京大学' | 1、2 | 等值比较 |
| LIKE '%北京大学%' | 1、2、3、4 | 包含该连续字符串 |
| LIKE '北京大学%' | 1、2、3 | 以该字符串开头 |
医学部在真实业务里是否应归入目标群体,需要数据定义决定,SQL 不能替你判断。这里的名字只是用来说明匹配范围,不能据这个实验作学校归属结论。
同时,=也不是所有数据库配置下的逐字节比较:大小写、重音、尾空格等可能受字符集、排序规则和类型影响。本文不拿 SQLite 的结果证明 MySQL 的这些细节。MySQL 比较运算说明。
4. NULL 与同名多设备
SELECT device_id FROM sql6_school_demo WHERE university IS NULL ORDER BY device_id;返回 6。普通等号不能判断“未知学校是否等于北京大学”,这行不会进入原题结果。
如果只查学校名单,可以单独选择 university 并去重;本题要的是设备明细,不能只返回一条学校。是否去重取决于要交付的结果,而不是看见重复校名就自动加 DISTINCT。
5. 怎么确认筛选没有误收,也没有误删
本次在 SQLite 内存数据库执行正文实验,核对命中设备与两列列名,另外测试前缀模式、空表、单行和全部不匹配。把等号错换成包含模式时,测试必须发现额外设备;把结果错改成学校去重时,测试必须发现设备列丢失。
没有跑 MySQL 索引或性能实验,因此不写“等号必然使用索引”“LIKE 必然全表扫描”。本篇只验证所画数据上的筛选语义。
真实业务如果长期依赖人工输入的校名,还可以考虑把学校维护为规范实体,用 school_id 表示身份、名称用于展示;这是数据建模方向,不是本题需要改表才能做。先把需求说清楚,再选等值、前缀或包含,才不会让一个看起来能运行的 WHERE 悄悄扩大调研对象。