【sql】光学不练假把式 —— 谈 sql 入门
欠的技术债
作为一个软件工程专业毕业的程序员,数据库是大学的必修课。
依然记得当时的我在考试前一晚,抱着书本挑灯夜战了一个通宵,临时抱佛脚地看完了所有考点。第二天考试时靠着临时记忆,居然也考过了。随后就把数据库的知识抛之脑后,再也没碰过。
参加工作后,稀里糊涂选了前端开发的岗位。数据库的知识更是一点也用不上了。
最近机缘巧合,又捡起了数据库,从 Mick 老师编写的《SQL 基础教程》开始,重新学习。几乎是一边翻书一边对着电脑敲 sql 代码,很快就学完了。
学完之后有两个感受:sql 方言多 和 需要实战演练。
sql 的方言真的多
前端开发者肯定都知道方言多意为着什么——明明自己写的代码没有问题,在其他设备上就是运行不了。
为了解决兼容性问题不得不把代码复杂化、冗余化。代码也因此不再优雅,就算测试阶段所有测试机都能正常运行,上线后依然要祈祷不要出现兼容性问题。
兼容性问题是前端开发者永远的痛,因为我们无法控制用户的设备。
sql 的方言多带来痛似乎是另一个极端,服务器的设备、数据库以及版本等都受开发者控制。但潜在的迁移困难、维护成本、学习成本等,依然需要开发者重视。
这似乎也导致各种 orm 库生态繁荣。
实战演练
纸上得来终觉浅,我在搜索引擎上搜索"sql 练习题",然后选了第一个结果:某网站的 sql 热门习题。
做了前三道,提交发现,全错了。
好在没有错的非常离谱,只是个别地方需要调整。
接下来我要记录这三道题,以及我错在哪了。
查找最晚入职员工信息
SELECT *
FROM employees
ORDER BY hire_date DESC
LIMIT 1;
我的第一版答案没有 limit 1
查找入职员工时间排名倒数第三的员工所有信息
SELECT *
FROM employees
ORDER BY hire_date DESC
LIMIT 2, 1;
如果你觉得上面这个 sql 写的没问题,那就上当了。因为可能会存在多个员工在同一天入职。
正确答案:
SELECT * FROM employees
WHERE hire_date = (
SELECT DISTINCT hire_date
FROM employees
ORDER BY hire_date DESC
LIMIT 2,1
)
即先通过子查询查找倒数第三的入职日期,然后通过主查询查找该入职日期的所有员工信息。
查找当前薪水详情以及部门编号 dept_no
有一个全部员工的薪水表 salaries 简况如下:
| emp_no | salary | from_date | to_date |
|---|---|---|---|
| 10001 | 88958 | 2002-06-22 | 9999-01-01 |
| 10002 | 72527 | 2001-08-02 | 9999-01-01 |
| 10003 | 43311 | 2001-12-01 | 9999-01-01 |
有一个各个部门的领导表 dept_manager 简况如下:
| dept_no | emp_no | to_date |
|---|---|---|
| d001 | 10001 | 9999-01-01 |
| d002 | 10003 | 9999-01-01 |
请你查找各个部门当前领导的薪水详情以及其对应部门编号 dept_no,输出结果以 salaries.emp_no 升序排序,并且请注意输出结果里面 dept_no 列是最后一列。以上例子输出如下:
| emp_no | salary | from_date | to_date | dept_no |
|---|---|---|---|---|
| 10001 | 88958 | 2002-06-22 | 9999-01-01 | d001 |
| 10003 | 43311 | 2001-12-01 | 9999-01-01 | d002 |
这题我一看,这不是我的老朋友“联表查询”吗?
select sal.emp_no,
sal.salary,
sal.from_date,
sal.to_date,
dept.dept_no
from salaries as sal right join dept_manager as dept
on sal.emp_no = dept.emp_no
order by emp_no
这个是正确答案,但我第一次提交的时候没有写 right join 而是写的 left join。
因为我学的时候,老师说 left join 左侧的表是主表。我以为的主表是指大多数列重合的表。
实际上主表是指保留所有记录的表,即使这些记录在另一个表中没有匹配项。在 left join 中,左表的所有记录都会出现在结果集中,而右表中不匹配的记录会以 NULL 填充。
但这里显然是右表是主表,因为想要的结果是部门领导的信息。
结论
经过了三连败,我明白我还是得多多练习啊!