返回文章列表

【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 填充。

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

结论

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