「LeetCode SQL入门学习计划」

Leetcode MySQL 入门学习计划

选择

595. 大的国家
思路:

  1. 简单过滤,无顺序要求
  2. 显示字段 name, population, area
  3. area >= 3 000 000 or population >=25 000 000
select name, population, area from World where area >= 3000000 
or population >=25000000

1757. 可回收且低脂的产品
思路:

  1. 简单过滤, 无顺序要求
  2. 显示字段product_id
  3. 低脂 and 可回收
select product_id from Products where low_fats='Y' and recyclable='Y'

584. 寻找用户推荐人
思路:

  1. 简单过滤,无顺序要求
  2. 显示字段name
  3. 推荐人编号不是2有两种情况,为空或者非空非2
select name from customer where referee_id<>2 or referee_id is null

183. 从不订购的客户
思路:

  1. 涉及两表,所以需要连接两张表然后进行条件过滤
    1. 自查询作为筛选范围
    2. join连接
  2. 两张表靠Customers表的id连接可用left join
select Name as Customers from Customers as c 
where c.id not in (select CustomerId from Orders)
select Name as Customers from Customers c
left join Orders o on c.id = o. CustomerId 
where o.CustomerId is null

排序 & 修改

1873. 计算特殊奖金
思路:

  1. 需要构造bonus字段在查询结果
  2. 结果需要按照employee_id升序
  3. case when then else end
  4. 取余函数mod(, ), 字符串中的charAt - left(, )
select employee_id,
case when mod(employee_id, 2)=1 and left(name,1)!='M' then salary
else 0
end bonus from Employees
order by employee_id

627. 变更性别
思路:

  1. 用 case when then else end 控制赋值
update Salary set sex = case 
when sex = 'f' then 'm'
else 'f'
end

196. 删除重复的电子邮箱
思路:

  1. 删除的语句时delete from where
  2. 这里需要构建一个相同的表进行比较删除

字符串处理函数/正则

1667. 修复表中的名字

思路:

  1. 用upper函数全变为大写再使用left()函数
select user_id,
concat(left(upper(name),1),lower(substring(name,2))) as name
from Users order by user_id; 

1484. 按日期分组销售产品
思路:

  1. 分组计数,连接名
select sell_date, 
count(distinct product) num_sold, 
group_concat(distinct product) products 
from Activities
group by sell_date

1527. 患某种疾病的患者
思路:

select patient_id, patient_name, conditions
from Patients where conditions like 'DIAB1%'
or conditions like "% DIAB1%"

组合查询 & 指定选取

1965. 丢失信息的雇员
思路:

  1. 将两个表的employee_id合并
  2. 找到合并后个数为1的employee_id即为缺信息的id
select 
    employee_id 
from 
    (
    select employee_id from employees
    union all 
    select employee_id from salaries
) as t
group by 
    employee_id
having 
    count(employee_id) = 1
order by 
    employee_id;

1795. 每个产品在不同商店的价格
思路:

  1. 一列一列处理:把“列名”做为新列的value(如本题的store),把原来的value也作为新列(如本题的price),这是一个查询,其他列不要
  2. 用union all拼接每一列的结果
  3. 注意本题如果这一产品在商店里没有出售,则不输出这一行,所以要原列 is not null的筛选条件
select product_id, 'store1' store, store1 price
from products
where store1 is not null
union all 
select product_id, 'store2' store, store2 price
from products 
where store2 is not null
union all 
select product_id, 'store3' store, store3 price
from products
where store3 is not null;

608. 树节点
思路一:

  1. 通过union将符合条件的结果分别查出来拼接
    union会自动压缩多个结果集合中的重复结果,而union all则将所有的结果全部显示出来,不管是不是重复
select id, 'Root' Type 
from tree 
where p_id is null
union 
select id, 'Inner' Type
from tree
where id in (select distinct p_id from tree) and p_id is not null
union 
select id, 'Leaf' 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

A not in B的原理是拿A表值与B表值做是否不等的比较, 也就是a != b. 在sql中, null是缺失未知值而不是空值(详情请见MySQL reference).

当你判断任意值a != null时, 官方说, “You cannot use arithmetic comparison operators such as =, <, or <> to test for NULL”, 任何与null值的对比都将返回null. 因此返回结果为否,这点可以用代码 select if(1 = null, ‘true’, ‘false’)证实.

从上述原理可见, 当询问 id not in (select p_id from tree)时, 因为p_id有null值, 返回结果全为false, 于是跳到else的结果, 返回值为inner. 所以在答案中,leaf结果从未彰显,全被inner取代.

select
    id,
    case when p_id is null then "Root"
         when id not in (select p_id from tree where p_id is not null) then "Leaf"
         else "Inner"
    end as Type
from
    tree

