尽管对于SQL专家来说,编译SQL查询并不是最有趣的事情,但是对想要成功完成与数据处理相关的任何活动的人来说,对SQL的良好理解至关重要。这里的关键是,SQL不仅是SELECT
,FROM
和WHERE
。专家了解的SQL构造越多,他就越容易创建从数据库获取他可能需要的所有内容的请求。
该文章的作者(我们今天将要翻译的译本)说,其目的是解决两个问题:
- 探索超越基本SQL知识的机制。
- 考虑使用SQL的一些实际任务。
本文介绍了来自Leetcode的5个SQL问题。它们代表了面试中经常遇到的实际任务。问题一:薪金第二
编写一个SQL查询,以从具有员工薪水信息(Employee
)的表中获取包含第二高薪水的条目。例如,为下表执行的查询应返回200
。如果表格的值不低于最高薪水,则请求应返回null
。+
| Id | Salary |
+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
+
▍决定A:使用IFNULL
和OFFSET
以下是此问题解决方案中将使用的主要机制:IFNULL(expression, alt)
:expression
如果不相等,则此函数返回其参数null
。否则,返回参数alt
。null
如果表不包含所需的值,我们将使用此函数返回。OFFSET
:此运算符与表达式ORDER BY
一起使用以舍弃前n
几行。这对我们很有用,因为我们对结果的第二行(即第二高的薪水,表中的数据)感兴趣。
这是一个现成的请求:SELECT
IFNULL(
(SELECT DISTINCT Salary
FROM Employee
ORDER BY Salary DESC
LIMIT 1 OFFSET 1
), null) as SecondHighestSalary
FROM Employee
LIMIT 1
▍解决方案B:使用 MAX
下面的查询使用功能MAX
。在此,选择最高薪水值,该值不等于整个表格中收到的最高薪水。结果,我们得到了我们所需要的-第二大薪水。SELECT MAX(salary) AS SecondHighestSalary
FROM Employee
WHERE salary != (SELECT MAX(salary) FROM Employee)
问题2:重复的电子邮件地址
编写一个SQL查询来检测表中Person
所有重复的电子邮件地址。+
| Id | Email |
+
| 1 | a@b.com |
| 2 | c@d.com |
| 3 | a@b.com |
+
▍决策A:COUNT
在子查询中
首先,我们创建一个子查询,在其中确定表中每个地址的出现频率。然后,使用指令过滤子查询返回的结果WHERE count > 1
。该查询将多次返回有关在源表中找到的地址的信息。SELECT Email
FROM (
SELECT Email, count(Email) AS count
FROM Person
GROUP BY Email
) as email_count
WHERE count > 1
▍解决方案B:表达 HAVING
HAVING
:这是一个表达式,允许您将指令WHERE
与表达式一起使用GROUP BY
。
SELECT Email
FROM Person
GROUP BY Email
HAVING count(Email) > 1
问题三:温度上升
编写一个SQL查询,以在表中查找Weather
温度高于其前日期温度的所有日期(日期标识符)。也就是说,我们对“今天”温度高于“昨天”温度的日期感兴趣。+
| Id(INT) | RecordDate(DATE) | Temperature(INT) |
+
| 1 | 2015-01-01 | 10 |
| 2 | 2015-01-02 | 25 |
| 3 | 2015-01-03 | 20 |
| 4 | 2015-01-04 | 30 |
+
▍解决方案: DATEDIFF
DATEDIFF
:此函数计算两个日期之间的时差。它用于提供精确的“今天”和“昨天”温度的比较。
如果我们用普通语言来表达以下查询,结果表明它表达了以下思想:我们需要选择标识符,使得与它们表示的日期相对应的温度大于针对它们的“昨天”日期的温度。SELECT DISTINCT a.Id
FROM Weather a, Weather b
WHERE a.Temperature > b.Temperature
AND DATEDIFF(a.Recorddate, b.Recorddate) = 1
问题4:单位中的最高薪水
该表Employee
存储有关公司员工的信息。该表中的每个条目均包含有关该Id
员工的标识符(),其姓名(Name
),工资(Salary
)以及其工作所在的公司部门(Department
)的信息。+
| Id | Name | Salary | DepartmentId |
+
| 1 | Joe | 70000 | 1 |
| 2 | Jim | 90000 | 1 |
| 3 | Henry | 80000 | 2 |
| 4 | Sam | 60000 | 2 |
| 5 | Max | 90000 | 1 |
+
该表Department
包含有关公司部门的信息。+
| Id | Name |
+
| 1 | IT |
| 2 | Sales |
+
编写一个SQL查询,该查询在每个员工部门中找到最高薪水。例如,对于上面的表,类似的查询应返回由下表表示的结果(表中行的顺序无关紧要):+
| Department | Employee | Salary |
+
| IT | Max | 90000 |
| IT | Jim | 90000 |
| Sales | Henry | 80000 |
+
▍解决方案:团队 IN
该命令IN
允许您在指令WHERE
中设置与使用多个命令相对应的条件OR
。例如,以下两个构造是相同的:WHERE country = ‘Canada’ OR country = ‘USA’
WHERE country IN (‘Canada’, ’USA’).
在这里,我们要获得一个包含部门名称(Department
),雇员名称(Employee
)和他的工资(Salary
)的表格。为此,我们创建了一个表格,其中包含有关单位标识符(DepartmentID
)和该单位最高工资的信息。然后,我们根据只有在结果表秋天哪个条目在条件表将二者结合起来DepartmentID
,并Salary
以前在表中形成的。SELECT
Department.name AS 'Department',
Employee.name AS 'Employee',
Salary
FROM Employee
INNER JOIN Department ON Employee.DepartmentId = Department.Id
WHERE (DepartmentId , Salary)
IN
( SELECT
DepartmentId, MAX(Salary)
FROM
Employee
GROUP BY DepartmentId
)
问题5:移植学生
玛丽是高中老师。她有一个表格seat
,用于存储学生的姓名以及他们在教室中的位置信息。该id
表中的值不断增加。玛丽想交换邻居学生。这是学生最初的位置表格:+
| id | student |
+
| 1 | Abbot |
| 2 | Doris |
| 3 | Emerson |
| 4 | Green |
| 5 | Jeames |
+
移植附近的学生后,应该发生以下情况:+
| id | student |
+
| 1 | Doris |
| 2 | Abbot |
| 3 | Green |
| 4 | Emerson |
| 5 | Jeames |
+
编写请求,使老师能够解决上述问题。请注意,如果学生人数为奇数,则无需将最后一个学生转移到任何地方。▍解决方案:使用运算符 WHEN
SQL构造CASE WHEN THEN
可以视为if
编程中的运算符。在我们的情况下,第一个运算符WHEN
用于检查是否将奇数标识符分配给表的最后一行。如果是这样,则该行不会更改。第二个运算符WHEN
负责对每个奇数标识符加1(例如,将1、3、5变成2、4、6),并从每个偶数标识符中减去1(将2、4、6变成1、3、5)。SELECT
CASE
WHEN((SELECT MAX(id) FROM seat)%2 = 1) AND id = (SELECT MAX(id) FROM seat) THEN id
WHEN id%2 = 1 THEN id + 1
ELSE id - 1
END AS id, student
FROM seat
ORDER BY id
摘要
我们研究了几个SQL任务,并一路讨论了一些可用于编译SQL查询的高级工具。我们希望您今天所学的内容在SQL访谈中对您有所帮助,并在日常工作中证明是有用的。PS在我们的市场上,有一个带有SQL Server Express的Docker映像,只需单击一下即可安装。您可以在VPS上检查容器的操作。所有新客户均可免费享受3天的测试。亲爱的读者们!对于那些想精通创建SQL查询的技巧的人,您能提供什么建议?