力扣SQL学习计划(入门)

SQL学习计划

我的力扣主页:https://leetcode.cn/u/youthful-6aussnpr/
关于如何构建测试数据库:
首先到工作台构建一个测试数据库,然后回到力扣题目界面,点击SQL架构,将其中内容悉数复制到工作台,然后在每条语句后面加上分号,执行,即可在工作台中生成测试用表,有时候还有额外的地方需要自己修改,比如把'None'改成NULL
注意:无法在网页测试时创建索引提高效率,that’s a pity!
前言

建议大家创建一个查询效率的存储过程(stored procedure)

DELIMITER $$
CREATE PROCEDURE get_last_query_cost()
BEGIN
	SHOW STATUS LIKE 'last_query_cost';
END$$

DELIMITER ;

然后执行完一段Query,就可以看看这个Query的value是多少,value越低越好!

第一天:选择

595 大的国家(简单题)

吐槽:这题结构有问题,gdp不能为int类型,应该为double,否则会越界(已测试)
https://leetcode.cn/problems/big-countries/

# Write your MySQL query statement below
# 两种解法速度相差无几,毕竟数据量小
# 但是今天的主题是选择,指明官方更希望我们用OR来解这道题
# 同时用OR也更简洁

-- 解法1:WHERE + OR
SELECT
    name,population,area
FROM
    world
WHERE
    area>=3000000 OR population >=25000000;

-- 解法2:WHERE + UNION
# SELECT
#     name, population, area
# FROM
#     world
# WHERE
#     area >= 3000000
# UNION
# SELECT
#     name, population, area
# FROM
#     world
# WHERE
#     population >= 25000000
# ;

#关于索引:最佳的选择应该是两种方法都进行尝试比较(OR和UNION)。

1757 可回收且低脂的产品(简单题)

https://leetcode.cn/problems/recyclable-and-low-fat-products/

# Write your MySQL query statement below
SELECT
    product_id
FROM
    Products
WHERE
    low_fats = 'Y' AND recyclable = 'Y';

584 寻找用户推荐人(简单题)

https://leetcode.cn/problems/find-customer-referee/

# Write your MySQL query statement below

-- 解法1:OR
-- 速度最快,查询了6行(使用EXLPALIN在数据库测试结果)
SELECT 
    name 
FROM 
    customer 
WHERE 
    referee_Id <> 2 OR referee_Id IS NULL;



-- 解法2:UNION ALL
-- 查询了12行
# SELECT 
#     name 
# FROM 
#     customer 
# WHERE 
#     referee_id <> 2
# UNION ALL
# SELECT 
#     name 
# FROM 
#     customer 
# WHERE 
#     referee_id IS NULL;

-- 解法3:双层SELECT
-- 查询了12行
# SELECT  
#     name
# FROM  
#     customer
# WHERE id NOT IN ( 
# 	SELECT id 
# 	FROM customer
# 	WHERE referee_id = 2);

-- 解法4:使用EXISTS筛选
-- 查询了13行
# SELECT C.name 
# FROM customer C
# WHERE NOT EXISTS (
# 	SELECT C1.name
# 	FROM  customer C1
# 	WHERE C1.id = C.id
# 	AND  C1.referee_id = 2);

183 从不订购的客户(简单题)

https://leetcode.cn/problems/customers-who-never-order/

# Write your MySQL query statement below
-- 在这里三种解法效率一模一样
-- 解法1:双层SELECT
SELECT Name AS Customers
FROM Customers
WHERE Id NOT IN(SELECT CustomerId FROM Orders);

-- 解法2:左连接
# SELECT 
# 	name 
# FROM 
# 	customers 
# LEFT JOIN orders
# 	ON customers.id = orders.customerId 
# WHERE ISNULL(customerId);

--  解法3:右连接,本质上和解法2一样
# SELECT 
# 	name 
# FROM 
# 	orders 
# RIGHT JOIN customers
# 	ON customers.id = orders.customerId 
# WHERE ISNULL(customerId);

第 2 天:排序 & 修改

1873 计算特殊奖金(简单题)

