SQL练习笔记

leetcode/nowcode SQL练习笔记

Posted by 敬方 on November 7, 2023

SQL练习笔记

2023-11-07 14:35:58

SQL 练习笔记,包含leetcode等SQL题目冲刺笔记

参考链接

leetcode 题目

175. 组合两个表

  • 提交解答:
# 直接正常查询即可 
SELECT Person.FirstName as firstName, Person.LastName as lastName, Address.City as city, Address.State AS state  FROM Person LEFT JOIN  Address ON Person.PersonId = Address.PersonId;
  • 优质解答:

# Write your MySQL query statement below
SELECT firstname, lastname, city, state FROM person LEFT JOIN address ON person.personid = address.personid
  • 官方题解:
select FirstName, LastName, City, State
from Person left join Address
on Person.PersonId = Address.PersonId;

作者:LeetCode 链接:https://leetcode.cn/problems/combine-two-tables/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

176.第二高的薪水

  • 提交解答
# Write your MySQL query statement below
# notice: 这里必须使用SELECT 子查询才能让空行显示null
SELECT (
    SELECT DISTINCT salary FROM Employee ORDER BY salary DESC LIMIT 1,1
) AS SecondHighestSalary;


# 使用ISFULL 进行二次替换
SELECT (
    IFNULL((SELECT DISTINCT salary FROM Employee ORDER BY salary DESC LIMIT 1,1),NULL)
) AS SecondHighestSalary;

  • 优质解答
# 使用offset加快了速度
SELECT (
    SELECT DISTINCT Salary AS 'SecondHighestSalary' FROM Employee ORDER BY Salary DESC LIMIT 1 OFFSET 1
) AS 'SecondHighestSalary';  
  • 官方题解:
# 思路相同
SELECT
    IFNULL(
      (SELECT DISTINCT Salary
       FROM Employee
       ORDER BY Salary DESC
        LIMIT 1 OFFSET 1),
    NULL) AS SecondHighestSalary

177.第N高的薪水

CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
    declare a int;
    SET a = N-1;
    RETURN (
        # Write your MySQL query statement below.
    SELECT IFNULL((SELECT DISTINCT salary  FROM Employee ORDER BY salary DESC LIMIT 1 OFFSET a),NULL)
    );
END
  • 优质解答:
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
Declare M INT;
set M=N-1;
  RETURN (
      # Write your MySQL query statement below.
select distinct Salary
      from Employee
      order by Salary desc
      limit M,1
  );
END
  • 官方题解:
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
DECLARE M INT; 
    SET M = N-1; 
  RETURN (
      SELECT DISTINCT salary
      FROM Employee
      ORDER BY salary DESC
      LIMIT M, 1
  );
END

# 作者:力扣官方题解
# 链接:https://leetcode.cn/problems/nth-highest-salary/
# 来源:力扣(LeetCode
# 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

178. 分数排名

SELECT
 a.score,
(SELECT COUNT(DISTINCT  score) FROM Scores AS b WHERE  b.score > a.score) + 1 AS 'rank'
FROM Scores AS a ORDER BY a.score DESC;
  • 优质解答:
# select  * from  Scores id  where score order by desc;
# dense_rank()窗口函数进行排序
#Scores这张表的S字段进行排序
#score字段进行排序按照降序排序
#最后放到rank这个新的列中
select S.score, dense_rank() over(
    order by S.score desc
) As 'rank' from Scores S;
  • 官方题解:
SELECT
  S.score,
  COUNT(DISTINCT T.score) AS 'rank'
FROM
  Scores S
  INNER JOIN Scores T ON S.score <= T.score
GROUP BY
  S.id,
  S.score
ORDER BY
  S.score DESC;

#作者:力扣官方题解
#链接:https://leetcode.cn/problems/rank-scores/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
SELECT
  S.score,
  DENSE_RANK() OVER (
    ORDER BY
      S.score DESC
  ) AS 'rank'
FROM
  Scores S;

#作者:力扣官方题解
#链接:https://leetcode.cn/problems/rank-scores/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

180. 连续出现的数字


# 使用in语句,保证id进行同匹配即可
SELECT DISTINCT(num) AS ConsecutiveNums   FROM Logs
WHERE (id+1, num) IN (SELECT id,num FROM Logs)
AND (id+2, num) IN (SELECT id,num FROM Logs)
  • 优质解答:
# 
# Write your MySQL query statement below
# 查询num 别名
select distinct Num as ConsecutiveNums
from (
  select Num, 
    # 筛选CNT
    case 
      when @prev = Num then @count := @count + 1
      when (@prev := Num) is not null then @count := 1
    end as CNT
  from Logs, (select @prev := null,@count := null) as t
) as temp
where temp.CNT >= 3
  • 官方题解:

## 直接使用别名进行简单计算即可
SELECT DISTINCT
    l1.Num AS ConsecutiveNums
FROM
    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
;
# 作者:LeetCode
# 链接:https://leetcode.cn/problems/consecutive-numbers/
# 来源:力扣(LeetCode
# 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

181. 超过经理收入的员工

  • 提交解答:
# Write your MySQL query statement below
# 直接使用子查询别名进行筛选
SELECT name as Employee FROM Employee JOIN (
 SELECT id, salary FROM Employee
) AS new_table ON Employee.managerId = new_table.id WHERE  Employee.salary > new_table.salary;
  • 优质解答:
# Write your MySQL query statement below
# 使用inner join 进行快速查询
select a.name as Employee
from  Employee as a  inner join Employee as b
on a.managerId=b.id and a.salary>b.salary;
  • 官方题解:

# 直接别名进行联表查询
SELECT
    *
FROM
    Employee AS a,
    Employee AS b
WHERE
    a.ManagerId = b.Id
        AND a.Salary > b.Salary;

#作者:LeetCode
#链接:https://leetcode.cn/problems/employees-earning-more-than-their-managers/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

# 使用join 进行查询
SELECT
     a.NAME AS Employee
FROM Employee AS a JOIN Employee AS b
     ON a.ManagerId = b.Id
     AND a.Salary > b.Salary
;

#作者:LeetCode
#链接:https://leetcode.cn/problems/employees-earning-more-than-their-managers/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

182. 查找重复的电子邮箱

  • 提交解答
# Write your MySQL query statement below

SELECT email AS Email FROM Person GROUP BY email HAVING COUNT(*) > 1;
  • 优质解答:
# Write your MySQL query statement below
SELECT DISTINCT Email FROM PERSON GROUP BY EMAIL HAVING COUNT(EMAIL) > 1;
  • 官方题解:
## 1. 直接使用group by 和临时表
select Email from
(
  select Email, count(Email) as num
  from Person
  group by Email
) as statistic
where num > 1;

#作者:LeetCode
#链接:https://leetcode.cn/problems/duplicate-emails/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

## 2. group by having

select Email from Person group by Email having count(Email) > 1;

183. 从不订购的客户

  • 提交解答
# Write your MySQL query statement below

SELECT name AS Customers FROM Customers WHERE Id NOT IN ( 
    SELECT DISTINCT(customerId) AS customerId FROM Orders
); 
  • 优质解答
# Write your MySQL query statement below
# 思路相同,没有使用DISTINCT 节省了时间
SELECT
    name as Customers
FROM
    Customers
WHERE
    id NOT IN (SELECT customerId as id FROM Orders)

# 使用NOT EXISTS 函数节省了时间
SELECT Name as Customers FROM Customers as c1
WHERE NOT EXISTS(
    SELECT Id FROM Orders as c2
    WHERE c2.CustomerId = c1.Id
)
  • 官方题解

# 使用 not in 进行排除
select customers.name as 'Customers'
from customers
where customers.id not in
(
    select customerid from orders
);

#作者:力扣官方题解
#链接:https://leetcode.cn/problems/customers-who-never-order/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

# 使用左连接
SELECT Customers.name AS Customers 
FROM Customers
LEFT JOIN Orders ON Customers.Id = Orders.CustomerId WHERE customerId is NULL;

#作者:力扣官方题解
#链接:https://leetcode.cn/problems/customers-who-never-order/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

184. 部门工资最高的员工

  • 提交解答:
# Write your MySQL query statement below
# 使用子查询,找出每个部门的最大值,然后匹配即可

SELECT b.department_name AS Department, Employee.name AS Employee, Employee.Salary AS Salary
FROM Employee, (
		SELECT MAX(salary) AS max_salary, Department.id AS department_id, Department.name AS department_name
		FROM Employee
			LEFT JOIN Department ON Department.id = Employee.departmentId
		GROUP BY departmentId
	) b
WHERE Employee.departmentId = b.department_id
	AND Employee.Salary = b.max_salary;
  • 优质解答1:
# Write your MySQL query statement below
# 使用rank 统计最大值
SELECT Department, name AS Employee, salary AS Salary 
FROM
(
    SELECT a.*, b.name AS Department, 
           RANK() OVER(PARTITION BY a.departmentId ORDER BY salary DESC) AS rk
    FROM Employee a LEFT JOIN Department b ON a.departmentId =b.id
) t
WHERE rk = 1
  • 优质解答2:
# Write your MySQL query statement below
# 使用连接后,直接使用IN 查询
SELECT Department.Name AS 'Department', Employee.Name AS 'Employee', Salary
FROM Employee
JOIN Department 
ON Employee.DepartmentId = Department.Id
WHERE (Employee.DepartmentId, Salary) 
IN (SELECT DepartmentId, MAX(Salary)
   FROM Employee
   GROUP BY DepartmentId);
  • 官方题解:
SELECT
    Department.name AS 'Department',
    Employee.name AS '

Employee',
    Salary
FROM
    Employee
        JOIN
    Department ON Employee.DepartmentId = Department.Id
WHERE
    (Employee.DepartmentId , Salary) IN
    (   SELECT
            DepartmentId, MAX(Salary)
        FROM
            Employee
        GROUP BY DepartmentId
    )
;

#作者:力扣官方题解
#链接:https://leetcode.cn/problems/department-highest-salary/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

185. 部门工资前三高的所有员工

  • 提交解答:

# 子查询排序后,使用 ROW_NUMBER 窗口函数统计行数
SELECT  Department.name AS Department, Employee.name AS Employee , Employee.salary AS Salary  
FROM Employee LEFT JOIN (
    SELECT departmentId, MIN(salary) as min_salary  FROM (
    SELECT departmentId,salary,
        ROW_NUMBER()  OVER(partition by departmentId  order by salary  desc) as num
    FROM 
    (
        select departmentId,salary FROM Employee GROUP BY departmentId,salary ) b
    ) c
    WHERE num <= 3 GROUP BY departmentId
) d ON  Employee.departmentId = d.departmentId
LEFT JOIN Department  ON Employee.departmentId = Department.id 
WHERE Employee.salary >= d.min_salary ;
  • 优质解答1:
## 直接左连接相同表,找到比自己小的表,最终统计小的数目即可
SELECT  d.name Department, e.name Employee, e.salary Salary
FROM Employee e
LEFT JOIN Employee ee
ON e.departmentId = ee.departmentId AND e.salary < ee.salary
JOIN Department d
ON d.id = e.departmentId
GROUP BY e.id
HAVING count(distinct(ee.salary)) < 3;
  • 优质解答2:
# 直接使用 DENSE_RANK 窗口函数,统计去重后的行数
SELECT Department, name AS Employee, salary AS Salary 
FROM
(
    SELECT a.*, b.name AS Department, 
           DENSE_RANK() OVER(PARTITION BY a.departmentId ORDER BY salary DESC) AS rk
    FROM Employee a LEFT JOIN Department b ON a.departmentId =b.id
) t
WHERE rk <= 3
  • 官方题解:
SELECT
    d.Name AS 'Department', e1.Name AS 'Employee', e1.Salary
FROM
    Employee e1
        JOIN
    Department d ON e1.DepartmentId = d.Id
WHERE
    3 > (SELECT
            COUNT(DISTINCT e2.Salary)
        FROM
            Employee e2
        WHERE
            e2.Salary > e1.Salary
                AND e1.DepartmentId = e2.DepartmentId
        )
;

#作者:LeetCode
#链接:https://leetcode.cn/problems/department-top-three-salaries/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

196. 删除重复的电子邮箱

  • 提交解答
# Write your MySQL query statement below
# 使用子查询找出最小的id即可
DELETE FROM  Person WHERE id NOT IN (
    SELECT a.min_id FROM
        (select email, MIN(id) AS min_id FROM Person GROUP BY email) a
);

  • 优质解答
delete from Person
where id in(
    select id from(
        select *,row_number() over(partition by email order by id ) as row_num
        from Person
    ) a
    where row_num >1)

  • 官方题解
# 使用where语句更加简洁
DELETE p1 FROM
    Person p1,
    Person p2
WHERE
    p1.Email = p2.Email AND p1.Id > p2.Id

#作者:力扣官方题解
#链接:https://leetcode.cn/problems/delete-duplicate-emails/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

511. 游戏玩法分析 I

  • 提交解答:

SELECT player_id, MIN(event_date) AS first_login  FROM Activity GROUP BY player_id; 
  • 优质解答:
elect a1.player_id, min(a1.event_date) as first_login
from Activity as a1
group by a1.player_id;
  • 官方题解:
# 使用窗口函数进行解决
SELECT DISTINCT
  A.player_id,
  FIRST_VALUE(A.event_date) OVER (
    PARTITION BY
      A.player_id
    ORDER BY
      A.event_date
  ) AS first_login
FROM
  Activity A;

#作者:力扣官方题解
#链接:https://leetcode.cn/problems/game-play-analysis-i/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

550. 游戏玩法分析 IV

  • 提交解答:
# Write your MySQL query statement below
SELECT  IFNULL(
    ROUND(
        COUNT(a.player_id) / c.all_user, 
        2
    ), 
    0
    ) AS fraction FROM 
Activity a,
# 首次登陆时间
(SELECT player_id, MIN(event_date) AS frist_date FROM Activity GROUP BY player_id) b,
(SELECT COUNT(DISTINCT(player_id))  AS all_user FROM  Activity)  c
WHERE a.player_id = b.player_id AND a.event_date = date_add(b.frist_date, interval 1 day);
  • 优质解答:

# Write your MySQL query statement below

# 使用datediff直接进行判断
select round(avg(if(a.event_date is null, 0, 1)), 2) fraction
from 
    (select player_id, min(event_date) as login
    from activity
    group by player_id) p 
left join activity a 
on p.player_id=a.player_id and datediff(a.event_date, p.login)=1

  • 优质解答2:
# 思路基本相同
SELECT 
    IFNULL(ROUND(COUNT(DISTINCT(result.player_id)) / COUNT(DISTINCT(Activity.player_id)),2),0) 
    AS fraction
FROM
(SELECT Activity.player_id as player_id
FROM 
(SELECT 
    player_id,
    DATE_ADD(MIN(event_date),INTERVAL 1 DAY) AS second_date
FROM
    Activity
GROUP BY player_id
) AS excepted,Activity
WHERE Activity.event_date = excepted.second_date and Activity.player_id = excepted.player_id
) AS result,Activity
  • 官方题解:
select IFNULL(round(count(distinct(Result.player_id)) / count(distinct(Activity.player_id)), 2), 0) as fraction
from (
  select Activity.player_id as player_id
  from (
    select player_id, DATE_ADD(MIN(event_date), INTERVAL 1 DAY) as second_date
    from Activity
    group by player_id
  ) as Expected, Activity
  where Activity.event_date = Expected.second_date and Activity.player_id = Expected.player_id
) as Result, Activity

