面试常见问题——数据库(二)
目录:
- 应用实例
- 交换工资【LeetCode】
- 部门工资前三高的所有员工【LeetCode】
- 体育馆的人流量【LeetCode】
- 行程和用户【LeetCode】
- 换座位【LeetCode】
- 连续出现的数字【LeetCode】
- 部门工资最高的员工【LeetCode】
- 删除重复的电子邮箱【LeetCode】
- 超过五名学生的课【LeetCode】
- 上升的温度【LeetCode】
- 重新格式化部门表【LeetCode】
- 有趣的电影【LeetCode】
- 从不订购的客户【LeetCode】
- 大的国家【LeetCode】
- 超过经理收入的员工【LeetCode】
一、应用实例:
1、题目描述:给定一个salary表,如下所示,有 m = 男性 和 f = 女性 的值。交换所有的 f 和 m 值(例如,将所有 f 值更改为 m,反之亦然)。要求只使用一个更新(Update)语句,并且没有中间的临时表。注意,您必只能写一个 Update 语句,请不要编写任何 Select 语句。【LeetCode】
例如:
运行你所编写的更新语句之后,将会得到以下表:
UPDATE salary
SET sex = (
CASE sex WHEN 'm' THEN 'f'
WHEN 'f' THEN 'm'
END
)
2、题目描述:部门工资前三高的所有员工。【LeetCode】
Employee 表包含所有员工信息,每个员工有其对应的工号 Id,姓名 Name,工资 Salary 和部门编号 DepartmentId 。
Department 表包含公司所有部门的信息。
编写一个SQL 查询,找出每个部门获得前三高工资的所有员工。例如,根据上述给定的表,查询结果应返回:
解释:IT 部门中,Max 获得了最高的工资,Randy 和 Joe 都拿到了第二高的工资,Will 的工资排第三。销售部门(Sales)只有两名员工,Henry 的工资最高,Sam 的工资排第二。
CREATE TABLE Department(
Id INT PRIMARY KEY IDENTITY(1,1),
Name VARCHAR(50) NOT NULL
);
CREATE TABLE Employee(
Id INT PRIMARY KEY IDENTITY(1,1),
Name VARCHAR(50) not null,
Salary DECIMAL(6,1) not null,
DepartmentId INT,
FOREIGN KEY(DepartmentId) REFERENCES Department(Id)
);
INSERT INTO Department(Name)
VALUES('IT'),('Sales');
INSERT INTO Employee(Name, Salary, DepartmentId)
VALUES('Joe', 85000, 1),
('Henry', 80000, 2),
('Sam', 60000, 2),
('Max', 90000, 1),
('Janet', 69000, 1),
('Randy', 85000, 1),
('Will', 70000, 1);
SELECT b.Name AS Department, a.Name AS Employee, Salary
FROM Employee AS a
INNER JOIN Department AS b
ON b.Id = a.DepartmentId
WHERE a.Id in(
SELECT e1.Id
FROM Employee e1
left join Employee e2
ON e1.DepartmentId = e2.DepartmentId
AND e1.Salary < e2.Salary
GROUP BY(e1.Id)
HAVING COUNT(distinct e2.Salary) <= 2
)
ORDER BY b.Id ASC, Salary DESC;
3、题目描述:体育馆的人流量。X 市建了一个新的体育馆,每日人流量信息被记录在这三列信息中:序号 (id)、日期 (visit_date)、人流量 (people)。请编写一个查询语句,找出人流量的高峰期。高峰期时,至少连续三行记录中的人流量不少于100。【LeetCode】
例如,表 stadium:
对于上面的示例数据,输出为:
提示:每天只有一行记录,日期随着 id 的增加而增加。
CREATE TABLE stadium(
id INT PRIMARY KEY IDENTITY(1, 1),
visit_date DATE NOT NULL,
people INT NOT NULL
);
INSERT INTO stadium(visit_date, people)
values('2017-01-01', 10),
('2017-01-02', 109),
('2017-01-03', 150),
('2017-01-04', 99),
('2017-01-05', 145),
('2017-01-06', 1455),
('2017-01-07', 199),
('2017-01-08', 188);
//方法一:
SELECT *
FROM (
SELECT s1.*
FROM stadium s1
INNER JOIN stadium s2
ON s2.id = s1.id + 1
INNER JOIN stadium s3
ON s3.id = s2.id + 1
WHERE (s1.people >= 100 AND s2.people >= 100 AND s3.people >= 100)
UNION
SELECT s2.*
FROM stadium s1
INNER JOIN stadium s2
ON s2.id = s1.id + 1
INNER JOIN stadium s3
ON s3.id = s2.id + 1
WHERE (s1.people >= 100 AND s2.people >= 100 AND s3.people >= 100)
UNION
SELECT s3.*
FROM stadium s1
INNER JOIN stadium s2
ON s2.id = s1.id + 1
INNER JOIN stadium s3
ON s3.id = s2.id + 1
WHERE (s1.people >= 100 AND s2.people >= 100 AND s3.people >= 100)
)t;
//方法2:
SELECT distinct s1.*
FROM stadium s1, stadium s2, stadium s3
WHERE (
(s1.id + 1 = s2.id AND s2.id + 1 = s3.id)
OR (s1.id - 1 = s2.id AND s1.id + 1 = s3.id)
OR (s1.id - 1 = s2.id AND s2.id - 1 = s3.id)
)AND s1.people >= 100
AND s2.people >= 100
AND s3.people >= 100
ORDER BY s1.id;
4、题目描述:行程和用户。【LeetCode】
Trips表中存所有出租车的行程信息。每段行程有唯一键 Id,Client_Id 和 Driver_Id 是Users表中Users_Id 的外键。Status是枚举类型,枚举成员为 (‘completed’, ‘cancelled_by_driver’, ‘cancelled_by_client’)。
Users表存所有用户。每个用户有唯一键 Users_Id。Banned表示这个用户是否被禁止,Role则是一个表示(‘client’, ‘driver’, ‘partner’)的枚举类型。
写一段 SQL 语句查出2013年10月1日至2013年10月3日期间非禁止用户的取消率。基于上表,你的SQL语句应返回如下结果,取消率(Cancellation Rate)保留两位小数。取消率的计算方式如下:(被司机或乘客取消的非禁止用户生成的订单数量) / (非禁止用户生成的订单总数)
CREATE TABLE Users(
Users_Id INT PRIMARY KEY,
Banned VARCHAR(10) NOT NULL,
Role VARCHAR(20) NOT NULL
);
CREATE TABLE Trips(
Id INT PRIMARY KEY IDENTITY(1, 1),
Client_Id INT NOT NULL,
Driver_Id INT NOT NULL,
City_Id INT NOT NULL,
Status VARCHAR(50) NOT NULL,
Request_at DATE NOT NULL
FOREIGN KEY(Client_Id) REFERENCES Users(Users_id),
FOREIGN KEY(Driver_Id) REFERENCES Users(Users_id)
);
/*ROUND第一个参数是我们要被操作的数据,第二个参数是设置四舍五入之后小数点后显示几位。*/
SELECT Request_at AS Day,
ROUND(CAST(SUM(CASE WHEN Status = 'completed' THEN 0 ELSE 1 END) AS FLOAT)/COUNT(Status), 2) AS 'Cancellation Rate'
FROM Trips
LEFT JOIN Users u1
ON u1.Users_Id = Client_Id
LEFT JOIN Users u2
ON u2.Users_Id = Driver_Id
WHERE u1.Banned = 'No'
AND u2.Banned = 'No'
AND Request_at BETWEEN '2013-10-01' AND '2013-10-03'
GROUP BY Request_at
SELECT Request_at AS Day,
ROUND(CAST(SUM(CASE WHEN Status = 'completed' THEN 0 ELSE 1 END) AS FLOAT)/COUNT(Status), 2) AS 'Cancellation Rate'
FROM Trips, Users u1, Users u2
WHERE u1.Users_Id = Client_Id
AND u2.Users_Id = Driver_Id
AND u1.Banned = 'No'
AND u2.Banned = 'No'
AND Request_at BETWEEN '2013-10-01' AND '2013-10-03'
GROUP BY Request_at
5、题目描述:小美是一所中学的信息科技老师,她有一张 seat座位表,平时用来储存学生名字和与他们相对应的座位 id。其中纵列的id是连续递增的,小美想改变相邻俩学生的座位。请帮她写一个 SQL query来输出小美想要的结果【LeetCode】
示例:
假如数据输入的是上表,则输出结果如下:
注意:如果学生人数是奇数,则不需要改变最后一个同学的座位。
SELECT s1.id, CASE WHEN s2.student IS NULL THEN s1.student ELSE s2.student END AS student
FROM seat s1
LEFT JOIN seat s2
ON s1.id = CASE WHEN s1.id % 2 != 0 THEN s2.id - 1
ELSE s2.id + 1 END;
6、题目描述:编写一个 SQL 查询,查找所有至少连续出现三次的数字。【LeetCode】
例如,给定上面的 Logs 表, 1 是唯一连续出现至少三次的数字。
SELECT DISTINCT log1.Num AS ConsecutiveNums
FROM Logs log1
INNER JOIN Logs log2
ON log1.id + 1 = log2.id
INNER JOIN Logs log3
ON log2.id + 1 = log3.id
WHERE log1.Num = log2.Num
AND log2.Num = log3.Num;
7、题目描述:编写一个 SQL 查询,找出每个部门工资最高的员工。【LeetCode】
Employee 表包含所有员工信息,每个员工有其对应的Id, salary 和 department Id。
Department表包含公司所有部门的信息。
例如,根据上述给定的表格,Max 在 IT 部门有最高工资,Henry 在 Sales 部门有最高工资。
SELECT t2.Name AS Department, t1.Name AS Employee, t1.Salary
FROM Employee t1, Department t2, (
SELECT d.Id, MAX(e.Salary) AS Salary
FROM Employee e, Department d
WHERE e.DepartmentId = d.Id
GROUP BY d.Id
)t3
WHERE t3.Id = t1.DepartmentId
AND t2.Id = t3.Id
AND t3.Salary = t1.Salary
ORDER BY Department;
8、题目描述:编写一个 SQL 查询,来删除Person表中所有重复的电子邮箱,重复的邮箱里只保留Id最小的那个。【LeetCode】
Id 是这个表的主键。例如,在运行你的查询语句之后,上面的 Person 表应返回以下几行:
DELETE FROM Person
WHERE Id IN(
SELECT p1.Id
FROM Person p1, Person p2
WHERE p1.Email = p2.Email
AND p1.Id > p2.Id
)
9、题目描述:有一个courses 表 ,有: student(学生) 和 class (课程)。请列出所有超过或等于5名学生的课。【LeetCode】
例如,表:
应该输出:
Note:
学生在每个课中不应被重复计算。
SELECT class
FROM courses
GROUP BY class
HAVING COUNT(DISTINCT student) >= 5
10、题目描述:给定一个 Weather 表,编写一个 SQL 查询,来查找与之前(昨天的)日期相比温度更高的所有日期的 Id。【LeetCode】
例如,根据上述给定的 Weather 表格,返回如下 Id:
SELECT w1.Id
FROM Weather w1
LEFT JOIN Weather w2
ON DATEDIFF(d, w1.RecordDate, w2.RecordDate) = -1
WHERE w2.RecordDate IS NOT NULL
AND w1.Temperature > w2.Temperature
11、题目描述:编写一个 SQL 查询来重新格式化表,使得新的表中有一个部门 id 列和一些对应每个月的收入(revenue)列。【LeetCode】
部门表Department,(id, month) 是表的联合主键。这个表格有关于每个部门每月收入的信息。月份(month)可以取下列值 ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]。
查询结果格式如下面的示例所示:Department 表:
查询得到的结果表:
注意,结果表有 13 列 (1个部门 id 列 + 12个月份的收入列)。
SELECT id,
MIN(CASE WHEN month = 'Jan' THEN revenue ELSE null END) AS Jan_Revenue,
MIN(CASE WHEN month = 'Feb' THEN revenue ELSE null END) AS Feb_Revenue,
MIN(CASE WHEN month = 'Mar' THEN revenue ELSE null END) AS Mar_Revenue,
MIN(CASE WHEN month = 'Apr' THEN revenue ELSE null END) AS Apr_Revenue,
MIN(CASE WHEN month = 'May' THEN revenue ELSE null END) AS May_Revenue,
MIN(CASE WHEN month = 'Jun' THEN revenue ELSE null END) AS Jun_Revenue,
MIN(CASE WHEN month = 'Jul' THEN revenue ELSE null END) AS Jul_Revenue,
MIN(CASE WHEN month = 'Aug' THEN revenue ELSE null END) AS Aug_Revenue,
MIN(CASE WHEN month = 'Sep' THEN revenue ELSE null END) AS Sep_Revenue,
MIN(CASE WHEN month = 'Oct' THEN revenue ELSE null END) AS Oct_Revenue,
MIN(CASE WHEN month = 'Nov' THEN revenue ELSE null END) AS Nov_Revenue,
MIN(CASE WHEN month = 'Dec' THEN revenue ELSE null END) AS Dec_Revenue
FROM Department
GROUP BY id;
12、某城市开了一家新的电影院,吸引了很多人过来看电影。该电影院特别注意用户体验,专门有个 LED显示板做电影推荐,上面公布着影评和相关电影描述。作为该电影院的信息部主管,您需要编写一个 SQL查询,找出所有影片描述为非boring(不无聊)的并且 id 为奇数的影片,结果请按等级 rating 排列。【LeetCode】
例如,下表 cinema:
对于上面的例子,则正确的输出是为:
SELECT id, movie, description, rating
FROM cinema
WHERE id % 2 = 1
AND description != 'boring'
ORDER BY rating DESC;
13、题目描述:某网站包含两个表,Customers 表和 Orders 表。编写一个 SQL 查询,找出所有从不订购任何东西的客户。【LeetCode】
Customers 表:
Orders 表:
例如给定上述表格,你的查询应返回:
SELECT Name AS Customers
FROM Customers
WHERE Id NOT IN (
SELECT CustomerId
FROM Orders
)
14、题目描述:编写一个SQL查询,输出表中所有大国家的名称、人口和面积。【LeetCode】
World 表:
如果一个国家的面积超过300万平方公里,或者人口超过2500万,那么这个国家就是大国家。
例如,根据上表,我们应该输出:
SELECT name, population, area
FROM World
WHERE population >= 25000000
OR area >= 3000000
15、题目描述:给定Employee表,编写一个 SQL 查询,该查询可以获取收入超过他们经理的员工的姓名。【LeetCode】
Employee表包含所有员工,他们的经理也属于员工。每个员工都有一个 Id,此外还有一列对应员工的经理的 Id。
在上面的表格中,Joe 是唯一一个收入超过他的经理的员工。
SELECT e1.Name AS Employee
FROM Employee e1, Employee e2
WHERE e1.ManagerId = e2.Id
AND e2.Salary < e1.Salary;