https://leetcode.cn/problems/calculate-special-bonus/

# Write your MySQL query statement below
# SELECT 
#     employee_id, 
#     salary AS bonus
# FROM Employees
# WHERE name NOT LIKE 'M%' AND employee_id%2 <> 0
# UNION 
# SELECT employee_id ,salary*0 AS bonus
# FROM Employees
# WHERE employee_id%2=0 OR name LIKE ('M%')
# ORDER BY employee_id;

# `IF`第一个参数写条件,第二个参数写条件成立返回的内容,第三个参数写条件不成立返回的内容
# Mod(a,b)    在sql中的意思是 a / b 的余数
# 基础用法:如果id需要是偶数或者奇数时就可以使用mod。
# mod(id,2)=1      是指id是奇数。
# mod(id,2)=0      是指id是偶数。
# SELECT 
#     employee_id,
# IF(MOD(employee_id,2)!=0 AND LEFT(name,1)!='M',salary,0) bonus
# FROM Employees
# ORDER BY employee_id

# CASE`配合`WHEN`,`THEN`使用,`WHEN`后接条件,`THEN`后接符合条件返回的内容 ,有多个条件时使用
# 需要用`ELSE`返回以上条件都不成立时返回的内容,最后以`END`结尾
SELECT 
    employee_id,
    CASE 
        WHEN MOD(employee_id,2)!=0 AND LEFT(name,1)!='M' THEN salary
        WHEN MOD(employee_id,2)=0 OR LEFT(name,1)='M' THEN 0
        ELSE 0 -- 这里ELSE可以省略
    END AS bonus
FROM Employees
ORDER BY employee_id

627 变更性别(简单题)

https://leetcode.cn/problems/swap-salary/

# Write your MySQL query statement below
UPDATE Salary
SET sex=IF(sex = 'm','f','m');

# 感觉这里用case有些鸡肋,case个人认为适用于多个选择
# UPDATE salary
# SET
#     sex = CASE sex
#         WHEN 'm' THEN 'f'
#         ELSE 'm'
#     END;

196 删除重复的电子邮箱(简单题)

https://leetcode.cn/problems/delete-duplicate-emails/

-- 解法1:类似自连接了,在这里效率极低,删除3000行代码花三秒多
# DELETE p1 
# FROM 
#     Person p1,
#     Person p2
# WHERE
#     p1.Email = p2.Email AND p1.Id > p2.Id;

-- 解法2:双重SELECT,效率高,删除3000行代码花0.25秒
DELETE FROM Person 
WHERE Id NOT IN (
    SELECT Id 
    FROM(
        SELECT MIN(Id) AS id
        FROM Person 
        GROUP BY Email
    )  derived_table
)

# 执行用时:
# 581 ms
# , 在所有 MySQL 提交中击败了
# 90.71%
# 的用户

第 3 天:字符串处理函数/正则

1667 修复表中的名字(简单题)

https://leetcode.cn/problems/fix-names-in-a-table/

# Write your MySQL query statement below

# CONACT(str1,str2)————拼接两个字符串
# UPPER(str)————字符串大写
# LOWER(str)————字符串小写
# LENGTH(str)————字符串长度
# SUBSTRING(str,start,end)————截取字符串,start开始,end结束。
# LEFT(str,len)————从左边开始截取字符串
# RIGHT(str,len)————从右边开始截取字符串

SELECT 
    user_id, 
    CONCAT(
            UPPER(LEFT(name, 1)), 
            LOWER(SUBSTRING(name, 2))
            ) AS name
FROM Users
ORDER BY user_id

1484 按日期分组销售产品(简单题)

https://leetcode.cn/problems/group-sold-products-by-the-date/

# Write your MySQL query statement below

# GROUP_CONCAT([DISTINCT] 要连接的字段 [ORDER BY ASC/DESC 排序字段] [SEPARATOR '分隔符'])`

SELECT 
    sell_date,
    COUNT(DISTINCT product) AS num_sold,
    GROUP_CONCAT(DISTINCT product ORDER BY product ASC SEPARATOR ',') AS products