# 作者:力扣官方题解
# 链接:https://leetcode.cn/problems/game-play-analysis-iv/
# 来源:力扣(LeetCode
# 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

577. 员工奖金

  • 提交解答:
SELECT Employee.name, Bonus.bonus FROM Employee 
LEFT JOIN  Bonus ON 
    Employee.empId = Bonus.empId 
WHERE Employee.empId NOT IN (
    SELECT empId FROM Bonus WHERE bonus >=1000
);
  • 优质解答:
# Write your MySQL query statement below
select Employee.name, Bonus.bonus from Employee left join Bonus on Employee.empId=Bonus.empId where Bonus.bonus <1000 or bonus  is null;
  • 官方题解:

select name, bonus
from Employee left join Bonus
on Employee.EmpId = Bonus.EmpId
where bonus is null or bonus < 1000

#作者:力扣官方题解
#链接:https://leetcode.cn/problems/employee-bonus/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

262. 行程和用户

  • 提交解答:

# 1. 先做子查询,查询出非禁止用户的所有订单
# 2. 子查询统计,每天订单总数/取消订单数,天数
# 3. round计算对应值

SELECT b.request_at AS Day, IFNULL(ROUND(c.completed_count /b.completed_count, 2), 0.00) AS "Cancellation Rate" FROM (
    SELECT  request_at , COUNT(*) AS completed_count FROM (
        SELECT status, request_at   FROM Trips WHERE client_id NOT IN (
            SELECT users_id FROM Users WHERE banned = "Yes"
        ) AND driver_id NOT IN (
            SELECT users_id FROM Users WHERE banned = "Yes"
        ) ) a WHERE request_at between  "2013-10-01" and "2013-10-03" GROUP BY request_at 
    ) b  
LEFT JOIN 
    (
    SELECT  request_at , COUNT(*) AS completed_count FROM (
        SELECT status, request_at   FROM Trips WHERE client_id NOT IN (
            SELECT users_id FROM Users WHERE banned = "Yes"
        ) AND driver_id NOT IN (
            SELECT users_id FROM Users WHERE banned = "Yes"
        ) ) b WHERE status  != "completed" AND  request_at between  "2013-10-01" and "2013-10-03"  GROUP BY request_at 
    ) c  
ON b.request_at = c.request_at 
  • 优质解答1:

# 直接使用AVG函数,统计特殊状态的值
SELECT 
    request_at Day,ROUND(AVG(status != 'completed'),2) 'Cancellation Rate' 
  FROM 
    Trips 
  WHERE 
      client_id IN (SELECT users_id FROM Users WHERE banned = 'No') 
    AND 
      driver_id in (SELECT users_id FROM Users WHERE banned = 'No') 
    AND 
      request_at BETWEEN '2013-10-01' AND '2013-10-03' GROUP BY request_at;
  • 优质解答2:
# Write your MySQL query statement below
# 使用了IF SUM 运算更快
SELECT T.request_at AS `Day`, 
ROUND(SUM(IF(T.STATUS = 'completed',0,1))/ COUNT(1),2) AS `Cancellation Rate`
FROM Trips AS T
JOIN Users AS U1 ON (T.client_id = U1.users_id AND U1.banned ='No')
JOIN Users AS U2 ON (T.driver_id = U2.users_id AND U2.banned ='No')
WHERE T.request_at BETWEEN '2013-10-01' AND '2013-10-03'
GROUP BY T.request_at;
  • 官方题解: 无

570. 至少有5名直接下属的经理

  • 提交解答:
# Write your MySQL query statement below

# 直接使用子查询
SELECT name FROM Employee WHERE id IN (
    SELECT managerId FROM Employee GROUP BY managerId HAVING COUNT(*) >= 5
);

# 使用连表查询
SELECT e1.name FROM 
Employee e1 LEFT JOIN  Employee e2 ON  e1.Id = e2.managerId GROUP BY e1.id HAVING COUNT(*) >=5; 

  • 优质解答:
# Write your MySQL query statement below
select
    m.name as name
from 
    employee e 
join 
    employee m 
on e.managerId = m.id
group by
    e.managerId
having count(*)>=5
  • 官方题解:
select Employee.Name as Name
from (
  select ManagerId as Id
  from Employee
  group by ManagerId
  having count(Id) >= 5
) as Manager join Employee
on Manager.Id = Employee.Id

#作者:力扣官方题解
#链接:https://leetcode.cn/problems/managers-with-at-least-5-direct-reports/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

584. 寻找用户推荐人

参考链接:

# Write your MySQL query statement below
SELECT name FROM Customer  WHERE referee_id <> 2 OR referee_id is null;
  • 优质解答:
# Write your MySQL query statement below
# 进行过滤筛选
select t.name from Customer t where (t.referee_id!=2 or t.referee_id is null)
# 进行对应的过滤筛选
select name from Customer where referee_id != 2 or referee_id is null;
  • 官方题解:
SELECT name FROM customer WHERE referee_id != 2 OR referee_id IS NULL;

统计用户每天登陆时长

577.员工奖金

  • 提交解答:
# Write your MySQL query statement below
# 直接反向取数即可
SELECT Employee.name, Bonus.bonus FROM Employee LEFT JOIN  Bonus ON Employee.empId = Bonus.empId WHERE Employee.empId NOT IN (
    SELECT empId FROM Bonus WHERE bonus >=1000
);
  • 优质解答(官方题解):
# Write your MySQL query statement below
# 直接使用null过滤
select Employee.name, Bonus.bonus from Employee left join Bonus on Employee.empId=Bonus.empId where Bonus.bonus <1000 or bonus  is null;

585. 2016年的投资

  • 提交解答:
# Write your MySQL query statement below


# 保留两位小数
SELECT ROUND(SUM(tiv_2016),2 ) AS tiv_2016 FROM Insurance 
WHERE pid IN (
    # 条件1
    SELECT  a.pid FROM Insurance a, Insurance b WHERE a.pid != b.pid  AND a.tiv_2015 = b.tiv_2015) 
AND pid NOT IN (
    # 条件2
    SELECT  a.pid FROM Insurance a, Insurance b WHERE a.pid != b.pid AND a.lat = b.lat AND a.lon = b.lon
);



# 保留两位小数
SELECT ROUND(SUM(tiv_2016),2 ) AS tiv_2016 
FROM Insurance 
WHERE  tiv_2015  IN (
    # 至少一相同
    SELECT tiv_2015  FROM Insurance  GROUP BY tiv_2015 HAVING COUNT(*) >1 ) 
AND (lat, lon) IN (
    SELECT lat,lon FROM Insurance GROUP BY lat,lon HAVING COUNT(*) = 1
);
  • 优质解答:
# 使用partition 直接统计数量
select round( sum(tiv_2016) ,2)  tiv_2016
from(
    select *,
    count(*) over(partition by tiv_2015) c1,
    count(*) over(partition by lat,lon) c2
    from Insurance
) t1
where t1.c1 > 1 and t1.c2 = 1 
  • 官方题解:

SELECT
    SUM(insurance.TIV_2016) AS TIV_2016
FROM
    insurance
WHERE
    insurance.TIV_2015 IN
    (
      SELECT
        TIV_2015
      FROM
        insurance
      GROUP BY TIV_2015
      HAVING COUNT(*) > 1
    )
    AND CONCAT(LAT, LON) IN
    (
      SELECT
        CONCAT(LAT, LON)
      FROM
        insurance
      GROUP BY LAT , LON
      HAVING COUNT(*) = 1
    )
;

#作者:LeetCode
##来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

586. 订单最多的客户

  • 提交解答:

SELECT customer_number FROM Orders GROUP bY customer_number ORDER BY  COUNT(*) DESC LIMIT 1;
  • 优质解答:
# 不使用COUNT(*) 直接指明字段,提升了速度
select  customer_number
from Orders
group by customer_number
order by count(customer_number) desc
limit 1


##  使用子查询
select cn customer_number 
from (
    select count(customer_number) cc, customer_number cn
    from Orders
    group by customer_number
) T
order by T.cc desc
limit 0,1
  • 官方题解:
SELECT
    customer_number
FROM
    orders
GROUP BY customer_number
ORDER BY COUNT(*) DESC
LIMIT 1
;

# 作者:力扣官方题解
# 链接:https://leetcode.cn/problems/customer-placing-the-largest-number-of-orders/solutions/2366301/ding-dan-zui-duo-de-ke-hu-by-leetcode-so-bywe/
# 来源:力扣(LeetCode
# 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

595. 大的国家

World 表:

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| name        | varchar |
| continent   | varchar |
| area        | int     |
| population  | int     |
| gdp         | bigint  |
+-------------+---------+

name 是该表的主键(具有唯一值的列)。 这张表的每一行提供:国家名称、所属大陆、面积、人口和 GDP 值。

如果一个国家满足下述两个条件之一,则认为该国是 大国 :

面积至少为 300 万平方公里(即,3000000 km2),或者 人口至少为 2500 万(即 25000000) 编写解决方案找出 大国 的国家名称、人口和面积。

按 任意顺序 返回结果表。

  • 提交解答:
# Write your MySQL query statement below
SELECT name, population, area FROM World WHERE population >= 25000000 OR area >= 3000000;
  • 优质解答:
# Write your MySQL query statement below
select name, population, area
from World
where area >= 3000000 or population >=25000000
  • 官方题解:
SELECT
    name, population, area
FROM
    world
WHERE
    area >= 3000000 OR population >= 25000000
;

#作者:力扣官方题解
#链接:https://leetcode.cn/problems/big-countries/solutions/2366084/big-countries-by-leetcode-solution-8k13/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

596. 超过5名学生的课

表: Courses

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| student     | varchar |
| class       | varchar |
+-------------+---------+

在 SQL 中,(student, class)是该表的主键列。 该表的每一行表示学生的名字和他们注册的班级。

查询 至少有5个学生 的所有班级。

以 任意顺序 返回结果表。

查询结果格式如下所示。

示例 1:

输入:

Courses table:
+---------+----------+
| student | class    |
+---------+----------+
| A       | Math     |
| B       | English  |
| C       | Math     |
| D       | Biology  |
| E       | Math     |
| F       | Computer |
| G       | Math     |
| H       | Math     |
| I       | Math     |
+---------+----------+

输出:

