【leetcodeMySQL每周一练】- 5道题带你练习mysql
🎈寫在前面
🙋?♂?大家好呀,我是超夢。小伙伴們都知道,不管是在學習中還是日常工作中,幾乎天天是要跟數據庫打交道的,為了更好的操作數據庫,我們的SQL知識儲備是必不可少的。想要掌握好SQL,那少不了每天的練習與學習。接下來小夢會帶領小伙伴們開啟LeetCode-MySQL強化訓練,通過力扣真題來復習鞏固我們的SQL知識,能在以后的工作與學習中熟練使用SQL語句。小夢會在每到題后面附加上對應的知識點,方便小伙伴們查缺補漏。
🙋?♂? 小伙伴們如果在學習過程中有不明白的地方,歡迎評論區留言提問,小夢定知無不言,言無不盡。
目錄
題目一:組合兩個表
題目概述
解題思路
代碼測試
知識點小結
聯表查詢之外連接
題目二:第二高的薪水
題目概述
解題思路
代碼測試
知識點小結
limit子句
ifnull函數
題目三:超過經理收入的員工
題目概述
解題思路
代碼測試
知識點小結
內連接與外連接
題目四:查找重復的電子郵箱
題目概述
解題思路
代碼測試
知識點小結
group by與having子句
題目五:從不訂購的顧客
題目概述
解題思路
代碼測試
知識點小結
內連接與外連接
題目一:組合兩個表
題目概述
?題目:
編寫一個 SQL 查詢,滿足條件:無論 person 是否有地址信息,都需要基于表1和表2兩表提供?person 的以下信息:
FirstName, LastName, City, State
LeetCode原題地址,點擊進入~
表1: Person
+-------------+---------+ | 列名 | 類型 | +-------------+---------+ | PersonId | int | | FirstName | varchar | | LastName | varchar | +-------------+---------+ PersonId 是Person表主鍵?表2: Address
+-------------+---------+ | 列名 | 類型 | +-------------+---------+ | AddressId | int | | PersonId | int | | City | varchar | | State | varchar | +-------------+---------+ AddressId 是Address表主鍵 PersonId 是表 Person 的外鍵解題思路
????????1. 我們先通讀一下題目,先看題目中提到的表1(person)和表2(address),從表的結構可以看出,表1(person)是人的姓名信息,表2(address)是人的地址信息。
???? ?? 2. 我們都要通過Person表與AddressId表來查詢出(FirstName, LastName, City, State)這四個字段的信息。查詢結果是兩個表里的列名,所以需要多表查詢。
??????? 3. 可能不是每個人都有地址信息,所以查詢出來的數據有的person就會有City,State兩個字段的信息,有的person就會沒有,對應顯示為null。考慮到有的人可能沒有地址信息,要是查詢結構要查所有人,需要保留表1(Person)里的全部數據,所以用左聯結(left join)。? ?
??????? 4. 表 Address 中的 PersonId 是表 Person 的外關鍵字,兩個表通過personId產生聯結。
代碼測試
?這里我們使用的是左外連接
select FirstName, LastName, City, State from Person left join Address on Person.PersonId = Address.PersonId; 在LeetCode上執行測試是否成功?
?與預期結果一致,通過!
?
知識點小結
聯表查詢之外連接
? 該題目主要考察了聯表查詢外連接的相關知識點,接下來帶著小伙伴們快速回顧一下外連接的相關知識點,幫助大家學習與鞏固。
外連接分為三種:左外連接(left join),右外連接(right join),全外連接(full join)。這里我們省略了outer 這個關鍵字。
外連接的一個重要特點:至少有一方保留全集,沒有匹配行用NULL代替。
下面小夢把這三種外連接簡單說一下:
??? 1. LEFT OUTER JOIN,簡稱LEFT JOIN,左外連接(左連接)
????? 結果集保留左表的所有行,但右表只包含與左表匹配的行。右表相應的空行為NULL值。
SELECT * FROM 表1 LEFT JOIN 表2 ON 表1.xx = 表2.xx??? 2. RIGHT OUTER JOIN,簡稱RIGHT JOIN,右外連接 (右連接)
?????? 結果集保留右表的所有行,但左表只包含與右表匹配的行。左表相應的空行為NULL值。
SELECT * FROM 表1 RIGHT JOIN 表2 ON 表1.xx = 表2.xx ???? 3. FULL OUTER JOIN,簡稱FULL JOIN,全外連接
?????? 會把兩個表所有的行都顯示在結果表中。
SELECT * FROM 表1 FULL JOIN 表2 ON 表1.xx = 表2.xx?
?
題目二:第二高的薪水
題目概述
?Employee?表
Employee 表 +----+--------+ | Id | Salary | +----+--------+ | 1 | 100 | | 2 | 200 | | 3 | 300 | +----+--------+?
- mployee?表中第二高的薪水(Salary),如果不存在第二高的薪水,那么查詢應返回 null。
- 例如上述?Employee?表,SQL查詢應該返回?200 作為第二高的薪水。
👇LeetCode原題地址,點擊進入~https://leetcode-cn.com/problems/combine-two-tables/
解題思路
?方式一
???? 2. 然后我們把第一步的查詢語句作為一個子句,我們通過where條件,使salary小于該子句得到的最高薪水。簡單來講就是我查詢到一個小于最高的薪水的最高薪水,不就是第二高薪水嘛。
select max(salary) from Employee where salary < (select max(salary) from Employee);??? 3. 接下來我們根據題意還需要做一個null判斷,如果不存在第二高薪水,就返回null值。這里我們用到了ifnull函數(文章知識點總結部分會有對ifnull函數的講解哦~)。
題解:
select ifnull(( select max(salary) from Employee where salary < (select max(salary) from Employee)),null) as SecondHighestSalary;方式二
題解:
##limit selectifnull((select distinct Salaryfrom Employeeorder by Salary desclimit 1,1), null) as SecondHighestSalary;## limit offset selectifnull((select distinct Salaryfrom Employeeorder by Salary desclimit 1 offset 1), null) as SecondHighestSalary;代碼測試
方式一
select ifnull(( select max(salary) from Employee where salary < (select max(salary) from Employee)),null) as SecondHighestSalary;?
?輸出與預期結果一致,答題成功!?
?
方式二
limit
selectifnull((select distinct Salaryfrom Employeeorder by Salary desclimit 1,1), null) as SecondHighestSalary;?
?輸出與預期結果一致,答題成功!
?
?limit offset
SELECTIFNULL((SELECT DISTINCT SalaryFROM EmployeeORDER BY Salary DESCLIMIT 1 OFFSET 1),NULL) AS SecondHighestSalary?
?輸出與預期結果一致,答題成功!
?
知識點小結
limit子句
我們來簡單回顧一下limit與limit offset的知識點,要常常溫故而知新~
ifnull函數
通過今天這一題,相信小伙伴們對ifnull函數也有些認識了。
ifnull(expression ,y)函數解釋:
如果第一個參數的表達式 expression 為 NULL,則返回第二個參數y的值(此題中是返回null值)。
如果第一個參數的表達式 expression 為 不為NULL,則返回第一個參數表達式expression的值。
題目三:超過經理收入的員工
題目概述
?Employee?表
+----+-------+--------+-----------+ | Id | Name | Salary | ManagerId | +----+-------+--------+-----------+ | 1 | Joe | 70000 | 3 | | 2 | Henry | 80000 | 4 | | 3 | Sam | 60000 | NULL | | 4 | Max | 90000 | NULL | +----+-------+--------+-----------+題目:Employee?表包含所有員工,他們的經理也屬于員工。每個員工都有一個 Id,此外還有一列對應員工的經理的 Id。給定?Employee?表,編寫一個 SQL 查詢,該查詢可以獲取收入超過他們經理的員工的姓名。在上面的表格中,Joe 是唯一一個收入超過他的經理的員工。查詢出的結果如下所示。
+----------+ | Employee | +----------+ | Joe | +----------+👇LeetCode原題地址~https://leetcode-cn.com/problems/employees-earning-more-than-their-managers/
解題思路
?????首先根據題意,Employee表包含所有員工,他們的經理也屬于員工。每個員工都有一個 Id,此外還有一列對應員工的經理的 Id。那我們看到字段ManagerId就是對應員工的經理Id,由Employee表得知joe對應的經理Id是3,Henry對應的經理Id是4。經理也屬于員工,id3對應的是Sam,Id4對應的是Max,也就是說joe對應的經理是Sam,Henry對應的經理是Max。
??????? 因為表既有員工信息又有經理信息,所以我們需要獲取兩次信息,我們可以把Employee既看成員工表又看成經理表。題目要求我們查找出員工工資大于經理的,那我們可以通過id字段與ManagerId字段做連接,加一個員工Salary大于經理Salary條件即可。具體方法如下。
方法一
????????表中存在員工與經理兩種信息,我們需要獲取兩次信息,然后使用Where語句做條件篩查,找出員工工資大于經理的數據。
??????? 題解1:
SELECT staff.Name AS 'Employee' FROMEmployee AS staff,Employee AS manager WHEREstaff.ManagerId = manager.Id AND staff.Salary > manager.Salary方法二
?????????表中存在員工與經理兩種信息,我們需要獲取兩次信息,除了使用where語句外,我們還可以使用內連接,通過on語句做條件篩查來找出員工工資大于經理的數據。
??????? 題解2:
SELECT staff.NAME AS 'Employee' FROM Employee AS staff JOIN Employee AS manager ON staff .ManagerId = manager.Id AND staff .Salary > manager.Salary代碼測試
?方法一
SELECT staff.Name AS 'Employee' FROMEmployee AS staff,Employee AS manager WHEREstaff.ManagerId = manager.Id AND staff.Salary > manager.Salary??與預測結果一致,成功!
方法二
SELECT staff.NAME AS 'Employee' FROM Employee AS staff JOIN Employee AS manager ON staff .ManagerId = manager.Id AND staff .Salary > manager.Salary??與預測結果一致,成功!
知識點小結
內連接與外連接
小夢用極簡單的方式帶小伙伴們過一遍內連接與外連接。
?表1 classa?????????????
?????????
表2 classb
1. 內連接 inner join (join 默認就是內連接)
表1與表2的交集,用上面兩個表演示一下
select classa.id as aid,classb.id as bid from classa inner join classb on classa.id = classb.id;?查詢的結果是classa與classb的交集
?2. 左外連接 left join
結果集保留左表的所有行,但右表只包含與左表匹配的行。右表相應的空行為NULL值。
select classa.id as aid,classb.id as bid from classa left join classb on classa.id = classb.id;?3. 右外連接 right join
結果集保留右表的所有行,但左表只包含與右表匹配的行。左表相應的空行為NULL值。
select classa.id as aid,classb.id as bid from classa right join classb on classa.id = classb.id;4. 全外連接 full join
會把兩個表所有的行都顯示在結果表中。
select classa.id as aid,classb.id as bid from classa full join classb on classa.id = classb.id;小伙伴們注意啦!!!
MySQL不支持full join!!!MySQL不支持full join!!!MySQL不支持full join!!!
重要的事情要說三遍!!!那怎么實現和full join一樣的效果呢?那就要通過使用union來實現,具體實現SQL語句如下
select classa.id as aid,classb.id as bid from classa left join classb on classa.id = classb.id union select classa.id as aid,classb.id as bid from classa right join classb on classa.id = classb.id;?
題目四:查找重復的電子郵箱
題目概述
?題目:
編寫一個 SQL 查詢,查找?Person 表中所有重復的電子郵箱。
Person表
+----+---------+ | Id | Email | +----+---------+ | 1 | a@b.com | | 2 | c@d.com | | 3 | a@b.com | +----+---------+根據以上輸入,你的查詢應返回以下結果:
+---------+ | Email | +---------+ | a@b.com | +---------+解題思路
??其實這道題很簡單啦,相信小伙伴們心中已經知道該怎么做了,趕緊去LeetCode揮筆寫下答案測試一番吧!!測試完可以再看看小夢與大家的思路是否一致呢,如果有多種思路,歡迎留言寫下你們的思路與解法,大家互相學習學習~
??????? 根據題意,要找出表中所有重復的電子郵箱,也就是Email字段對應的數據有重復的我需要查找出來。那我們可以使用count函數來獲取Email中各電子郵箱的數量,只要數量大于1就是題目中要求的。接下來,根據該思路,小夢列出一下三種解法,小伙伴們如果有其它思路,歡迎補充~
方法1
我們可以先查出Email和對應Email的個數,把查出的內容當作一個臨時表,在通過查該臨時表,找出Email數量大于的1的,這樣我們就查找出了題目所要求的【找出表中所有重復的電子郵箱】。
題解:
select Email from (select Email, count(Email) as num from Person group by Email) as temporary where num > 1;方法2
我們可以通過group by對Email進行分組,然后通過having進行條件篩查,having后面可以運用聚合函數非常方便(知識點小結部分會有group by與having的簡單講解,小伙伴們記得查閱哦~)。通過聚合函數count(Email)在having后進行條件篩查,找出Email個數大于1的,這樣我們就查找出了題目所要求的【找出表中所有重復的電子郵箱】。
題解:
select Email from Person group by Email having count(Email) > 1;方法3
第三種方法大家可以發散一下思維,如果不用count函數怎么知道重復的Email呢?怎么查呢?小夢來帶小伙伴們一起思考,首先我們可以想想,前兩種方法實質上都是通過查出Email數判斷是否大于1,大于1就是我們所要的答案,不大1就不是。那大家有沒有注意表Person雖然Email有重復的,但是id是唯一的,那我們就可以把Person表看成兩張表,一張a表和一張b表。連接兩張表,where語句后面加上a表的Email等于b表的Email和a表的id不等于b表的id。然后查詢Email做去重操作,就得到了我們想要的答案。
題解:
select distinct a.Email from Person a,Person b where a.Email = b.Email and a.id <> b.id;代碼測試
?方法1
select Email from (select Email, count(Email) as num from Person group by Email) as temporary where num > 1;輸入題解,進行測試
?測試成功!
方法2
select Email from Person group by Email having count(Email) > 1;輸入題解,進行測試
?測試成功!
方法3
select distinct a.Email from Person a,Person b where a.Email = b.Email and a.id <> b.id;輸入題解,進行測試
測試成功!
知識點小結
group by與having子句
SQL中的數據可以按列名分組,可以搭配聚合函數一起使用,方便我們對于數據的查詢與獲取。
例:
SELECT count(stuname) FROM student GROUP BY student_class;使用GROUP BY分組語句可以與WHERE語句一起使用,當然這里有個非常重要的地方希望小伙伴們記下來,非常重要!->當一條SQL中有聚合函數,WHERE語句,GRUOP BY語句時,他們的執行順序是怎么的呢?WHERE >GROUP BY>聚合函數。?
所以在WHERE語句執行過濾條件中我們不能使用聚合函數,使用的話就會報錯,在這我們可以使用HAVING子句執行過濾條件篩查時使用聚合函數。小伙伴們一定要記住!
最后呢小夢再分享一下SQL查詢語句各關鍵字的執行順序,可以拿小本本記一下了,有用的很~
【重點】SQL的執行順序:
?
題目五:從不訂購的顧客
題目概述
Customers 表:
+----+-------+ | Id | Name | +----+-------+ | 1 | Joe | | 2 | Henry | | 3 | Sam | | 4 | Max | +----+-------+Orders 表:
+----+------------+ | Id | CustomerId | +----+------------+ | 1 | 3 | | 2 | 1 | +----+------------+某網站包含兩個表,Customers 表和 Orders 表。編寫一個 SQL 查詢,找出所有從不訂購任何東西的客戶。
例如給定上述表格,你的查詢應返回:
+-----------+ | Customers | +-----------+ | Henry | | Max | +-----------+LeetCode原題鏈接~ 點擊進入https://leetcode-cn.com/problems/customers-who-never-order/
解題思路
?根據題目,我們先看題目要求我們查什么,要查出從不訂購任何東西的顧客。根據這一點我們可以從Orders 訂單表中得知CustomerId為1和3的是訂購過東西的顧客,而2和4則沒有訂購過任何東西。再從Customers 顧客表中查id2與id4對應的顧客名字就查到了。
方法一
1. 根據解題思路,我們可以先寫一個子查詢查出Orders訂單表中對應的CustomerId顧客Id
select customerid from orders;2. 查出顧客Id后,我們就知道誰買過東西誰從來不買東西。我們再通過NOT IN子句給顧客Id做限制,查Customers表中顧客Id不在Orders表中的就是題目所要求的。
select customers.name as 'Customers' from customers where customers.id not in (select customerid from orders);LeetCode原題解析https://leetcode-cn.com/problems/customers-who-never-order/solution/cong-bu-ding-gou-de-ke-hu-by-leetcode/
方法二
我們通過左外鏈接,把Customers 表與Orders 表鏈接起來,我們只需要查鏈接后Orders表的數據為NULL的數據,就是從來沒有買過東西的顧客。
select c.name as Customers from Customers c left join Orders o on c.id = o.CustomerId where o.id is null;代碼測試
?方法一
SQL代碼
select customers.name as 'Customers' from customers where customers.id not in (select customerid from orders);執行代碼,測試
測試成功!
方法二
SQL代碼
select c.name as Customers from Customers c left join Orders o on c.id = o.CustomerId where o.id is null;執行代碼,測試
測試成功
知識點小結
內連接與外連接
?表1 classa?????????????
?????????
表2 classb
1. 內連接 inner join (join 默認就是內連接)
表1與表2的交集,用上面兩個表演示一下
select classa.id as aid,classb.id as bid from classa inner join classb on classa.id = classb.id;?查詢的結果是classa與classb的交集
?2. 左外連接 left join
結果集保留左表的所有行,但右表只包含與左表匹配的行。右表相應的空行為NULL值。
select classa.id as aid,classb.id as bid from classa left join classb on classa.id = classb.id;?3. 右外連接 right join
結果集保留右表的所有行,但左表只包含與右表匹配的行。左表相應的空行為NULL值。
select classa.id as aid,classb.id as bid from classa right join classb on classa.id = classb.id;4. 全外連接 full join
會把兩個表所有的行都顯示在結果表中。
select classa.id as aid,classb.id as bid from classa full join classb on classa.id = classb.id;小伙伴們注意啦!!!
MySQL不支持full join!!!MySQL不支持full join!!!MySQL不支持full join!!!
重要的事情要說三遍!!!那怎么實現和full join一樣的效果呢?那就要通過使用union來實現,具體實現SQL語句如下
select classa.id as aid,classb.id as bid from classa left join classb on classa.id = classb.id union select classa.id as aid,classb.id as bid from classa right join classb on classa.id = classb.id;😀感謝小伙伴們支持,如果有什么疑問,歡迎留言詢問,小夢定知無不言,言無不盡!
?
?
?
總結
以上是生活随笔為你收集整理的【leetcodeMySQL每周一练】- 5道题带你练习mysql的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 谷歌浏览器检查更新时出错:无法启动更新检
- 下一篇: 基金需要经常买卖吗?为什么基金不要频繁交