FROM Activities 
GROUP BY sell_date
ORDER BY sell_date
;

1527 患某种疾病的患者(简单题)

https://leetcode.cn/problems/patients-with-a-condition/

测试了九万多行代码,影响行数三万多
测试了很多遍,也有正则速度更快的时候,但总体上是LIKE比正则速度更快

-- 解法1:OR + LIKE
SELECT * FROM Patients 
WHERE conditions LIKE 'DIAB1%' OR conditions LIKE '% DIAB1%';

-- 解法2:正则
SELECT * FROM PATIENTS
WHERE CONDITIONS REGEXP '^DIAB1|\\sDIAB1';

第 4 天:组合查询 & 指定选取

1965 丢失信息的雇员(简单题)

https://leetcode.cn/problems/employees-with-missing-information/

# Write your MySQL query statement below
#方法一:双重SELECT
# SELECT employee_id
# FROM employees
# WHERE employee_id NOT IN (SELECT employee_id FROM salaries)

# UNION

# SELECT employee_id
# FROM salaries
# WHERE employee_id NOT IN (SELECT employee_id FROM employees)

# ORDER BY employee_id ASC


#方法二:LEFT JOIN
SELECT A.employee_id
FROM employees A 
LEFT JOIN salaries B 
    ON A.employee_id = B.employee_id
WHERE B.salary IS NULL

UNION

SELECT A.employee_id
FROM salaries A 
LEFT JOIN employees B 
    ON A.employee_id = B.employee_id
WHERE B.name IS NULL

ORDER BY employee_id ASC

#使用SHOW STATUS LIKE 'last_query_cost';测试,方法二效率比方法一高许多

1795 每个产品在不同商店的价格(简单题)

报表系统中经常需要行列转换,在 SQL Server 等数据库中可以用 PIVOT 、UNPIVOT 来实现,但是在 MySQL 数据库中却不支持,太傻了,太傻了,找到了教程,测试案例已经写完了,却发现根本执行不了,为什么其他数据库支持MySQL不支持???
今天是8月19号晚上8:06,写到这里的时候,正在下载Oracle,待更新这题的题解
这个题,如果有多个store,MySQL直接无解
https://leetcode.cn/problems/rearrange-products-table/

# Write your MySQL query statement below

# 执行速度不行 ,存在更优解
# SELECT product_id,'store1' AS store ,store1 AS price FROM  Products WHERE store1 IS NOT NULL
# -- 下面省略了两个AS
# UNION 
# SELECT product_id,'store2',store2 FROM  Products WHERE store2 IS NOT NULL
# UNION 
# SELECT product_id,'store3',store3 FROM  Products WHERE store3 IS NOT NULL
# # ORDER BY product_id ASC;

608 树节点(中等题)

https://leetcode.cn/problems/tree-node/

--  解法1:使用 CASE WHEN
--  使用SHOW STATUS LIKE 'last_query_cost';测试value=1.498,效率最高
SELECT id ,
CASE 
WHEN p_id IS NULL THEN "Root"
WHEN id  IN (SELECT DISTINCT p_id FROM tree) THEN "Inner"
ELSE "Leaf"
END TYPE
FROM tree;

--  解法2:使用 CASE WHEN
--  使用SHOW STATUS LIKE 'last_query_cost';测试value=2.247,效率一般
# SELECT
#     id AS `Id`,
#     CASE
#         WHEN tree.id = (SELECT atree.id FROM tree atree WHERE atree.p_id IS NULL)
#           THEN 'Root'
#         WHEN tree.id IN (SELECT atree.p_id FROM tree atree)
#           THEN 'Inner'
#         ELSE 'Leaf'
#     END AS Type
# FROM tree



