LeetCode上面公開的幾道SQL題結果,歡迎大家討論。
(https://leetcode-cn.com/problemset/database/)
175. 組合兩個表【簡單】
表1:Person(
Id 是主鍵)
+-------------+---------+
| 列名 | 類型 |
+-------------+---------+
| PersonId | int |
| FirstName | varchar |
| LastName | varchar |
+-------------+---------+
表2: Address(
AddressId 是主鍵)
+-------------+---------+
| 列名 | 類型 |
+-------------+---------+
| AddressId | int |
| PersonId | int |
| City | varchar |
| State | varchar |
+-------------+---------+
編寫一個 SQL 查詢,滿足條件:無論 person 是否有地址信息,都需要基於上述兩表提供 person 的以下信息:
FirstName, LastName, City, State
select p.firstname, p.lastname, a.city, a.state
from person p left join address a
on p.personid = a.personid
這裏需要注意的是,select後字段最好加上表名,我第一遍沒加表名,運行超時了。
176. 第二高的薪水【簡單】
編寫一個 SQL 查詢,獲取 Employee
表中第二高的薪水(Salary) 。
+----+--------+
| Id | Salary |
+----+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
+----+--------+
例如上述 Employee
表,SQL查詢應該返回 200
作爲第二高的薪水。如果不存在第二高的薪水,那麼查詢應返回 null
。
+---------------------+
| SecondHighestSalary |
+---------------------+
| 200 |
+---------------------+
select ifnull
((select distinct salary from employee order by salary desc limit 1 offset 1), null)
SecondHighestSalary
select max(a.salary) SecondHighestSalary from employee a
where 1 = (select count(distinct(b.salary)) from employee b where b.salary > a.salary)
select max(salary) SecondHighestSalary
from employee
where salary not in
(select max(salary) from employee)
這裏需要注意的是,當沒有第二高的薪水時,要返回null,ifnull就是起的這樣的作用。
177. 第N高的薪水【中等】
編寫一個 SQL 查詢,獲取 Employee
表中第 n 高的薪水(Salary)。
+----+--------+
| Id | Salary |
+----+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
+----+--------+
例如上述 Employee
表,n = 2 時,應返回第二高的薪水 200
。如果不存在第 n 高的薪水,那麼查詢應返回 null
。
+------------------------+
| getNthHighestSalary(2) |
+------------------------+
| 200 |
+------------------------+
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
set N = N - 1;
RETURN (
# Write your MySQL query statement below.
(select distinct salary from employee group by Salary order by salary desc limit 1 offset N)
);
END
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
RETURN (
# Write your MySQL query statement below.
select max(salary) from employee a
where N - 1 = (
select count(distinct(b.salary)) from employee b where b.salary > a.salary
)
);
END
178. 分數排名【中等】
編寫一個 SQL 查詢來實現分數排名。如果兩個分數相同,則兩個分數排名(Rank)相同。請注意,平分後的下一個名次應該是下一個連續的整數值。換句話說,名次之間不應該有“間隔”。
+----+-------+
| Id | Score |
+----+-------+
| 1 | 3.50 |
| 2 | 3.65 |
| 3 | 4.00 |
| 4 | 3.85 |
| 5 | 4.00 |
| 6 | 3.65 |
+----+-------+
例如,根據上述給定的 Scores
表,你的查詢應該返回(按分數從高到低排列):
+-------+------+
| Score | Rank |
+-------+------+
| 4.00 | 1 |
| 4.00 | 1 |
| 3.85 | 2 |
| 3.65 | 3 |
| 3.65 | 3 |
| 3.50 | 4 |
+-------+------+
select score,
(select count(distinct score) from scores where score >= s.score) rank
from scores s order by score desc
select a.score, count(distinct(b.score)) rank
from scores a join scores b
on a.score <= b.score
group by a.id
order by a.score desc
180. 連續出現的數字【中等】
編寫一個 SQL 查詢,查找所有至少連續出現三次的數字。
+----+-----+
| Id | Num |
+----+-----+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
+----+-----+
例如,給定上面的 Logs
表, 1
是唯一連續出現至少三次的數字。
+-----------------+
| ConsecutiveNums |
+-----------------+
| 1 |
+-----------------+
select distinct a.num ConsecutiveNums
from logs a
left join logs b on a.id = b.id-1
left join logs c on b.id = c.id-1
where a.num = b.num and b.num = c.num
這裏需要注意的是,我用from..where連接了三張表,運行超時了
181. 超過經理收入的員工【簡單】
Employee
表包含所有員工,他們的經理也屬於員工。每個員工都有一個 Id,此外還有一列對應員工的經理的 Id。
+----+-------+--------+-----------+
| Id | Name | Salary | ManagerId |
+----+-------+--------+-----------+
| 1 | Joe | 70000 | 3 |
| 2 | Henry | 80000 | 4 |
| 3 | Sam | 60000 | NULL |
| 4 | Max | 90000 | NULL |
+----+-------+--------+-----------+
給定 Employee
表,編寫一個 SQL 查詢,該查詢可以獲取收入超過他們經理的員工的姓名。在上面的表格中,Joe 是唯一一個收入超過他的經理的員工。
+----------+
| Employee |
+----------+
| Joe |
+----------+
select a.name employee
from employee a join employee b
on a.managerid = b.id
where a.salary > b.salary
select a.name employee from employee a
where a.salary > (select salary from employee where id=a.managerid)
182. 查找重複的電子郵箱【簡單】
編寫一個 SQL 查詢,查找 Person
表中所有重複的電子郵箱。
示例:
+----+---------+
| Id | Email |
+----+---------+
| 1 | [email protected] |
| 2 | [email protected] |
| 3 | [email protected] |
+----+---------+
根據以上輸入,你的查詢應返回以下結果:
+---------+
| Email |
+---------+
| [email protected] |
+---------+
select email from person group by email having count(email) > 1
183. 從不訂購的客戶【簡單】
某網站包含兩個表,Customers
表和 Orders
表。編寫一個 SQL 查詢,找出所有從不訂購任何東西的客戶。
Customers
表:
+----+-------+
| Id | Name |
+----+-------+
| 1 | Joe |
| 2 | Henry |
| 3 | Sam |
| 4 | Max |
+----+-------+
Orders
表:
+----+------------+
| Id | CustomerId |
+----+------------+
| 1 | 3 |
| 2 | 1 |
+----+------------+
例如給定上述表格,你的查詢應返回:
+-----------+
| Customers |
+-----------+
| Henry |
| Max |
+-----------+
select name customers
from customers
where id not in (select distinct(customerid) from orders)
select c.name customers
from customers c left join orders o
on c.id = o.customerid
where o.customerid is null
184. 部門工資最高的員工【中等】
Employee
表包含所有員工信息,每個員工有其對應的 Id, salary 和 department Id。
+----+-------+--------+--------------+
| Id | Name | Salary | DepartmentId |
+----+-------+--------+--------------+
| 1 | Joe | 70000 | 1 |
| 2 | Henry | 80000 | 2 |
| 3 | Sam | 60000 | 2 |
| 4 | Max | 90000 | 1 |
+----+-------+--------+--------------+
Department
表包含公司所有部門的信息。
+----+----------+
| Id | Name |
+----+----------+
| 1 | IT |
| 2 | Sales |
+----+----------+
編寫一個 SQL 查詢,找出每個部門工資最高的員工。例如,根據上述給定的表格,Max 在 IT 部門有最高工資,Henry 在 Sales 部門有最高工資。
+------------+----------+--------+
| Department | Employee | Salary |
+------------+----------+--------+
| IT | Max | 90000 |
| Sales | Henry | 80000 |
+------------+----------+--------+
select d.name department, e.name employee, e.salary
from employee e join department d
on e.departmentid = d.id
where e.salary = (select max(salary) from employee where departmentid = e.departmentid)
select d.name department, e.name employee, e.salary
from employee e, department d, (select max(salary) salary, departmentid from employee group by departmentid) m
where e.departmentid = d.id and e.salary = m.salary and e.departmentid = m.departmentid
196. 刪除重複的電子郵箱【簡單】
編寫一個 SQL 查詢,來刪除 Person
表中所有重複的電子郵箱,重複的郵箱裏只保留 Id 最小 的那個。
+----+------------------+
| Id | Email |
+----+------------------+
| 1 | [email protected] |
| 2 | [email protected] |
| 3 | [email protected] |
+----+------------------+
Id 是這個表的主鍵。
例如,在運行你的查詢語句之後,上面的 Person
表應返回以下幾行:
+----+------------------+
| Id | Email |
+----+------------------+
| 1 | [email protected] |
| 2 | [email protected] |
+----+------------------+
delete b
from person a join person b
on a.email = b.email and a.id < b.id
1)找出所有重複的電子郵箱,需要判斷出所有重複的電子郵箱,即p1.Email = p2.Email
2)刪除Id大的重複郵箱,需要判斷重複郵箱中Id較大的:p1.Id > p2.Id
197. 上升的溫度【簡單】
給定一個 Weather
表,編寫一個 SQL 查詢,來查找與之前(昨天的)日期相比溫度更高的所有日期的 Id。
+---------+------------------+------------------+
| 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 |
+---------+------------------+------------------+
例如,根據上述給定的 Weather
表格,返回如下 Id:
+----+
| Id |
+----+
| 2 |
| 4 |
+----+
select a.id
from weather a join weather b
on a.temperature > b.temperature
where datediff(a.RecordDate, b.RecordDate) = 1
262. 行程和用戶【困難】
Trips
表中存所有出租車的行程信息。每段行程有唯一鍵 Id,Client_Id 和 Driver_Id 是 Users
表中 Users_Id 的外鍵。Status 是枚舉類型,枚舉成員爲 (‘completed’, ‘cancelled_by_driver’, ‘cancelled_by_client’)。
+----+-----------+-----------+---------+--------------------+----------+
| Id | Client_Id | Driver_Id | City_Id | Status |Request_at|
+----+-----------+-----------+---------+--------------------+----------+
| 1 | 1 | 10 | 1 | completed |2013-10-01|
| 2 | 2 | 11 | 1 | cancelled_by_driver|2013-10-01|
| 3 | 3 | 12 | 6 | completed |2013-10-01|
| 4 | 4 | 13 | 6 | cancelled_by_client|2013-10-01|
| 5 | 1 | 10 | 1 | completed |2013-10-02|
| 6 | 2 | 11 | 6 | completed |2013-10-02|
| 7 | 3 | 12 | 6 | completed |2013-10-02|
| 8 | 2 | 12 | 12 | completed |2013-10-03|
| 9 | 3 | 10 | 12 | completed |2013-10-03|
| 10 | 4 | 13 | 12 | cancelled_by_driver|2013-10-03|
+----+-----------+-----------+---------+--------------------+----------+
Users
表存所有用戶。每個用戶有唯一鍵 Users_Id。Banned 表示這個用戶是否被禁止,Role 則是一個表示(‘client’, ‘driver’, ‘partner’)的枚舉類型。
+----------+--------+--------+
| Users_Id | Banned | Role |
+----------+--------+--------+
| 1 | No | client |
| 2 | Yes | client |
| 3 | No | client |
| 4 | No | client |
| 10 | No | driver |
| 11 | No | driver |
| 12 | No | driver |
| 13 | No | driver |
+----------+--------+--------+
寫一段 SQL 語句查出 2013年10月1日 至 2013年10月3日 期間非禁止用戶的取消率。基於上表,你的 SQL 語句應返回如下結果,取消率(Cancellation Rate)保留兩位小數。
+------------+-------------------+
| Day | Cancellation Rate |
+------------+-------------------+
| 2013-10-01 | 0.33 |
| 2013-10-02 | 0.00 |
| 2013-10-03 | 0.50 |
+------------+-------------------+
select t.request_at day, (round((count(case when t.status like 'cancelled%' then 1 end)/count(t.status)),2)) 'cancellation rate'
from trips t join users u
on t.client_id = u.users_id
where u.banned = 'no'
and t.request_at between '2013-10-01' and '2013-10-03'
group by t.request_at
order by t.request_at
595. 大的國家【簡單】
這裏有張 World
表
+-----------------+------------+------------+--------------+---------------+
| name | continent | area | population | gdp |
+-----------------+------------+------------+--------------+---------------+
| Afghanistan | Asia | 652230 | 25500100 | 20343000 |
| Albania | Europe | 28748 | 2831741 | 12960000 |
| Algeria | Africa | 2381741 | 37100000 | 188681000 |
| Andorra | Europe | 468 | 78115 | 3712000 |
| Angola | Africa | 1246700 | 20609294 | 100990000 |
+-----------------+------------+------------+--------------+---------------+
如果一個國家的面積超過300萬平方公里,或者人口超過2500萬,那麼這個國家就是大國家。
編寫一個SQL查詢,輸出表中所有大國家的名稱、人口和麪積。
例如,根據上表,我們應該輸出:
+--------------+-------------+--------------+
| name | population | area |
+--------------+-------------+--------------+
| Afghanistan | 25500100 | 652230 |
| Algeria | 37100000 | 2381741 |
+--------------+-------------+--------------+
select name, population, area
from world
where area>3000000 or population>25000000
596. 超過5名學生的課【簡單】
有一個courses
表 ,有: student (學生) 和 class (課程)。
請列出所有超過或等於5名學生的課。
例如,表:
+---------+------------+
| student | class |
+---------+------------+
| A | Math |
| B | English |
| C | Math |
| D | Biology |
| E | Math |
| F | Computer |
| G | Math |
| H | Math |
| I | Math |
+---------+------------+
應該輸出:
+---------+
| class |
+---------+
| Math |
+---------+
Note:
學生在每個課中不應被重複計算。
select class
from courses
group by class
having count(distinct(student))>4
601. 體育館的人流量【困難】
X 市建了一個新的體育館,每日人流量信息被記錄在這三列信息中:序號 (id)、日期 (date)、 人流量 (people)。
請編寫一個查詢語句,找出高峯期時段,要求連續三天及以上,並且每天人流量均不少於100。
例如,表 stadium
:
+------+------------+-----------+
| id | date | people |
+------+------------+-----------+
| 1 | 2017-01-01 | 10 |
| 2 | 2017-01-02 | 109 |
| 3 | 2017-01-03 | 150 |
| 4 | 2017-01-04 | 99 |
| 5 | 2017-01-05 | 145 |
| 6 | 2017-01-06 | 1455 |
| 7 | 2017-01-07 | 199 |
| 8 | 2017-01-08 | 188 |
+------+------------+-----------+
對於上面的示例數據,輸出爲:
+------+------------+-----------+
| id | date | people |
+------+------------+-----------+
| 5 | 2017-01-05 | 145 |
| 6 | 2017-01-06 | 1455 |
| 7 | 2017-01-07 | 199 |
| 8 | 2017-01-08 | 188 |
+------+------------+-----------+
Note:
每天只有一行記錄,日期隨着 id 的增加而增加。
select distinct a.*
from stadium a, stadium b, stadium c
where a.people >= 100 and b.people >= 100 and c.people >= 100
and ((a.id = b.id - 1 and b.id = c.id - 1)
or
(b.id = a.id - 1 and a.id = c.id - 1)
or
(c.id = b.id - 1 and b.id = a.id - 1))
order by a.id
620. 有趣的電影【簡單】
某城市開了一家新的電影院,吸引了很多人過來看電影。該電影院特別注意用戶體驗,專門有個 LED顯示板做電影推薦,上面公佈着影評和相關電影描述。
作爲該電影院的信息部主管,您需要編寫一個 SQL查詢,找出所有影片描述爲非 boring
(不無聊) 的並且 id 爲奇數 的影片,結果請按等級 rating
排列。
例如,下表 cinema
:
+---------+-----------+--------------+-----------+
| id | movie | description | rating |
+---------+-----------+--------------+-----------+
| 1 | War | great 3D | 8.9 |
| 2 | Science | fiction | 8.5 |
| 3 | irish | boring | 6.2 |
| 4 | Ice song | Fantacy | 8.6 |
| 5 | House card| Interesting| 9.1 |
+---------+-----------+--------------+-----------+
對於上面的例子,則正確的輸出是爲:
+---------+-----------+--------------+-----------+
| id | movie | description | rating |
+---------+-----------+--------------+-----------+
| 5 | House card| Interesting| 9.1 |
| 1 | War | great 3D | 8.9 |
+---------+-----------+--------------+-----------+
select *
from cinema
where description != 'boring'
and id%2 != 0
order by rating desc
626. 換座位【中等】
小美是一所中學的信息科技老師,她有一張 seat
座位表,平時用來儲存學生名字和與他們相對應的座位 id。
其中縱列的 id 是連續遞增的
小美想改變相鄰倆學生的座位。
你能不能幫她寫一個 SQL query 來輸出小美想要的結果呢?
示例:
+---------+---------+
| id | student |
+---------+---------+
| 1 | Abbot |
| 2 | Doris |
| 3 | Emerson |
| 4 | Green |
| 5 | Jeames |
+---------+---------+
假如數據輸入的是上表,則輸出結果如下:
+---------+---------+
| id | student |
+---------+---------+
| 1 | Doris |
| 2 | Abbot |
| 3 | Green |
| 4 | Emerson |
| 5 | Jeames |
+---------+---------+
注意:
如果學生人數是奇數,則不需要改變最後一個同學的座位。
select s.id , s.student from
(
select id-1 as id ,student from seat where mod(id,2)=0
union
select id+1 as id,student from seat where mod(id,2)=1 and id != (select count(*) from seat)
union
select id,student from seat where mod(id,2)=1 and id = (select count(*) from seat)
) s order by id;
627. 交換工資【簡單】
給定一個 salary
表,如下所示,有m=男性 和 f=女性的值 。交換所有的 f 和 m 值(例如,將所有 f 值更改爲 m,反之亦然)。要求使用一個更新查詢,並且沒有中間臨時表。
例如:
| id | name | sex | salary |
|----|------|-----|--------|
| 1 | A | m | 2500 |
| 2 | B | f | 1500 |
| 3 | C | m | 5500 |
| 4 | D | f | 500 |
運行你所編寫的查詢語句之後,將會得到以下表:
| id | name | sex | salary |
|----|------|-----|--------|
| 1 | A | f | 2500 |
| 2 | B | m | 1500 |
| 3 | C | f | 5500 |
| 4 | D | m | 500 |
update salary
set sex = (case when sex = 'f' then 'm' else 'f' end)
update salary
set sex = if(sex = 'f', 'm', 'f')