返回文章列表

光学不练假把式 —— 谈 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 填充。

但这里显然是右表是主表,因为想要的结果是部门领导的信息。

结论

经过了这三连败,我明白我还是得多多练习啊!