--  解法3:UNION
--  使用SHOW STATUS LIKE 'last_query_cost';测试value=4.946048,效率最低
# SELECT
#     id, 
#     'Root' AS Type
# FROM tree
# WHERE
#     p_id IS NULL
# UNION
# SELECT
#     id, 
#     'Inner' AS Type
# FROM tree
# WHERE
#     id IN (
#             SELECT DISTINCT
#                 p_id
#             FROM
#                 tree
#             WHERE
#                 p_id IS NOT NULL)
#         AND p_id IS NOT NULL
# UNION
# SELECT
#     id, 
#     'Leaf' AS Type
# FROM tree
# WHERE
#     id NOT IN (
#             SELECT DISTINCT
#                 p_id
#             FROM
#                 tree
#             WHERE
#                 p_id IS NOT NULL)
#         AND p_id IS NOT NULL

# ORDER BY id;

176 第二高的薪水(中等题)

https://leetcode.cn/problems/second-highest-salary/

# Write your MySQL query statement below
-- 解法1:LIMIT,和解法3效率一样
-- value = 2.449
# SELECT (
# 	SELECT 
# 		DISTINCT salary 
# 	FROM Employee 
# 	ORDER BY salary DESC 
# 	LIMIT 1,1
# ) AS SecondHighestSalary;


-- 解法2:WHERE,效率最高
-- value = 0.898
SELECT 
 	MAX(DISTINCT salary) AS SecondHighestSalary
FROM Employee
WHERE salary<(
		SELECT MAX(salary)
		FROM Employee
);


-- 解法3: IFNULL
-- 这是一个错误案例,因为如果第二不存在,该解返回的是无内容,而不是NULL
# SELECT DISTINCT salary SecondHighestSalary
# FROM Employee
# ORDER BY salary desc
# LIMIT 1,1;
# # 我们把上述解套上IFNULL
# SELECT IFNULL(
# 	(SELECT DISTINCT salary
# 	FROM Employee
# 	ORDER BY salary desc
# 	LIMIT 1,1)
# 	,Null) AS SecondHighestSalary

第 5 天:合并

175 组合两个表

https://leetcode.cn/problems/combine-two-tables/

-- sql左连接和右连接区别是:左连接会读取左边数据表的全部数据,即使右边数据表没有对应数据;而右连接会读取右边数据表的全部数据,即使左边数据表没有对应数据

-- 多表外连接即用外连接的方式,连接多个表,在使用过程中,尽量避免使用`RIGHT JOIN`,最好都适用`LEFT JOIN`,因为在一个Query中同时使用`LEFT`,`RIGHT`,及`INNER JOIN`时,情况会变得很复杂,可读性差


# 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 Address
RIGHT JOIN Person
ON Person.PersonId = Address.PersonId;

1581 进店却未进行过交易的顾客

https://leetcode.cn/problems/customer-who-visited-but-did-not-make-any-transactions/

# SELECT customer_id,COUNT(customer_id) AS count_no_trans 
-- 解法1:NOT IN + 双层SELECT
SELECT 
	customer_id,
    COUNT(customer_id) count_no_trans 
FROM Visits
WHERE visit_id NOT IN(	SELECT 
						visit_id 
						FROM Transactions)
GROUP BY customer_id;

-- 解法2:IS NULL +JOIN
SELECT customer_id, COUNT(customer_id) count_no_trans 
FROM Visits 
LEFT JOIN  Transactions
	ON  Visits.visit_id = Transactions.visit_id
WHERE  transaction_id IS NULL
GROUP BY customer_id;

1148 文章浏览 I

https://leetcode.cn/problems/article-views-i/

-- 解法1和解法2效率相同
-- 解法1:DISTINCT
SELECT DISTINCT author_id id
FROM Views
WHERE author_id = viewer_id
ORDER BY author_id


-- 解法2:GROUP BY
# SELECT author_id AS 'id'
# FROM Views
# WHERE author_id = viewer_id
# GROUP BY id
# ORDER BY id

第 6 天:合并

197 上升的温度

https://leetcode.cn/problems/rising-temperature/

# Write your MySQL query statement below
-- 两者效率相同,个人认为解法1可读性更高

-- 解法1:FROM选择双表
SELECT w1.id
FROM Weather w1,Weather w2
WHERE DATEDIFF(w1.recordDate,w2.recordDate)=1 
AND w1.temperature > w2.temperature;
-- 反着来也行
# SELECT w2.Id
# FROM Weather w1, Weather w2
# WHERE DATEDIFF(w2.recordDate, w1.recordDate) = 1
# AND w1.Temperature < w2.Temperature;