176. 第二高的薪水
思路:

  1. 要想获取第二高,需要排序,使用 order by(默认是升序 asc,即从小到大),若想降序则使用关键字 desc
  2. 去重,如果有多个相同的数据,使用关键字 distinct 去重
  3. 判断临界输出,如果不存在第二高的薪水,查询应返回 null,使用 ifNull(查询,null)方法
  4. 起别名,使用关键字 as …
  5. 因为去了重,又按顺序排序,使用 limit()方法,查询第二大的数据,即第二高的薪水,即 limit(1,1) (因为默认从0开始,所以第一个1是查询第二大的数,第二个1是表示往后显示多少条数据,这里只需要一条)
select ifNull((
    select distinct salary from employee
    order by salary desc limit 1,1),null) 
    as SecondHighestSalary

合并

175. 组合两个表

select p.firstName, p.lastName, a.city , a.state 
from person p left join address a on p.personid = a.personid

1581. 进店却未进行过交易的顾客
思路一:
查询进店未消费的人然后分组统计

select v.customer_id, count(v.customer_id) count_no_trans from visits v
where v.visit_id not in (select visit_id from transactions)
group by v.customer_id

思路二:
链接两张表,用transaction_id来筛选微交易的customer_id, 然后分组统计

select v.customer_id as customer_id, count(v.customer_id) as count_no_trans 
from Visits v left join Transactions t on v.visit_id = t.visit_id 
where transaction_id is null group by v.customer_id;

1148. 文章浏览 I

select distinct author_id id from views
where author_id = viewer_id
order by viewer_id

197. 上升的温度
思路:
MySQL 使用 DATEDIFF 来比较两个日期类型的值。
因此,我们可以通过将 weather 与自身相结合,并使用 DATEDIFF() 函数。

SELECT w2.Id
FROM Weather w1, Weather w2
WHERE DATEDIFF(w2.RecordDate, w1.RecordDate) = 1
AND w1.Temperature < w2.Temperature

607. 销售员

select name from salesperson
where 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")
select name from salesperson
where sales_id not in
(select o.sales_id from orders o, company c
where o.com_id = c.com_id and c.name = "RED")

计算函数

1141. 查询近30天活跃用户数

select activity_date day, count(distinct user_id) active_users from activity
where datediff('2019-07-27', activity_date) >= 0 AND datediff('2019-07-27', activity_date) <30
group by activity_date

1693. 每天的领导和合伙人

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

1729. 求关注者的数量

select user_id, count(follower_id) followers_count from followers
group by user_id
order by user_id

586. 订单最多的客户

SELECT
    customer_number
FROM
    orders
GROUP BY customer_number
ORDER BY COUNT(*) DESC
LIMIT 1
;

511. 游戏玩法分析 I

select player_id, min(event_date) as first_login from activity
group by player_id;

1890. 2020年最后一次登录

select user_id, max(time_stamp) last_stamp 
    from logins t
        where year(time_stamp) = 2020
            group by t.user_id;

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

select event_day as day, emp_id, sum(out_time - in_time) as total_time 
from Employees 
group by emp_id, event_day 
order by event_day, emp_id;

控制流

1393. 股票的资本损益

select stock_name, sum(if(operation='Buy', -price, price)) capital_gain_loss
from stocks
group by stock_name

1407. 排名靠前的旅行者

select u.name, sum(if(r.distance is not null, r.distance, 0)) travelled_distance from users u left join rides r
on u.id = r.user_id
group by r.user_id
order by travelled_distance desc, u.name

1158. 市场分析 I
思路:
外连接时要注意where和on的区别,on是在连接构造临时表时执行的,不管on中条件是否成立都会返回主表(也就是left join左边的表)的内容,where是在临时表形成后执行筛选作用的,不满足条件的整行都会被过滤掉。如果这里用的是 where year(order_date)=‘2019’ 那么得到的结果将会把不满足条件的user_id为3,4的行给删掉。用on的话会保留user_id为3,4的行。

select user_id as buyer_id, join_date, count(order_id) as orders_in_2019
from Users as u left join Orders as o on u.user_id = o.buyer_id and year(order_date)='2019'
group by user_id

过滤

182. 查找重复的电子邮箱
思路:
where>group by>having>order by

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

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

select actor_id, director_id from actordirector
group by actor_id, director_id
having count(*)>=3

1587. 银行账户概要 II

select u.name NAME, sum(t.amount) BALANCE from users u left join transactions t
on u.account = t.account
group by t.account
having sum(t.amount) >= 10000

1084. 销售分析III

SELECT 
    s.product_id, p.product_name
FROM 
    sales s
LEFT JOIN 
    product p 
ON 
    s.product_id = p.product_id
GROUP BY 
    s.product_id
HAVING MIN(sale_date) >= '2019-01-01' 
AND MAX(sale_date) <= '2019-03-31';

你可能感兴趣的:(MySQL,leetcode,sql,学习)