+---------+ 
| class   | 
+---------+ 
| Math    | 
+---------+

解释: -数学课有6个学生,所以我们包括它。 -英语课有1名学生,所以我们不包括它。 -生物课有1名学生,所以我们不包括它。 -计算机课有1个学生,所以我们不包括它。

  • 提交解答:
# Write your MySQL query statement below
# 主要思路直接使用GROUP having进行解决
SELECT class FROM Courses GROUP BY class HAVING COUNT() >=5;
  • 优质解答:
# Write your MySQL query statement below
select
    class
From
    Courses
group by 
    class
having count(student)>=5;
  • 官方题解:

## 使用子查询对每个班级的学生进行统计
## 统计完成后执行过滤
SELECT
    class
FROM
    (SELECT
        class, COUNT(student) AS num
    FROM
        courses
    GROUP BY class) AS temp_table
WHERE
    num >= 5
;

#作者:力扣官方题解
#链接:https://leetcode.cn/problems/classes-more-than-5-students/solutions/2366294/chao-guo-5ming-xue-sheng-de-ke-by-leetco-l4es/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

[602. 好友申请 II :谁有最多的好友](https://leetcode.cn/problems/friend-reqz

RequestAccepted 表:

+----------------+---------+
| Column Name    | Type    |
+----------------+---------+
| requester_id   | int     |
| accepter_id    | int     |
| accept_date    | date    |
+----------------+---------+

(requester_id, accepter_id) 是这张表的主键(具有唯一值的列的组合)。 这张表包含发送好友请求的人的 ID ,接收好友请求的人的 ID ,以及好友请求通过的日期。

编写解决方案,找出拥有最多的好友的人和他拥有的好友数目。

生成的测试用例保证拥有最多好友数目的只有 1 个人。

查询结果格式如下例所示。

示例 1:

输入: RequestAccepted 表:

+--------------+-------------+-------------+
| requester_id | accepter_id | accept_date |
+--------------+-------------+-------------+
| 1            | 2           | 2016/06/03  |
| 1            | 3           | 2016/06/08  |
| 2            | 3           | 2016/06/08  |
| 3            | 4           | 2016/06/09  |
+--------------+-------------+-------------+

输出:

+----+-----+
| id | num |
+----+-----+
| 3  | 3   |
+----+-----+

解释: 编号为 3 的人是编号为 1 ,2 和 4 的人的好友,所以他总共有 3 个好友,比其他人都多。

进阶:在真实世界里,可能会有多个人拥有好友数相同且最多,你能找到所有这些人吗?

  • 提交解答:
## 主要思路
# 先分别统计作为发送者和接收者的子表,再进行合并统计
# 注意这里使用 UNION ALL 进行两张表的合并
SELECT user AS id , SUM(count)  AS num   FROM 
(
    SELECT accepter_id AS user, COUNT(*) AS count FROM RequestAccepted GROUP BY accepter_id
    union 
    SELECT  requester_id AS user, COUNT(*) AS count FROM RequestAccepted GROUP BY requester_id
) c GROUP BY id ORDER BY num DESC LIMIT 0,1

  • 优质解答:
# Write your MySQL query statement below
# 使用union 与组合group 进行了统一去重
select id, count(*) as num from (
    select r.requester_id as id, accepter_id as sid, accept_date from requestaccepted r group by id, sid
    union 
    (   
        # 这个子查询巧妙的将列进行了转换 
        select t.accepter_id as id, requester_id as sid, accept_date from requestaccepted t group by id, sid)
) tmp group by id order by count(*) desc limit 1

# 思路相同
select id, num from
(select pid as id, sum(cnt) as num from
    (select accepter_id as pid, count(1) as cnt from request_accepted group by accepter_id
    union all
    select requester_id as pid, count(1) as cnt from request_accepted group by requester_id) t1
group by pid) t2
order by num desc
limit 1;

# 思路相同,代码更加简洁
select t1.ids as id,count(*) as num
from(
        select requester_id as ids from RequestAccepted 
        union all
        select accepter_id as ids from RequestAccepted
) as t1
group by id
order by num desc
limit 1;
  • 官方题解:
select ids as id, cnt as num
from
(
select ids, count(*) as cnt
   from
   (
        select requester_id as ids from request_accepted
        union all
        select accepter_id from request_accepted
    ) as tbl1
   group by ids
   ) as tbl2
order by cnt desc
limit 1
;

#作者:LeetCode
#链接:https://leetcode.cn/problems/friend-requests-ii-who-has-the-most-friends/solutions/23104/hao-you-shen-qing-ii-shui-you-zui-duo-de-hao-you-b/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

607. 销售员

表: SalesPerson

+-----------------+---------+
| Column Name     | Type    |
+-----------------+---------+
| sales_id        | int     |
| name            | varchar |
| salary          | int     |
| commission_rate | int     |
| hire_date       | date    |
+-----------------+---------+

sales_id 是该表的主键列(具有唯一值的列)。 该表的每一行都显示了销售人员的姓名和 ID ,以及他们的工资、佣金率和雇佣日期。

表: Company

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| com_id      | int     |
| name        | varchar |
| city        | varchar |
+-------------+---------+

com_id 是该表的主键列(具有唯一值的列)。 该表的每一行都表示公司的名称和 ID ,以及公司所在的城市。

表: Orders

+-------------+------+
| Column Name | Type |
+-------------+------+
| order_id    | int  |
| order_date  | date |
| com_id      | int  |
| sales_id    | int  |
| amount      | int  |
+-------------+------+

order_id 是该表的主键列(具有唯一值的列)。 com_id 是 Company 表中 com_id 的外键(reference 列)。 sales_id 是来自销售员表 sales_id 的外键(reference 列)。 该表的每一行包含一个订单的信息。这包括公司的 ID 、销售人员的 ID 、订单日期和支付的金额。

编写解决方案,找出没有任何与名为 “RED” 的公司相关的订单的所有销售人员的姓名。

以 任意顺序 返回结果表。

返回结果格式如下所示。

示例 1:

输入: SalesPerson 表:

+----------+------+--------+-----------------+------------+
| sales_id | name | salary | commission_rate | hire_date  |
+----------+------+--------+-----------------+------------+
| 1        | John | 100000 | 6               | 4/1/2006   |
| 2        | Amy  | 12000  | 5               | 5/1/2010   |
| 3        | Mark | 65000  | 12              | 12/25/2008 |
| 4        | Pam  | 25000  | 25              | 1/1/2005   |
| 5        | Alex | 5000   | 10              | 2/3/2007   |
+----------+------+--------+-----------------+------------+

Company 表:

+--------+--------+----------+
| com_id | name   | city     |
+--------+--------+----------+
| 1      | RED    | Boston   |
| 2      | ORANGE | New York |
| 3      | YELLOW | Boston   |
| 4      | GREEN  | Austin   |
+--------+--------+----------+

Orders 表:

+----------+------------+--------+----------+--------+
| order_id | order_date | com_id | sales_id | amount |
+----------+------------+--------+----------+--------+
| 1        | 1/1/2014   | 3      | 4        | 10000  |
| 2        | 2/1/2014   | 4      | 5        | 5000   |
| 3        | 3/1/2014   | 1      | 1        | 50000  |
| 4        | 4/1/2014   | 1      | 4        | 25000  |
+----------+------------+--------+----------+--------+

输出:

+------+
| name |
+------+
| Amy  |
| Mark |
| Alex |
+------+

解释: 根据表 orders 中的订单 ‘3’ 和 ‘4’ ,容易看出只有 ‘John’ 和 ‘Pam’ 两个销售员曾经向公司 ‘RED’ 销售过。 所以我们需要输出表 salesperson 中所有其他人的名字。

  • 提交解答:
# Write your MySQL query statement below
# 按照公司和订单找出相关的销售员ID
# 最后使用not in 排除即可

SELECT name FROM SalesPerson WHERE sales_id NOT IN (
SELECT DISTINCT(sales_id) AS sales_id 
    FROM  Orders 
    LEFT JOIN Company ON Orders.com_id =  Company.com_id 
WHERE Company.name = "RED"
)
  • 优质解答:

# 代码更加简洁,取消了左连接
SELECT
    name
FROM SalesPerson 
WHERE sales_id NOT IN (
    SELECT sales_id
    FROM Orders
    WHERE com_id = (
        SELECT com_id 
        FROM Company 
        WHERE name = 'RED'
    )
)
  • 官方题解:
SELECT
    s.name
FROM
    salesperson s
WHERE
    s.sales_id NOT IN (SELECT
            o.sales_id
        FROM
            orders o
                LEFT JOIN
            company c ON o.com_id = c.com_id
        WHERE
            c.name = 'RED')
;

#作者:力扣官方题解
#链接:https://leetcode.cn/problems/sales-person/solutions/2366337/xiao-shou-yuan-by-leetcode-solution-wg7i/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

601.体育馆的人流量

表:Stadium

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| id            | int     |
| visit_date    | date    |
| people        | int     |
+---------------+---------+

visit_date 是该表中具有唯一值的列。 每日人流量信息被记录在这三列信息中:序号 (id)、日期 (visit_date)、 人流量 (people) 每天只有一行记录,日期随着 id 的增加而增加

编写解决方案找出每行的人数大于或等于 100 且 id 连续的三行或更多行记录。

返回按 visit_date 升序排列 的结果表。

查询结果格式如下所示。

示例 1:

输入: Stadium 表:

+------+------------+-----------+
| id   | visit_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-09 | 188       |
+------+------------+-----------+

输出:

+------+------------+-----------+
| id   | visit_date | people    |
+------+------------+-----------+
| 5    | 2017-01-05 | 145       |
| 6    | 2017-01-06 | 1455      |
| 7    | 2017-01-07 | 199       |
| 8    | 2017-01-09 | 188       |
+------+------------+-----------+

解释: id 为 5、6、7、8 的四行 id 连续,并且每行都有 >= 100 的人数记录。 请注意,即使第 7 行和第 8 行的 visit_date 不是连续的,输出也应当包含第 8 行,因为我们只需要考虑 id 连续的记录。 不输出 id 为 2 和 3 的行,因为至少需要三条 id 连续的记录。

  • 提交解答:
# 直接使用连表查询
# Write your MySQL query statement below
SELECT DISTINCT l1.*
FROM
    Stadium l1,
    Stadium l2,
    Stadium l3
WHERE
    l1.people >= 100
    AND l2.people >= 100
    AND l3.people >= 100
    AND (
        ( l1.id+1 = l2.id AND l3.id = l1.id + 2 ) 
        OR ( l1.id+1 = l2.id AND l3.id = l1.id - 1 ) 
        OR ( l1.id-1 = l2.id AND l3.id = l1.id - 2 )
    )
ORDER BY visit_date;

  • 优质解答:
# Write your MySQL query statement below
# 使用了group by 直接进行了去重
select s1.*
from stadium s1, stadium s2, stadium s3
where(
    (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)) and 
    s1.people >= 100 and s2.people >= 100 and s3.people >= 100
group by s1.id
  • 官方题解:
select distinct t1.*
from stadium t1, stadium t2, stadium t3
where t1.people >= 100 and t2.people >= 100 and t3.people >= 100
and
(
	  (t1.id - t2.id = 1 and t1.id - t3.id = 2 and t2.id - t3.id =1)  -- t1, t2, t3
    or
    (t2.id - t1.id = 1 and t2.id - t3.id = 2 and t1.id - t3.id =1) -- t2, t1, t3
    or
    (t3.id - t2.id = 1 and t2.id - t1.id =1 and t3.id - t1.id = 2) -- t3, t2, t1
)
order by t1.id
;

#作者:LeetCode
#链接:https://leetcode.cn/problems/human-traffic-of-stadium/solutions/50428/ti-yu-guan-de-ren-liu-liang-by-leetcode/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

608. 树节点

表:Tree

+-------------+------+
| Column Name | Type |
+-------------+------+
| id          | int  |
| p_id        | int  |
+-------------+------+

id 是该表中具有唯一值的列。 该表的每行包含树中节点的 id 及其父节点的 id 信息。 给定的结构总是一个有效的树。

树中的每个节点可以是以下三种类型之一:

“Leaf”:节点是叶子节点。 “Root”:节点是树的根节点。 “lnner”:节点既不是叶子节点也不是根节点。 编写一个解决方案来报告树中每个节点的类型。

以 任意顺序 返回结果表。

结果格式如下所示。

示例 1:

输入:

Tree table:
+----+------+
| id | p_id |
+----+------+
| 1  | null |
| 2  | 1    |
| 3  | 1    |
| 4  | 2    |
| 5  | 2    |
+----+------+

输出:

+----+-------+
| id | type  |
+----+-------+
| 1  | Root  |
| 2  | Inner |
| 3  | Leaf  |
| 4  | Leaf  |
| 5  | Leaf  |
+----+-------+

解释: 节点 1 是根节点,因为它的父节点为空,并且它有子节点 2 和 3。 节点 2 是一个内部节点,因为它有父节点 1 和子节点 4 和 5。 节点 3、4 和 5 是叶子节点,因为它们有父节点而没有子节点。 示例 2:

输入:

Tree table:
+----+------+
| id | p_id |
+----+------+
| 1  | null |
+----+------+

输出:

+----+-------+
| id | type  |
+----+-------+
| 1  | Root  |
+----+-------+

解释:如果树中只有一个节点,则只需要输出其根属性。

  • 提交解答
# 主要思路
# 统计节点所有的子节点数目,与父节点数目
SELECT A.id, IF(A.p_count=0, "Root",IF(s_count > 0,"Inner","Leaf") ) AS  type  
FROM 
(
 SELECT id, COUNT(p_id) AS p_count  FROM TREE GROUP BY id
) A LEFT JOIN 
(
    SELECT p_id  AS id, COUNT(id) AS s_count FROM TREE WHERE p_id >=0 GROUP BY p_id
) B ON A.id = B.id;

  • 优质解答:
select id,case when p_id is null then 'Root' 
when id not in (select distinct p_id from Tree where p_id is not null) then 'Leaf'
else 'Inner' end type
from Tree 


  • 官方题解:
SELECT
    atree.id,
    IF(ISNULL(atree.p_id),
        'Root',
        IF(atree.id IN (SELECT p_id FROM tree), 'Inner','Leaf')) Type
FROM
    tree atree
ORDER BY atree.id

#作者:LeetCode
#链接:https://leetcode.cn/problems/tree-node/solutions/23160/shu-jie-dian-by-leetcode/
#来源:力扣(LeetCode
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

行列转置

描述:使用SQL实现最终的行列数据转置 如:

行转列

解答方法:

# 使用group进行分组
# 使用max 进行运算
select 姓名 as 姓名 ,
  max(case 课程 when '语文' then 分数 else 0 end) 语文, 
  max(case 课程 when '数学' then 分数 else 0 end) 数学,
  max(case 课程 when '物理' then 分数 else 0 end) 物理
from 行列转换m  
group by 姓名 # group 进行分组

优质解答:使用sql 拼接

# 声明sql
declare @sql varchar(8000)
# 设置初始值
set @sql = 'select 姓名 '
# 进行SQL拼接
select @sql = @sql + ' , max(case 课程 when ''' + 课程 + ''' then 分数 else 0 end) [' + 课程 + ']'
from (select distinct 课程 from 行列转换m) as a
# 添加group by变量
set @sql = @sql + ' from 行列转换m group by 姓名'
# 执行函数
exec(@sql)