-- 解法2:通过JOIN
SELECT
	w1.id
FROM Weather w1
JOIN Weather w2
	ON DATEDIFF(w1.recordDate,w2.recordDate)=1
		AND w1.temperature>w2.temperature;

607 销售员

https://leetcode.cn/problems/sales-person/

# Write your MySQL query statement below
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')
;

第 7 天:计算函数

1141 查询近30天活跃用户数

https://leetcode.cn/problems/user-activity-for-the-past-30-days-i/

# Write your MySQL query statement below
SELECT 
	activity_date day,
	COUNT(DISTINCT user_id) active_users
FROM Activity
WHERE DATEDIFF('2019-07-27',activity_date)<30 
    AND DATEDIFF('2019-07-27',activity_date)>0 -- 截至 2019-07-27(包含2019-07-27)
GROUP BY activity_date;

1693 每天的领导和合伙人

https://leetcode.cn/problems/daily-leads-and-partners/

# Write your MySQL query statement below
select date_id , make_name ,count(distinct lead_id) unique_leads , count(distinct partner_id) unique_partners
from dailysales
group by date_id,make_name;

-- ID这里为啥会有0,迷惑,对题目输出困惑了五六分钟,才发现0也是id,之前以为id为0 就是NULl害

1729 求关注者的数量

https://leetcode.cn/problems/find-followers-count/

# Write your MySQL query statement below
SELECT user_id ,COUNT(follower_id) followers_count
FROM Followers
GROUP BY user_id
ORDER BY user_id;

第 8 天:计算函数

586 订单最多的客户

https://leetcode.cn/problems/customer-placing-the-largest-number-of-orders/

# Write your MySQL query statement below
-- 正常题解
SELECT customer_number
FROM Orders
GROUP BY customer_number
ORDER BY COUNT(order_number)  DESC
LIMIT 1;


-- 使用HAVING,ORDER BYBY,LIMIT1,可以解决两个最
# SELECT
#     customer_number
# FROM
#     Orders
# GROUP BY customer_number
# HAVING COUNT(*) = (
#     SELECT 
#         COUNT(customer_number) AS 'cnt' 
#     FROM 
#         Orders 
#     GROUP BY customer_number 
#     ORDER BY cnt DESC  
#     LIMIT 1
#     );

-- 使用HAVING ALL同样可以解决两个最
# SELECT customer_number
# FROM Orders
# GROUP BY customer_number
# HAVING COUNT(*) >= ALL(
#     SELECT COUNT(*) AS cnt
#     FROM Orders
#     GROUP BY customer_number    
#     );

511 游戏玩法分析 I

https://leetcode.cn/problems/game-play-analysis-i/

# Write your MySQL query statement below
select player_id,min(event_date) first_login
from activity
group by player_id

# select distinct player_id,min(event_date) over(partition by player_id) as first_login
# from Activity

1890 2020年最后一次登录

https://leetcode.cn/problems/the-latest-login-in-2020/

# Write your MySQL query statement below
SELECT user_id, max(time_stamp) last_stamp
FROM Logins
WHERE year(time_stamp) = 2020
GROUP BY user_id

1741 查找每个员工花费的总时间

https://leetcode.cn/problems/find-total-time-spent-by-each-employee/

# Write your MySQL query statement below
SELECT  
	event_day day,
    emp_id,
    SUM(out_time-in_time) total_time
FROM Employees
GROUP BY day,emp_id;

第 9 天:控制流

1393 股票的资本损益(中等题)

https://leetcode.cn/problems/capital-gainloss/

# Write your MySQL query statement below

-- SUM + CASE WHEN
# SELECT  stock_name, SUM(CASE WHEN operation="Buy" then -price else price end) capital_gain_loss
# FROM Stocks 
# GROUP BY stock_name;

-- SUM + IF
SELECT  stock_name, SUM(IF(operation="Buy",-price,price)) capital_gain_loss
FROM Stocks 
GROUP BY stock_name;


