CS-Notes/docs/notes/Leetcode-Database 题解.md

932 lines
20 KiB
Markdown
Raw Normal View History

2019-03-27 20:46:47 +08:00
# 595. Big Countries
2018-06-03 23:17:02 +08:00
https://leetcode.com/problems/big-countries/description/
2019-03-27 20:46:47 +08:00
## Description
2018-06-03 23:17:02 +08:00
```html
+-----------------+------------+------------+--------------+---------------+
2019-03-27 20:46:47 +08:00
| name            | continent  | area       | population   | gdp           |
2018-06-03 23:17:02 +08:00
+-----------------+------------+------------+--------------+---------------+
2019-03-27 20:46:47 +08:00
| 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     |
2018-06-03 23:17:02 +08:00
+-----------------+------------+------------+--------------+---------------+
```
2019-03-27 20:46:47 +08:00
查找面积超过 3,000,000 或者人口数超过 25,000,000 的国家。
2018-06-03 23:17:02 +08:00
```html
+--------------+-------------+--------------+
2019-03-27 20:46:47 +08:00
| name         | population  | area         |
2018-06-03 23:17:02 +08:00
+--------------+-------------+--------------+
2019-03-27 20:46:47 +08:00
| Afghanistan  | 25500100    | 652230       |
| Algeria      | 37100000    | 2381741      |
2018-06-03 23:17:02 +08:00
+--------------+-------------+--------------+
```
2019-03-27 20:46:47 +08:00
## SQL Schema
2018-06-03 23:17:02 +08:00
```sql
2019-03-27 20:46:47 +08:00
DROP TABLE
2018-06-03 23:17:02 +08:00
IF
2019-03-27 20:46:47 +08:00
    EXISTS World;
CREATE TABLE World ( NAME VARCHAR ( 255 ), continent VARCHAR ( 255 ), area INT, population INT, gdp INT );
INSERT INTO World ( NAME, continent, area, population, gdp )
2018-06-03 23:17:02 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( 'Afghanistan', 'Asia', '652230', '25500100', '203430000' ),
    ( 'Albania', 'Europe', '28748', '2831741', '129600000' ),
    ( 'Algeria', 'Africa', '2381741', '37100000', '1886810000' ),
    ( 'Andorra', 'Europe', '468', '78115', '37120000' ),
    ( 'Angola', 'Africa', '1246700', '20609294', '1009900000' );
2018-06-03 23:17:02 +08:00
```
2019-03-27 20:46:47 +08:00
## Solution
2018-06-03 23:17:02 +08:00
```sql
2019-03-27 20:46:47 +08:00
SELECT name,
    population,
    area
2018-06-03 23:17:02 +08:00
FROM
2019-03-27 20:46:47 +08:00
    World
2018-06-03 23:17:02 +08:00
WHERE
2019-03-27 20:46:47 +08:00
    area > 3000000
    OR population > 25000000;
2018-06-03 23:17:02 +08:00
```
2019-03-27 20:46:47 +08:00
# 627. Swap Salary
2018-06-03 23:17:02 +08:00
https://leetcode.com/problems/swap-salary/description/
2019-03-27 20:46:47 +08:00
## Description
2018-06-03 23:17:02 +08:00
```html
2019-03-27 20:46:47 +08:00
| id | name | sex | salary |
2018-06-03 23:17:02 +08:00
|----|------|-----|--------|
2019-03-27 20:46:47 +08:00
| 1  | A    | m   | 2500   |
| 2  | B    | f   | 1500   |
| 3  | C    | m   | 5500   |
| 4  | D    | f   | 500    |
2018-06-03 23:17:02 +08:00
```
2019-03-27 20:46:47 +08:00
只用一个 SQL 查询 sex 字段反转。
2018-06-03 23:17:02 +08:00
```html
2019-03-27 20:46:47 +08:00
| id | name | sex | salary |
2018-06-03 23:17:02 +08:00
|----|------|-----|--------|
2019-03-27 20:46:47 +08:00
| 1  | A    | f   | 2500   |
| 2  | B    | m   | 1500   |
| 3  | C    | f   | 5500   |
| 4  | D    | m   | 500    |
2018-06-03 23:17:02 +08:00
```
2019-03-27 20:46:47 +08:00
## SQL Schema
2018-06-03 23:17:02 +08:00
```sql
2019-03-27 20:46:47 +08:00
DROP TABLE
2018-06-03 23:17:02 +08:00
IF
2019-03-27 20:46:47 +08:00
    EXISTS salary;
CREATE TABLE salary ( id INT, NAME VARCHAR ( 100 ), sex CHAR ( 1 ), salary INT );
INSERT INTO salary ( id, NAME, sex, salary )
2018-06-03 23:17:02 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( '1', 'A', 'm', '2500' ),
    ( '2', 'B', 'f', '1500' ),
    ( '3', 'C', 'm', '5500' ),
    ( '4', 'D', 'f', '500' );
2018-06-03 23:17:02 +08:00
```
2019-03-27 20:46:47 +08:00
## Solution
2018-06-03 23:17:02 +08:00
```sql
2019-03-27 20:46:47 +08:00
UPDATE salary
SET sex = CHAR ( ASCII(sex) ^ ASCII( 'm' ) ^ ASCII( 'f' ) );
2018-06-03 23:17:02 +08:00
```
2019-03-27 20:46:47 +08:00
# 620. Not Boring Movies
2018-06-03 23:17:02 +08:00
https://leetcode.com/problems/not-boring-movies/description/
2019-03-27 20:46:47 +08:00
## Description
2018-06-03 23:17:02 +08:00
```html
+---------+-----------+--------------+-----------+
2019-03-27 20:46:47 +08:00
|   id    | movie     |  description |  rating   |
2018-06-03 23:17:02 +08:00
+---------+-----------+--------------+-----------+
2019-03-27 20:46:47 +08:00
|   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     |
2018-06-03 23:17:02 +08:00
+---------+-----------+--------------+-----------+
```
2019-03-27 20:46:47 +08:00
查找 id 为奇数并且 description 不是 boring 的电影 rating 降序。
2018-06-03 23:17:02 +08:00
```html
+---------+-----------+--------------+-----------+
2019-03-27 20:46:47 +08:00
|   id    | movie     |  description |  rating   |
2018-06-03 23:17:02 +08:00
+---------+-----------+--------------+-----------+
2019-03-27 20:46:47 +08:00
|   5     | House card|   Interesting|   9.1     |
|   1     | War       |   great 3D   |   8.9     |
2018-06-03 23:17:02 +08:00
+---------+-----------+--------------+-----------+
```
2019-03-27 20:46:47 +08:00
## SQL Schema
2018-06-03 23:17:02 +08:00
```sql
2019-03-27 20:46:47 +08:00
DROP TABLE
2018-06-03 23:17:02 +08:00
IF
2019-03-27 20:46:47 +08:00
    EXISTS cinema;
CREATE TABLE cinema ( id INT, movie VARCHAR ( 255 ), description VARCHAR ( 255 ), rating FLOAT ( 2, 1 ) );
INSERT INTO cinema ( id, movie, description, rating )
2018-06-03 23:17:02 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( 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 );
2018-06-03 23:17:02 +08:00
```
2019-03-27 20:46:47 +08:00
## Solution
2018-06-03 23:17:02 +08:00
```sql
SELECT
2019-03-27 20:46:47 +08:00
    *
2018-06-03 23:17:02 +08:00
FROM
2019-03-27 20:46:47 +08:00
    cinema
2018-06-03 23:17:02 +08:00
WHERE
2019-03-27 20:46:47 +08:00
    id % 2 = 1
    AND description != 'boring'
ORDER BY
    rating DESC;
2018-06-03 23:17:02 +08:00
```
2019-03-27 20:46:47 +08:00
# 596. Classes More Than 5 Students
2018-06-03 23:17:02 +08:00
https://leetcode.com/problems/classes-more-than-5-students/description/
2019-03-27 20:46:47 +08:00
## Description
2018-06-03 23:17:02 +08:00
```html
+---------+------------+
2019-03-27 20:46:47 +08:00
| student | class      |
2018-06-03 23:17:02 +08:00
+---------+------------+
2019-03-27 20:46:47 +08:00
| A       | Math       |
| B       | English    |
| C       | Math       |
| D       | Biology    |
| E       | Math       |
| F       | Computer   |
| G       | Math       |
| H       | Math       |
| I       | Math       |
2018-06-03 23:17:02 +08:00
+---------+------------+
```
2019-03-27 20:46:47 +08:00
查找有五名及以上 student  class。
2018-06-03 23:17:02 +08:00
```html
+---------+
2019-03-27 20:46:47 +08:00
| class   |
2018-06-03 23:17:02 +08:00
+---------+
2019-03-27 20:46:47 +08:00
| Math    |
2018-06-03 23:17:02 +08:00
+---------+
```
2019-03-27 20:46:47 +08:00
## SQL Schema
2018-06-03 23:17:02 +08:00
```sql
2019-03-27 20:46:47 +08:00
DROP TABLE
2018-06-03 23:17:02 +08:00
IF
2019-03-27 20:46:47 +08:00
    EXISTS courses;
CREATE TABLE courses ( student VARCHAR ( 255 ), class VARCHAR ( 255 ) );
INSERT INTO courses ( student, class )
2018-06-03 23:17:02 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( 'A', 'Math' ),
    ( 'B', 'English' ),
    ( 'C', 'Math' ),
    ( 'D', 'Biology' ),
    ( 'E', 'Math' ),
    ( 'F', 'Computer' ),
    ( 'G', 'Math' ),
    ( 'H', 'Math' ),
    ( 'I', 'Math' );
2018-06-03 23:17:02 +08:00
```
2019-03-27 20:46:47 +08:00
## Solution
2018-06-03 23:17:02 +08:00
```sql
SELECT
2019-03-27 20:46:47 +08:00
    class
2018-06-03 23:17:02 +08:00
FROM
2019-03-27 20:46:47 +08:00
    courses
GROUP BY
    class
2018-06-03 23:17:02 +08:00
HAVING
2019-03-27 20:46:47 +08:00
    count( DISTINCT student ) >= 5;
2018-06-03 23:17:02 +08:00
```
2019-03-27 20:46:47 +08:00
# 182. Duplicate Emails
2018-06-03 23:17:02 +08:00
https://leetcode.com/problems/duplicate-emails/description/
2019-03-27 20:46:47 +08:00
## Description
2018-06-03 23:17:02 +08:00
邮件地址表:
```html
+----+---------+
2019-03-27 20:46:47 +08:00
| Id | Email   |
2018-06-03 23:17:02 +08:00
+----+---------+
2019-03-27 20:46:47 +08:00
| 1  | a@b.com |
| 2  | c@d.com |
| 3  | a@b.com |
2018-06-03 23:17:02 +08:00
+----+---------+
```
查找重复的邮件地址:
```html
+---------+
2019-03-27 20:46:47 +08:00
| Email   |
2018-06-03 23:17:02 +08:00
+---------+
2019-03-27 20:46:47 +08:00
| a@b.com |
2018-06-03 23:17:02 +08:00
+---------+
```
2019-03-27 20:46:47 +08:00
## SQL Schema
2018-06-03 23:17:02 +08:00
```sql
2019-03-27 20:46:47 +08:00
DROP TABLE
2018-06-03 23:17:02 +08:00
IF
2019-03-27 20:46:47 +08:00
    EXISTS Person;
CREATE TABLE Person ( Id INT, Email VARCHAR ( 255 ) );
INSERT INTO Person ( Id, Email )
2018-06-03 23:17:02 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( 1, 'a@b.com' ),
    ( 2, 'c@d.com' ),
    ( 3, 'a@b.com' );
2018-06-03 23:17:02 +08:00
```
2019-03-27 20:46:47 +08:00
## Solution
2018-06-03 23:17:02 +08:00
```sql
SELECT
2019-03-27 20:46:47 +08:00
    Email
2018-06-03 23:17:02 +08:00
FROM
2019-03-27 20:46:47 +08:00
    Person
GROUP BY
    Email
2018-06-03 23:17:02 +08:00
HAVING
2019-03-27 20:46:47 +08:00
    COUNT( * ) >= 2;
2018-06-03 23:17:02 +08:00
```
2019-03-27 20:46:47 +08:00
# 196. Delete Duplicate Emails
2018-06-03 23:17:02 +08:00
2018-07-09 23:40:46 +08:00
https://leetcode.com/problems/delete-duplicate-emails/description/
2019-03-27 20:46:47 +08:00
## Description
2018-06-03 23:17:02 +08:00
邮件地址表:
```html
+----+---------+
2019-03-27 20:46:47 +08:00
| Id | Email   |
2018-06-03 23:17:02 +08:00
+----+---------+
2019-03-27 20:46:47 +08:00
| 1  | a@b.com |
| 2  | c@d.com |
| 3  | a@b.com |
2018-06-03 23:17:02 +08:00
+----+---------+
```
2018-07-09 23:40:46 +08:00
删除重复的邮件地址:
2018-06-03 23:17:02 +08:00
```html
2018-07-09 23:40:46 +08:00
+----+------------------+
2019-03-27 20:46:47 +08:00
| Id | Email            |
2018-07-09 23:40:46 +08:00
+----+------------------+
2019-03-27 20:46:47 +08:00
| 1  | john@example.com |
| 2  | bob@example.com  |
2018-07-09 23:40:46 +08:00
+----+------------------+
2018-06-03 23:17:02 +08:00
```
2019-03-27 20:46:47 +08:00
## SQL Schema
2018-06-03 23:17:02 +08:00
2019-03-27 20:46:47 +08:00
 182 相同。
