# SQL (LeetCode、HackerRank)
- [w3schools:SQL](https://www.w3schools.com/sql/default.asp)
- [SQL語法教學](https://www.1keydata.com/tw/sql/sql.html)
- [runoob](http://www.runoob.com/sql/sql-orderby.html)
> - https://dotblogs.com.tw/joysdw12/2011/12/28/63596
> > [SQL] 於多筆重複資料中取得該重複群組中最新一筆資料)
```
THIS WORKED on MySQL
```
```
SQL Syntax Running Priority
FROM -> ON -> JOIN -> WHERE -> GROUP BY ->
WITH -> HAVING -> SELECT -> DISTINCT -> ORDER BY
```
#### 更複雜的SQL語法
- [進階SQL](https://www.1keydata.com/tw/sql/advanced.html)
- 先前公司資料庫未完全正規化,所以還是會有主鍵重覆值的問題,因為要轉拋資料到另外一個資料庫,所以在編寫SQL時"盡可能"撈出資料未有重覆情況,若是在SQL方面可解決,就不會用程式去一一比對處理反而效能受到影響。後續若還是無法將重覆情況順利塞到另一資料表,直接使用"Update data if it already exists INSERT if it does not exist".”
``` SQL=
INSERT INTO...ON DUPLICATE KEY UPDATE
```
``` SQL=
SELECT a.Type , a.Qty, a.Amount
FROM OrderSummary AS a
WHERE (a.Type, a.Qty) IN
(SELECT Type,MAX(Qty)
FROM OrderSummary
GROUP BY Type);
```
#### 175. Combine Two Tables (LEFT JOIN)
- 透過資料表pserson的主鍵PersonID與Address的PersonID left join on
```SQL=
# Write your MySQL query statement below
Select p.FirstName as FirstName, p.LastName as LastName, a.City as City, a.State as State
from Person as p
left join Address as a
on p.PersonId = a.PersonId;
```
#### 176. Second Highest Salary ()
- 第一方法:先用(select max(Salary) from Employee)找出最大的salary,與每個Salary比較後會找到第二大的,之後透過select max找出最大值,簡單來說就是先把第一大的排除。
```SQL=
select max(Salary) as SecondHighestSalary
from Employee
Where Salary < (select max(Salary) from Employee);
```
- 第二種方法:用ORDER BY DECS Limit 1 降序取最大值做比較
```SQL=
select max(Salary) as SecondHighestSalary
from Employee
Where Salary < (select Salary from Employee ORDER BY Salary Desc limit 1);
```
#### 178. Rank Scores
- 要找出S2中比S1大的Score且不重覆,因為最高值找到的個數為0,需要將count出來的值+1做AS Rank,最後用ORDER BY DESC
```SQL=
# Write your MySQL query statement below
SELECT S1.Score AS Score , (SELECT Count(DISTINCT(Score))
FROM Scores AS S2
WHERE S2.Score > S1.Score ) + 1 AS Rank
FROM Scores AS S1
ORDER BY S1.Score DESC
;
```
#### 180. Consecutive Numbers
- 透過as三個資料表做比較,採取Id + 1 方式,在比較是否為三次連續的值,最後用distinct過濾重覆值將值選出。
```SQL=
# Write your MySQL query statement below
select distinct(L1.Num) as ConsecutiveNums
from Logs as L1, Logs as L2, Logs as L3
WHERE L1.Id + 1 = L2.Id and L2.Id + 1 = L3.Id and L1.Num = L2.Num and L2.Num = L3.Num;
```
#### 181. Employees Earning More Than Their Managers
- 第一種:主要找到員工比管理者薪水多的,所以AS出兩個資料表e1,e2,在用where找出哪個員工是被管理的,並且薪資是大於e2.Id的
```SQL=
SELECT e1.Name as Employee
FROM
Employee AS e1,
Employee AS e2
WHERE
e1.ManagerId = e2.Id
AND e1.Salary > e2.Salary
;
```
- 第二種 使用LEFT JOIN As e2 ON 哪個員工是被管理的e1.ManagerId = e2.Id,Where薪資是大於e2.Id的
```SQL=
SELECT e1.Name As Employee
FROM
Employee As e1
LEFT JOIN
Employee As e2
ON
e1.ManagerId = e2.Id
WHERE
e1.Salary > e2.Salary
;
```
#### 182. Duplicate Emails
- 第一種:先用GROUP BY群組後用Having 篩選並使用聚合函數找出count(email)大於1的
```SQL=
# Write your MySQL query statement below
SELECT Email
FROM Person
GROUP BY Email
HAVING count(Email) > 1
;
```
- 第二種:先as兩個資料表後,用WHERE篩選出email相同但id不同的,這種方法是self join。也可以用 (INNER JOIN Person as P2)或是單純JOIN
```SQL=
SELECT DISTINCT p1.Email
FROM Person AS p1, Person AS p2
WHERE p1.Email = p2.Email and p1.id != p2.id
;
```
#### 183. Customers Who Never Order
- 第一種:使用LEFT JOIN orders on C.id = O.CustomerId,在用WHERE 找出O.Id是Null的客戶。
```SQL=
SELECT C.Name as Customers
FROM Customers as C
LEFT JOIN Orders as O
ON C.Id = O.CustomerId
WHERE O.Id IS NULL
;
```
- 第二種:直接用WHERE找出C.Id沒有在在Orders中的CId。
```SQL=
SELECT Customers.Name as Customers
FROM Customers
WHERE Customers.Id NOT IN
(
SELECT CustomerId FROM Orders
);
```
#### 184. Department Highest Salary
- 將兩個資料表做JOIN後,使用GROUP BY 群組後找出薪資MAX最大的員工,用WHERE (e.DepartmentId, e.Salary) IN 若是在此資料表中則,將值帶出。
```SQL=
SELECT D.Name as Department, E.Name as Employee, E.Salary as Salary
FROM Employee as e
JOIN Department as D
ON e.DepartmentId = D.Id
WHERE (e.DepartmentId, e.Salary) IN
(SELECT DepartmentId, MAX(Salary)
FROM Employee
GROUP BY DepartmentId
)
;
```
#### 185. Department Top Three Salaries (hard)
- 先JOIN(INNER JOIN也可)兩個資料表依靠DepartmentId(外部索引)連結,E2.Salary中比E1的資料表找出比E1.Salary(1 | Joe | 85000 | 1 )薪水還高的Salary有幾位,並且是在同一個部門,因為要在每個部門找出前三高的,所以需要過濾重覆Salary做計數後的值要小於3。(若找出來數值是0那就代表是第一高薪的,若count出來大於3則代表非前三高排除)
```SQL=
SELECT D.Name AS Department, E1.Name AS Employee, E1.Salary AS Salary
FROM Employee AS E1
JOIN Department AS D
ON E1.DepartmentId = D.Id
WHERE 3 > ( SELECT count(DISTINCT(Salary))
FROM Employee AS E2
WHERE E2.DepartmentId = E1.DepartmentId AND E2.Salary > E1.Salary
)
;
```
#### 196. Delete Duplicate Emails
- 找出重覆值並刪除,若P1.Id 比 P2.Id 大 則代表此紀錄是後續新增的
```SQL=
DELETE P1
FROM Person as P1, Person as P2
WHERE P1.Email = P2.Email AND P1.Id > P2.Id
;
```
#### 197. Rising Temperature
- 先self JOIN AS W2,使用DATEDIFF去找出相差是正數1的日期(代表是第二天-第一天),並且第二天的溫度比第一天的溫度高。
```SQL=
SELECT W1.Id
FROM Weather AS W1
JOIN Weather AS W2
WHERE DATEDIFF(W1.RecordDate, W2.RecordDate) = 1 AND W1.Temperature > W2.Temperature
;
```
#### 262. Trips and Users (Hard)
```SQL=
```
#### 595. Big Countries
```SQL=
SELECT name, population, area
FROM World
WHERE area > 3000000 OR population > 25000000;
```
#### 596. Classes More Than 5 Students
- 先將class做群組,用HAVING 找出每門課的學生人數>=5的課程,並且學生是不能重覆的。
```SQL=
SELECT class
FROM courses
GROUP BY class
HAVING count(DISTINCT student) >= 5
;
```
#### 601. Human Traffic of Stadium
- AS 三個資料表,先找出people>=100,因為要找出連續三天以上人數都>=100的,所以需要對id進行判斷,三種條件符合其中一項即為正確。
```SQL=
# Write your MySQL query statement below
SELECT DISTINCT S1.id , S1.visit_date , S1.people
FROM stadium AS S1, stadium AS S2, stadium AS S3
WHERE S1.people >= 100 AND S2.people >= 100 AND S3.people >=100 AND
((S1.id + 1 = S2.id AND S1.id + 2 = S3.id)
OR
(S1.id - 1 = S2.id AND S1.id + 1 = S3.id)
OR
(S1.id - 1 = S2.id AND S1.id - 2 = S3.id))
ORDER BY S1.id
;
```
#### 627. Swap Salary
- 當sex等於f則換成m,若不等於f則換成f
```SQL=
update salary
SET sex=(IF(sex='f','m','f'));
```
###### tags: `SQL`