-- 两层SELECT
# SELECT 
# 	s1.stock_name,
#     s2.sell-s1.buy capital_gain_loss 
# FROM (
# 	SELECT 
# 		stock_name,
#         SUM(price) buy 
# 	FROM Stocks 
#     WHERE operation="Buy" 
#     GROUP BY stock_name) AS s1,
#     (
#     SELECT 
# 		stock_name,
#         SUM(price) sell 
# 	FROM Stocks 
#     WHERE operation="Sell" 
#     GROUP BY stock_name) AS s2 
# WHERE s1.stock_name=s2.stock_name

1407 排名靠前的旅行者

https://leetcode.cn/problems/top-travellers/

# Write your MySQL query statement below
# SELECT 
# 	name,
#     IFNULL(travelled_distance,0)  AS travelled_distance
# FROM Users
# LEFT JOIN(
# 	SELECT
# 		user_id,
# 		SUM(distance) travelled_distance
# 	FROM Rides
# 	GROUP BY user_id) x
# ON Users.id =  x.user_id
# ORDER BY travelled_distance DESC,name;

SELECT 
	name,
    IFNULL(SUM(distance),0) travelled_distance
FROM Users u
LEFT JOIN Rides r ON u.id  = r.user_id
GROUP BY u.id,name
ORDER BY travelled_distance DESC, name;

1158 市场分析 I(中等题)

https://leetcode.cn/problems/market-analysis-i/

# Write your MySQL query statement below
-- 官方解
# select Users.user_id as buyer_id, join_date, ifnull(UserBuy.cnt, 0) as orders_in_2019
# from Users
# left join (
#     select buyer_id, count(order_id) cnt 
#     from Orders
#     -- where order_date between '2019-01-01' and '2019-12-31'
#     where YEAR(order_date)=2019
#     group by buyer_id
# ) UserBuy
# on Users.user_id = UserBuy.buyer_id;

SELECT user_id buyer_id,join_date,COUNT(order_id) orders_in_2019
FROM users 
LEFT JOIN orders
ON user_id = buyer_id AND YEAR(order_date)='2019'
GROUP BY user_id,join_date;

# SELECT user_id buyer_id,join_date,COUNT(buyer_id) orders_in_2019
# FROM users u
# LEFT JOIN orders o ON YEAR(o.order_date)='2019' AND u.user_id=o.buyer_id
# GROUP BY user_id,join_date;

第 10 天 过滤

182 查找重复的电子邮箱

https://leetcode.cn/problems/duplicate-emails/

# Write your MySQL query statement below
-- 效率:1>3>2
-- 解法1
SELECT Email FROM Person GROUP BY Email HAVING COUNT(Email)>1;

-- 解法2
# SELECT Email FROM (SELECT COUNT(1) AS T,Email FROM Person GROUP BY Email) r WHERE r.T>1;

-- 解法3
# SELECT DISTINCT(P1.Email) FROM Person P1  
# JOIN Person  P2 ON p1.Email = p2.Email AND p1.Id!=p2.Id;

1050 合作过至少三次的演员和导演

https://leetcode.cn/problems/actors-and-directors-who-cooperated-at-least-three-times/

# Write your MySQL query statement below
SELECT 
    actor_id,
    director_id
FROM ActorDirector
GROUP BY actor_id,director_id
-- 选出合作过的导演和演员
HAVING  COUNT(*)>=3
-- 筛选出合作次数大于等于3的组合

1587 银行账户概要 II

https://leetcode.cn/problems/bank-account-summary-ii/

# Write your MySQL query statement below
SELECT
    name,
    SUM(amount) balance
FROM Users
LEFT JOIN Transactions USING(account)
GROUP BY name
HAVING balance>=10000

1084 销售分析III

https://leetcode.cn/problems/sales-analysis-iii/

# Write your MySQL query statement below
SELECT p.product_id,product_name FROM sales s,product p 
WHERE s.product_id=p.product_id
GROUP BY p.product_id
HAVING SUM(sale_date < '2019-01-01')=0
AND SUM(sale_date>'2019-03-31')=0;
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值