2018-06-03 23:17:02 +08:00
2019-03-27 20:46:47 +08:00
## Solution
2018-06-03 23:17:02 +08:00
连接:
```sql
2019-03-27 20:46:47 +08:00
DELETE p1
2018-06-03 23:17:02 +08:00
FROM
2019-03-27 20:46:47 +08:00
    Person p1,
    Person p2
2018-06-03 23:17:02 +08:00
WHERE
2019-03-27 20:46:47 +08:00
    p1.Email = p2.Email
    AND p1.Id > p2.Id
2018-06-03 23:17:02 +08:00
```
子查询:
```sql
DELETE
FROM
2019-03-27 20:46:47 +08:00
    Person
2018-06-03 23:17:02 +08:00
WHERE
2019-03-27 20:46:47 +08:00
    id NOT IN ( SELECT id FROM ( SELECT min( id ) AS id FROM Person GROUP BY email ) AS m );
2018-06-03 23:17:02 +08:00
```
2019-03-27 20:46:47 +08:00
应该注意的是上述解法额外嵌套了一个 SELECT 语句如果不这么做会出现错误You can't specify target table 'Person' for update in FROM clause。以下演示了这种错误解法。
2018-06-03 23:17:02 +08:00
```sql
DELETE
FROM
2019-03-27 20:46:47 +08:00
    Person
2018-06-03 23:17:02 +08:00
WHERE
2019-03-27 20:46:47 +08:00
    id NOT IN ( SELECT min( id ) AS id FROM Person GROUP BY email );
2018-06-03 23:17:02 +08:00
```
2019-03-27 20:46:47 +08:00
参考:[pMySQL Error 1093 - Can't specify target table for update in FROM clause](https://stackoverflow.com/questions/45494/mysql-error-1093-cant-specify-target-table-for-update-in-from-clause)
2018-06-03 23:17:02 +08:00
2019-03-27 20:46:47 +08:00
# 175. Combine Two Tables
2018-05-11 23:03:49 +08:00
https://leetcode.com/problems/combine-two-tables/description/
2019-03-27 20:46:47 +08:00
## Description
2018-05-11 23:03:49 +08:00
2019-03-27 20:46:47 +08:00
Person 
2018-05-11 23:03:49 +08:00
```html
+-------------+---------+
2019-03-27 20:46:47 +08:00
| Column Name | Type    |
2018-05-11 23:03:49 +08:00
+-------------+---------+
2019-03-27 20:46:47 +08:00
| PersonId    | int     |
| FirstName   | varchar |
| LastName    | varchar |
2018-05-11 23:03:49 +08:00
+-------------+---------+
2019-03-27 20:46:47 +08:00
PersonId is the primary key column for this table.
2018-05-11 23:03:49 +08:00
```
2019-03-27 20:46:47 +08:00
Address 
2018-05-11 23:03:49 +08:00
```html
+-------------+---------+
2019-03-27 20:46:47 +08:00
| Column Name | Type    |
2018-05-11 23:03:49 +08:00
+-------------+---------+
2019-03-27 20:46:47 +08:00
| AddressId   | int     |
| PersonId    | int     |
| City        | varchar |
| State       | varchar |
2018-05-11 23:03:49 +08:00
+-------------+---------+
2019-03-27 20:46:47 +08:00
AddressId is the primary key column for this table.
2018-05-11 23:03:49 +08:00
```
2019-03-27 20:46:47 +08:00
查找 FirstName, LastName, City, State 数据而不管一个用户有没有填地址信息。
2018-05-11 23:03:49 +08:00
2019-03-27 20:46:47 +08:00
## SQL Schema
2018-05-11 23:03:49 +08:00
```sql
2019-03-27 20:46:47 +08:00
DROP TABLE
2018-06-03 21:57:52 +08:00
IF
2019-03-27 20:46:47 +08:00
    EXISTS Person;
CREATE TABLE Person ( PersonId INT, FirstName VARCHAR ( 255 ), LastName VARCHAR ( 255 ) );
DROP TABLE
2018-06-03 21:57:52 +08:00
IF
2019-03-27 20:46:47 +08:00
    EXISTS Address;
CREATE TABLE Address ( AddressId INT, PersonId INT, City VARCHAR ( 255 ), State VARCHAR ( 255 ) );
INSERT INTO Person ( PersonId, LastName, FirstName )
2018-05-11 23:03:49 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( 1, 'Wang', 'Allen' );
INSERT INTO Address ( AddressId, PersonId, City, State )
2018-05-11 23:03:49 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( 1, 2, 'New York City', 'New York' );
2018-05-11 23:03:49 +08:00
```
2019-03-27 20:46:47 +08:00
## Solution
2018-05-11 23:03:49 +08:00
使用左外连接。
```sql
2018-06-03 21:57:52 +08:00
SELECT
2019-03-27 20:46:47 +08:00
    FirstName,
    LastName,
    City,
    State
2018-06-03 21:57:52 +08:00
FROM
2019-03-27 20:46:47 +08:00
    Person P
    LEFT JOIN Address A
    ON P.PersonId = A.PersonId;
2018-05-12 21:01:57 +08:00
```
2019-03-27 20:46:47 +08:00
# 181. Employees Earning More Than Their Managers
2018-05-12 21:01:57 +08:00
https://leetcode.com/problems/employees-earning-more-than-their-managers/description/
2019-03-27 20:46:47 +08:00
## Description
2018-05-12 21:01:57 +08:00
2019-03-27 20:46:47 +08:00
Employee 
2018-05-12 21:01:57 +08:00
```html
+----+-------+--------+-----------+
2019-03-27 20:46:47 +08:00
| Id | Name  | Salary | ManagerId |
2018-05-12 21:01:57 +08:00
+----+-------+--------+-----------+
2019-03-27 20:46:47 +08:00
| 1  | Joe   | 70000  | 3         |
| 2  | Henry | 80000  | 4         |
| 3  | Sam   | 60000  | NULL      |
| 4  | Max   | 90000  | NULL      |
2018-05-12 21:01:57 +08:00
+----+-------+--------+-----------+
```
2018-08-12 22:53:28 +08:00
查找薪资大于其经理薪资的员工信息。
2018-05-12 21:01:57 +08:00
2019-03-27 20:46:47 +08:00
## SQL Schema
2018-05-12 21:01:57 +08:00
```sql
2019-03-27 20:46:47 +08:00
DROP TABLE
2018-06-03 23:17:02 +08:00
IF
2019-03-27 20:46:47 +08:00
    EXISTS Employee;
CREATE TABLE Employee ( Id INT, NAME VARCHAR ( 255 ), Salary INT, ManagerId INT );
INSERT INTO Employee ( Id, NAME, Salary, ManagerId )
2018-05-12 21:01:57 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( 1, 'Joe', 70000, 3 ),
    ( 2, 'Henry', 80000, 4 ),
    ( 3, 'Sam', 60000, NULL ),
    ( 4, 'Max', 90000, NULL );
2018-05-12 21:01:57 +08:00
```
2019-03-27 20:46:47 +08:00
## Solution
2018-05-12 21:01:57 +08:00
```sql
2018-06-03 21:57:52 +08:00
SELECT
2019-03-27 20:46:47 +08:00
    E1.NAME AS Employee
2018-06-03 21:57:52 +08:00
FROM
2019-03-27 20:46:47 +08:00
    Employee E1
    INNER JOIN Employee E2
    ON E1.ManagerId = E2.Id
    AND E1.Salary > E2.Salary;
2018-05-12 21:01:57 +08:00
```
2019-03-27 20:46:47 +08:00
# 183. Customers Who Never Order
2018-05-12 21:01:57 +08:00
https://leetcode.com/problems/customers-who-never-order/description/
2019-03-27 20:46:47 +08:00
## Description
2018-05-12 21:01:57 +08:00
2019-03-27 20:46:47 +08:00
Customers 
2018-05-12 21:01:57 +08:00
```html
+----+-------+
2019-03-27 20:46:47 +08:00
| Id | Name  |
2018-05-12 21:01:57 +08:00
+----+-------+
2019-03-27 20:46:47 +08:00
| 1  | Joe   |
| 2  | Henry |
| 3  | Sam   |
| 4  | Max   |
2018-05-12 21:01:57 +08:00
+----+-------+
```
2019-03-27 20:46:47 +08:00
Orders 
2018-05-12 21:01:57 +08:00
```html
+----+------------+
2019-03-27 20:46:47 +08:00
| Id | CustomerId |
2018-05-12 21:01:57 +08:00
+----+------------+
2019-03-27 20:46:47 +08:00
| 1  | 3          |
| 2  | 1          |
2018-05-12 21:01:57 +08:00
+----+------------+
```
查找没有订单的顾客信息:
```html
+-----------+
2019-03-27 20:46:47 +08:00
| Customers |
2018-05-12 21:01:57 +08:00
+-----------+
2019-03-27 20:46:47 +08:00
| Henry     |
| Max       |
2018-05-12 21:01:57 +08:00
+-----------+
```
2019-03-27 20:46:47 +08:00
## SQL Schema
2018-05-12 21:01:57 +08:00
```sql
2019-03-27 20:46:47 +08:00
DROP TABLE
2018-06-03 23:17:02 +08:00
IF
2019-03-27 20:46:47 +08:00
    EXISTS Customers;
CREATE TABLE Customers ( Id INT, NAME VARCHAR ( 255 ) );
DROP TABLE
2018-06-03 23:17:02 +08:00
IF
2019-03-27 20:46:47 +08:00
    EXISTS Orders;
CREATE TABLE Orders ( Id INT, CustomerId INT );
INSERT INTO Customers ( Id, NAME )
2018-05-12 21:01:57 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( 1, 'Joe' ),
    ( 2, 'Henry' ),
    ( 3, 'Sam' ),
    ( 4, 'Max' );
INSERT INTO Orders ( Id, CustomerId )
2018-05-12 21:01:57 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( 1, 3 ),
    ( 2, 1 );
2018-05-12 21:01:57 +08:00
```
2019-03-27 20:46:47 +08:00
## Solution
2018-05-12 21:01:57 +08:00
左外链接
```sql
2018-06-03 21:57:52 +08:00
SELECT
2019-03-27 20:46:47 +08:00
    C.Name AS Customers
2018-06-03 21:57:52 +08:00
FROM
2019-03-27 20:46:47 +08:00
    Customers C
    LEFT JOIN Orders O
    ON C.Id = O.CustomerId
2018-06-03 21:57:52 +08:00
WHERE
2019-03-27 20:46:47 +08:00
    O.CustomerId IS NULL;
2018-05-12 21:01:57 +08:00
```
子查询
```sql
2018-06-03 21:57:52 +08:00
SELECT
2019-03-27 20:46:47 +08:00
    Name AS Customers
2018-06-03 21:57:52 +08:00
FROM
2019-03-27 20:46:47 +08:00
    Customers
2018-06-03 21:57:52 +08:00
WHERE
2019-03-27 20:46:47 +08:00
    Id NOT IN ( SELECT CustomerId FROM Orders );
2018-05-12 21:01:57 +08:00
```
2019-03-27 20:46:47 +08:00
# 184. Department Highest Salary
2018-05-12 21:01:57 +08:00
https://leetcode.com/problems/department-highest-salary/description/
2019-03-27 20:46:47 +08:00
## Description
2018-05-12 21:01:57 +08:00
2019-03-27 20:46:47 +08:00
Employee 
2018-05-12 21:01:57 +08:00
```html
+----+-------+--------+--------------+
2019-03-27 20:46:47 +08:00
| Id | Name  | Salary | DepartmentId |
2018-05-12 21:01:57 +08:00
+----+-------+--------+--------------+
2019-03-27 20:46:47 +08:00
| 1  | Joe   | 70000  | 1            |
| 2  | Henry | 80000  | 2            |
| 3  | Sam   | 60000  | 2            |
| 4  | Max   | 90000  | 1            |
2018-05-12 21:01:57 +08:00
+----+-------+--------+--------------+
```
2019-03-27 20:46:47 +08:00
Department 
2018-05-12 21:01:57 +08:00
```html
+----+----------+
2019-03-27 20:46:47 +08:00
| Id | Name     |
2018-05-12 21:01:57 +08:00
+----+----------+
2019-03-27 20:46:47 +08:00
| 1  | IT       |
| 2  | Sales    |
2018-05-12 21:01:57 +08:00
+----+----------+
```
2019-03-27 20:46:47 +08:00
查找一个 Department 中收入最高者的信息
2018-05-12 21:01:57 +08:00
```html
+------------+----------+--------+
2019-03-27 20:46:47 +08:00
| Department | Employee | Salary |
2018-05-12 21:01:57 +08:00
+------------+----------+--------+
2019-03-27 20:46:47 +08:00
| IT         | Max      | 90000  |
| Sales      | Henry    | 80000  |
2018-05-12 21:01:57 +08:00
+------------+----------+--------+
```
2019-03-27 20:46:47 +08:00
## SQL Schema
2018-05-12 21:01:57 +08:00
```sql
2019-03-27 20:46:47 +08:00
DROP TABLE IF EXISTS Employee;
CREATE TABLE Employee ( Id INT, NAME VARCHAR ( 255 ), Salary INT, DepartmentId INT );
DROP TABLE IF EXISTS Department;
CREATE TABLE Department ( Id INT, NAME VARCHAR ( 255 ) );
INSERT INTO Employee ( Id, NAME, Salary, DepartmentId )
2018-05-12 21:01:57 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( 1, 'Joe', 70000, 1 ),
    ( 2, 'Henry', 80000, 2 ),
    ( 3, 'Sam', 60000, 2 ),
    ( 4, 'Max', 90000, 1 );
INSERT INTO Department ( Id, NAME )
2018-05-12 21:01:57 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( 1, 'IT' ),
    ( 2, 'Sales' );
2018-05-12 21:01:57 +08:00
```
2019-03-27 20:46:47 +08:00
## Solution
2018-05-12 21:01:57 +08:00
2019-03-27 20:46:47 +08:00
创建一个临时表包含了部门员工的最大薪资。可以对部门进行分组然后使用 MAX() 汇总函数取得最大薪资。
2018-06-03 21:57:52 +08:00
2018-06-09 21:43:10 +08:00
之后使用连接找到一个部门中薪资等于临时表中最大薪资的员工。
2018-06-03 21:57:52 +08:00
2018-05-12 21:01:57 +08:00
```sql
2018-06-03 21:57:52 +08:00
SELECT
2019-03-27 20:46:47 +08:00
    D.NAME Department,
    E.NAME Employee,
    E.Salary
2018-06-03 21:57:52 +08:00
FROM
2019-03-27 20:46:47 +08:00
    Employee E,
    Department D,
    ( SELECT DepartmentId, MAX( Salary ) Salary FROM Employee GROUP BY DepartmentId ) M
2018-06-03 21:57:52 +08:00
WHERE
2019-03-27 20:46:47 +08:00
    E.DepartmentId = D.Id
    AND E.DepartmentId = M.DepartmentId
    AND E.Salary = M.Salary;
2018-05-11 23:03:49 +08:00
```
2019-03-27 20:46:47 +08:00
# 176. Second Highest Salary
2018-06-03 21:57:52 +08:00
https://leetcode.com/problems/second-highest-salary/description/
2019-03-27 20:46:47 +08:00
## Description
2018-06-03 21:57:52 +08:00
```html
+----+--------+
2019-03-27 20:46:47 +08:00
| Id | Salary |
2018-06-03 21:57:52 +08:00
+----+--------+
2019-03-27 20:46:47 +08:00
| 1  | 100    |
| 2  | 200    |
| 3  | 300    |
2018-06-03 21:57:52 +08:00
+----+--------+
```
查找工资第二高的员工。
```html
+---------------------+
2019-03-27 20:46:47 +08:00
| SecondHighestSalary |
2018-06-03 21:57:52 +08:00
+---------------------+
2019-03-27 20:46:47 +08:00
| 200                 |
2018-06-03 21:57:52 +08:00
+---------------------+
```
2019-03-27 20:46:47 +08:00
没有找到返回 null 而不是不返回数据。
2018-06-03 21:57:52 +08:00
2019-03-27 20:46:47 +08:00
## SQL Schema
2018-06-03 21:57:52 +08:00
```sql
2019-03-27 20:46:47 +08:00
DROP TABLE
2018-06-03 21:57:52 +08:00
IF
2019-03-27 20:46:47 +08:00
    EXISTS Employee;
CREATE TABLE Employee ( Id INT, Salary INT );
INSERT INTO Employee ( Id, Salary )
2018-06-03 21:57:52 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( 1, 100 ),
    ( 2, 200 ),
    ( 3, 300 );
2018-06-03 21:57:52 +08:00
```
2019-03-27 20:46:47 +08:00
## Solution
2018-06-03 21:57:52 +08:00
2019-03-27 20:46:47 +08:00
为了在没有查找到数据时返回 null需要在查询结果外面再套一层 SELECT。
2018-06-03 21:57:52 +08:00
```sql
SELECT
2019-03-27 20:46:47 +08:00
    ( SELECT DISTINCT Salary FROM Employee ORDER BY Salary DESC LIMIT 1, 1 ) SecondHighestSalary;
2018-06-03 21:57:52 +08:00
```
2019-03-27 20:46:47 +08:00
# 177. Nth Highest Salary
2018-06-03 21:57:52 +08:00
2019-03-27 20:46:47 +08:00
## Description
2018-06-03 21:57:52 +08:00
2019-03-27 20:46:47 +08:00
查找工资第 N 高的员工。
2018-06-03 21:57:52 +08:00
2019-03-27 20:46:47 +08:00
## SQL Schema
2018-06-03 21:57:52 +08:00
2019-03-27 20:46:47 +08:00
 176。
2018-06-03 21:57:52 +08:00
2019-03-27 20:46:47 +08:00
## Solution
2018-06-03 21:57:52 +08:00
```sql
2019-03-27 20:46:47 +08:00
CREATE FUNCTION getNthHighestSalary ( N INT ) RETURNS INT BEGIN
2018-06-03 21:57:52 +08:00
2019-03-27 20:46:47 +08:00
SET N = N - 1;
RETURN ( SELECT ( SELECT DISTINCT Salary FROM Employee ORDER BY Salary DESC LIMIT N, 1 ) );
2018-06-03 21:57:52 +08:00
END
```
2019-03-27 20:46:47 +08:00
# 178. Rank Scores
2018-06-03 21:57:52 +08:00
https://leetcode.com/problems/rank-scores/description/
2019-03-27 20:46:47 +08:00
## Description
2018-06-03 21:57:52 +08:00
得分表:
```html
+----+-------+
2019-03-27 20:46:47 +08:00
| Id | Score |
2018-06-03 21:57:52 +08:00
+----+-------+
2019-03-27 20:46:47 +08:00
| 1  | 3.50  |
| 2  | 3.65  |
| 3  | 4.00  |
| 4  | 3.85  |
| 5  | 4.00  |
| 6  | 3.65  |
2018-06-03 21:57:52 +08:00
+----+-------+
```
将得分排序,并统计排名。
```html
+-------+------+
2019-03-27 20:46:47 +08:00
| Score | Rank |
2018-06-03 21:57:52 +08:00
+-------+------+
2019-03-27 20:46:47 +08:00
| 4.00  | 1    |
| 4.00  | 1    |
| 3.85  | 2    |
| 3.65  | 3    |
| 3.65  | 3    |
| 3.50  | 4    |
2018-06-03 21:57:52 +08:00
+-------+------+
```
2019-03-27 20:46:47 +08:00
## SQL Schema
2018-06-03 21:57:52 +08:00
```sql
2019-03-27 20:46:47 +08:00
DROP TABLE
2018-06-03 21:57:52 +08:00
IF
2019-03-27 20:46:47 +08:00
    EXISTS Scores;
CREATE TABLE Scores ( Id INT, Score DECIMAL ( 3, 2 ) );
INSERT INTO Scores ( Id, Score )
2018-06-03 21:57:52 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( 1, 3.5 ),
    ( 2, 3.65 ),
    ( 3, 4.0 ),
    ( 4, 3.85 ),
    ( 5, 4.0 ),
    ( 6, 3.65 );
2018-06-03 21:57:52 +08:00
```
2019-03-27 20:46:47 +08:00
## Solution
2018-06-03 21:57:52 +08:00
```sql
SELECT
2019-03-27 20:46:47 +08:00
    S1.score,
    COUNT( DISTINCT S2.score ) Rank
2018-06-03 21:57:52 +08:00
FROM
2019-03-27 20:46:47 +08:00
    Scores S1
    INNER JOIN Scores S2
    ON S1.score <= S2.score
GROUP BY
    S1.id
ORDER BY
    S1.score DESC;
2018-06-03 21:57:52 +08:00
```
2019-03-27 20:46:47 +08:00
# 180. Consecutive Numbers
2018-06-03 21:57:52 +08:00
https://leetcode.com/problems/consecutive-numbers/description/
2019-03-27 20:46:47 +08:00
## Description
2018-06-03 21:57:52 +08:00
数字表:
```html
+----+-----+
2019-03-27 20:46:47 +08:00
| Id | Num |
2018-06-03 21:57:52 +08:00
+----+-----+
2019-03-27 20:46:47 +08:00
| 1  |  1  |
| 2  |  1  |
| 3  |  1  |
| 4  |  2  |
| 5  |  1  |
| 6  |  2  |
| 7  |  2  |
2018-06-03 21:57:52 +08:00
+----+-----+
```
查找连续出现三次的数字。
```html
+-----------------+
2019-03-27 20:46:47 +08:00
| ConsecutiveNums |
2018-06-03 21:57:52 +08:00
+-----------------+
2019-03-27 20:46:47 +08:00
| 1               |
2018-06-03 21:57:52 +08:00
+-----------------+
```
2019-03-27 20:46:47 +08:00
## SQL Schema
2018-06-03 21:57:52 +08:00
```sql
2019-03-27 20:46:47 +08:00
DROP TABLE
2018-06-03 21:57:52 +08:00
IF
2019-03-27 20:46:47 +08:00
    EXISTS LOGS;
CREATE TABLE LOGS ( Id INT, Num INT );
INSERT INTO LOGS ( Id, Num )
2018-06-03 21:57:52 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( 1, 1 ),
    ( 2, 1 ),
    ( 3, 1 ),
    ( 4, 2 ),
    ( 5, 1 ),
    ( 6, 2 ),
    ( 7, 2 );
2018-06-03 21:57:52 +08:00
```
2019-03-27 20:46:47 +08:00
## Solution
2018-06-03 21:57:52 +08:00
```sql
SELECT
2019-03-27 20:46:47 +08:00
    DISTINCT L1.num ConsecutiveNums
2018-06-03 21:57:52 +08:00
FROM
2019-03-27 20:46:47 +08:00
    Logs L1,
    Logs L2,
    Logs L3
WHERE L1.id = l2.id - 1
    AND L2.id = L3.id - 1
    AND L1.num = L2.num
    AND l2.num = l3.num;
2018-06-29 20:30:16 +08:00
```
2019-03-27 20:46:47 +08:00
# 626. Exchange Seats
2018-06-29 20:30:16 +08:00
https://leetcode.com/problems/exchange-seats/description/
2019-03-27 20:46:47 +08:00
## Description
2018-06-29 20:30:16 +08:00
2019-03-27 20:46:47 +08:00
seat 表存储着座位对应的学生。
2018-06-29 20:30:16 +08:00
```html
+---------+---------+
2019-03-27 20:46:47 +08:00
|    id   | student |
2018-06-29 20:30:16 +08:00
+---------+---------+
2019-03-27 20:46:47 +08:00
|    1    | Abbot   |
|    2    | Doris   |
|    3    | Emerson |
|    4    | Green   |
|    5    | Jeames  |
2018-06-29 20:30:16 +08:00
+---------+---------+
```
要求交换相邻座位的两个学生,如果最后一个座位是奇数,那么不交换这个座位上的学生。
```html
+---------+---------+
2019-03-27 20:46:47 +08:00
|    id   | student |
2018-06-29 20:30:16 +08:00
+---------+---------+
2019-03-27 20:46:47 +08:00
|    1    | Doris   |
|    2    | Abbot   |
|    3    | Green   |
|    4    | Emerson |
|    5    | Jeames  |
2018-06-29 20:30:16 +08:00
+---------+---------+
```
2019-03-27 20:46:47 +08:00
## SQL Schema
2018-06-29 20:30:16 +08:00
```sql
2019-03-27 20:46:47 +08:00
DROP TABLE
2018-06-29 20:30:16 +08:00
IF
2019-03-27 20:46:47 +08:00
    EXISTS seat;
CREATE TABLE seat ( id INT, student VARCHAR ( 255 ) );
INSERT INTO seat ( id, student )
2018-06-29 20:30:16 +08:00
VALUES
2019-03-27 20:46:47 +08:00
    ( '1', 'Abbot' ),
    ( '2', 'Doris' ),
    ( '3', 'Emerson' ),
    ( '4', 'Green' ),
    ( '5', 'Jeames' );
2018-06-29 20:30:16 +08:00
```
2019-03-27 20:46:47 +08:00
## Solution
2018-06-29 20:30:16 +08:00
2019-03-27 20:46:47 +08:00
使用多个 union。
2018-06-29 20:30:16 +08:00
```sql
SELECT
2019-03-27 20:46:47 +08:00
    s1.id - 1 AS id,
    s1.student
2018-06-29 20:30:16 +08:00
FROM
2019-03-27 20:46:47 +08:00
    seat s1
2018-06-29 20:30:16 +08:00
WHERE
2019-03-27 20:46:47 +08:00
    s1.id MOD 2 = 0 UNION
2018-06-29 20:30:16 +08:00
SELECT
2019-03-27 20:46:47 +08:00
    s2.id + 1 AS id,
    s2.student
2018-06-29 20:30:16 +08:00
FROM
2019-03-27 20:46:47 +08:00
    seat s2
2018-06-29 20:30:16 +08:00
WHERE
2019-03-27 20:46:47 +08:00
    s2.id MOD 2 = 1
    AND s2.id != ( SELECT max( s3.id ) FROM seat s3 ) UNION
2018-06-29 20:30:16 +08:00
SELECT
2019-03-27 20:46:47 +08:00
    s4.id AS id,
    s4.student
2018-06-29 20:30:16 +08:00
FROM
2019-03-27 20:46:47 +08:00
    seat s4
2018-06-29 20:30:16 +08:00
WHERE
2019-03-27 20:46:47 +08:00
    s4.id MOD 2 = 1
    AND s4.id = ( SELECT max( s5.id ) FROM seat s5 )
ORDER BY
    id;
2018-06-03 21:57:52 +08:00
```