leetcode数据库题第五弹

leetcode数据库题第五弹

  • 1141. 查询近30天活跃用户数
  • 1148. 文章浏览 I
  • 1158. 市场分析 I
  • 1164. 指定日期的产品价格
  • 1174. 即时食物配送 II
  • 1179. 重新格式化部门表
  • 1193. 每月交易 I
  • 1204. 最后一个能进入电梯的人
  • 1211. 查询结果的质量和占比
  • 1251. 平均售价
  • 小结

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

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

简单题目,统计每天活跃的用户,有的用户会跨天,则两天都算活跃用户,也就是忽略状态,有操作就算。

# oracle 因为日期不包含时间,所以 oracle 还要转一下数据类型
select to_char(activity_date,'YYYY-mm-DD') day,count(distinct user_id) active_users 
from activity 
where activity_date between '2019-6-28' and '2019-7-27'
group by activity_date
# mssql && mysql
select activity_date day,count(distinct user_id) active_users 
from activity 
where activity_date between '2019-6-28' and '2019-7-27'
group by activity_date

CSDN 文盲老顾的博客,https://blog.csdn.net/superwfei

1148. 文章浏览 I

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

嗯。。。。。排重 distinct ?注意输出信息有要求排序。

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

1158. 市场分析 I

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

类型转换函数,日期函数要熟练掌握。因为要列出订单数为0的用户,所以应该先统计后关联。然后为空的数据,就要用到各自的 nvl、isnull、ifnull 了,注意不同数据库有不同的函数和用法。

#oracle
select u.user_id buyer_id,to_char(join_date,'YYYY-mm-DD') join_date,nvl(orders_in_2019,0) orders_in_2019
from users u
left join (
    select buyer_id,count(order_id) orders_in_2019
    from orders
    where order_date>='2019-01-01' and order_date<'2020-01-01'
    group by buyer_id
) c on u.user_id=c.buyer_id
# mssql
select u.user_id buyer_id,join_date,isnull(orders_in_2019,0) orders_in_2019
from users u
left join (
    select buyer_id,count(order_id) orders_in_2019
    from orders
    where order_date>='2019-01-01' and order_date<'2020-01-01'
    group by buyer_id
) c on u.user_id=c.buyer_id
# mysql
select u.user_id buyer_id,join_date,ifnull(orders_in_2019,0) orders_in_2019
from users u
left join (
    select buyer_id,count(order_id) orders_in_2019
    from orders
    where order_date>='2019-01-01' and order_date<'2020-01-01'
    group by buyer_id
) c on u.user_id=c.buyer_id

1164. 指定日期的产品价格

https://leetcode.cn/problems/product-price-at-a-given-date/

用两个子查询即可,一个取得所有产品 id ,并给出默认价格,另一个获取截止日期前最后一次更新的价格,如果没有更新的,就按默认价格,否则按更新价格列出。

# mysql
select a.product_id,ifnull(b.new_price,a.price) price 
from (
    select distinct product_id,10 price
    from products
) a
left join (
    select * from (
        select *,row_number() over(partition by product_id order by change_date desc) rid 
        from products
        where change_date<='2019-08-16'
    ) x
    where rid=1
) b on a.product_id=b.product_id
# mssql
select a.product_id,isnull(b.new_price,a.price) price 
from (
    select distinct product_id,10 price
    from products
) a
left join (
    select * from (
        select *,row_number() over(partition by product_id order by change_date desc) rid 
        from products
        where change_date<='2019-08-16'
    ) x
    where rid=1
) b on a.product_id=b.product_id
# oracle 
select a.product_id,nvl(b.new_price,a.price) price 
from (
    select distinct product_id,10 as price
    from products
) a
left join (
    select * from (
        select p.*,row_number() over(partition by product_id order by change_date desc) rid 
        from products p
        where change_date<='2019-08-16'
    ) x
    where x.rid=1
) b on a.product_id=b.product_id

1174. 即时食物配送 II

https://leetcode.cn/problems/immediate-food-delivery-ii/

额。。。sum 聚合函数立大功。因为 mssql 需要整型除整型,最后还会得到整型,所以,中间懒得转类型,直接乘一个浮点型就当转类型了。

# oracle && mysql
select round(sum(case when order_date=customer_pref_delivery_date then 1 else 0 end) / count(0) * 100,2) immediate_percentage
from (
    select d.*,row_number() over(partition by customer_id order by order_date) rid 
    from delivery d
) a
where rid=1
# mssql
select convert(decimal(5,2),sum(case when order_date=customer_pref_delivery_date then 1 else 0 end) * 1.0 / count(0) * 100) immediate_percentage
from (
    select d.*,row_number() over(partition by customer_id order by order_date) rid 
    from delivery d
) a
where rid=1

1179. 重新格式化部门表

https://leetcode.cn/problems/reformat-department-table/

哦吼,一个经典行转列的需求。

# 经典行转列,一拖三
select id,max(case when month='Jan' then revenue else null end) Jan_Revenue
    ,max(case when month='Feb' then revenue else null end) Feb_Revenue
    ,max(case when month='Mar' then revenue else null end) Mar_Revenue
    ,max(case when month='Apr' then revenue else null end) Apr_Revenue
    ,max(case when month='May' then revenue else null end) May_Revenue
    ,max(case when month='Jun' then revenue else null end) Jun_Revenue
    ,max(case when month='Jul' then revenue else null end) Jul_Revenue
    ,max(case when month='Aug' then revenue else null end) Aug_Revenue
    ,max(case when month='Sep' then revenue else null end) Sep_Revenue
    ,max(case when month='Oct' then revenue else null end) Oct_Revenue
    ,max(case when month='Nov' then revenue else null end) Nov_Revenue
    ,max(case when month='Dec' then revenue else null end) Dec_Revenue
from department
group by id
# mssql 特有行转列
select id,Jan Jan_Revenue,Feb Feb_Revenue,Mar Mar_Revenue,Apr Apr_Revenue,May May_Revenue,Jun Jun_Revenue,Jul Jul_Revenue,Aug Aug_Revenue,Sep Sep_Revenue,Oct Oct_Revenue,Nov Nov_Revenue,Dec  Dec_Revenue
from department d
pivot(max(revenue) for month in (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec)) p

1193. 每月交易 I

https://leetcode.cn/problems/monthly-transactions-i/

嗯。。。。日期转字符串并截取,然后聚合加 case when 。

# mssql
select convert(varchar(7),trans_date,126) month,country,count(0) trans_count
    ,sum(case when state='approved' then 1 else 0 end) approved_count
    ,sum(amount) trans_total_amount,sum(case when state='approved' then amount else 0 end) approved_total_amount
from transactions
group by convert(varchar(7),trans_date,126),country
# oracle
select to_char(trans_date,'YYYY-mm') month,country,count(0) trans_count
    ,sum(case when state='approved' then 1 else 0 end) approved_count
    ,sum(amount) trans_total_amount,sum(case when state='approved' then amount else 0 end) approved_total_amount
from transactions
group by to_char(trans_date,'YYYY-mm'),country
# mysql
select DATE_FORMAT(trans_date,'%Y-%m') month,country,count(0) trans_count
    ,sum(case when state='approved' then 1 else 0 end) approved_count
    ,sum(amount) trans_total_amount,sum(case when state='approved' then amount else 0 end) approved_total_amount
from transactions
group by DATE_FORMAT(trans_date,'%Y-%m'),country

然后,测试了一下,可以建立索引,下次碰到有超时风险的情况,就用索引来优化一下好了。

#mssql
if not exists(select * from sysindexes where name='NonClusteredIndex-20230619-125842')
	begin
        CREATE NONCLUSTERED INDEX [NonClusteredIndex-20230619-125842] ON transactions
        (
            id ASC
        )
        INCLUDE ( country,	trans_date) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);


	end
select convert(varchar(7),trans_date,126) month,country,count(0) trans_count
    ,sum(case when state='approved' then 1 else 0 end) approved_count
    ,sum(amount) trans_total_amount,sum(case when state='approved' then amount else 0 end) approved_total_amount
from transactions
group by convert(varchar(7),trans_date,126),country

1204. 最后一个能进入电梯的人

https://leetcode.cn/problems/last-person-to-fit-in-the-bus/

额,刚分享过的知识点,聚合函数也可以和开窗函数一起使用,嘿嘿。

由于 oracle 的 order 不能直接影响当前 rownum,所以还要套一层,真麻烦

# mssql
select top 1 person_name 
from (
    select *,sum(weight) over(order by turn) w 
    from queue
) a
where w<=1000
order by w desc
# mysql
select person_name 
from (
    select *,sum(weight) over(order by turn) w 
    from queue
) a
where w<=1000
order by w desc
limit 0,1
# oracle
select * from (
	select person_name 
	from (
	    select q.*,sum(weight) over(order by turn) w 
	    from queue q
	) a
	where w<=1000
	order by w desc
) a
where rownum=1

1211. 查询结果的质量和占比

https://leetcode.cn/problems/queries-quality-and-percentage/

嗯。。。计算后的结果求平均,以及部分符合条件的数据求汇总,sum 和 case 组合永远好用。额。。。注意百分比那个需要乘100。

# oracle && mysql
select query_name,round(avg(rating * 1.0 / position),2) quality
    ,round(sum(case when rating < 3 then 1.0 else 0 end) / count(0) * 100,2) poor_query_percentage
from queries
group by query_name
# mssql
select query_name,convert(decimal(5,2),avg(rating * 1.0 / position)) quality
    ,convert(decimal(5,2),sum(case when rating < 3 then 1.0 else 0 end) / count(0) * 100) poor_query_percentage
from queries
group by query_name

1251. 平均售价

https://leetcode.cn/problems/average-selling-price/

临到本期结束,又一个简单题目,直接聚合比聚合即可。

# mssql
select u.product_id,convert(decimal(8,2),sum(u.units * 1.0 * p.price) / sum(u.units)) average_price 
from unitssold u
left join prices p on u.purchase_date between p.start_date and p.end_date and u.product_id=p.product_id
group by u.product_id
# mysql && oracle
select u.product_id,round(sum(u.units * 1.0 * p.price) / sum(u.units),2) average_price 
from unitssold u
left join prices p on u.purchase_date between p.start_date and p.end_date and u.product_id=p.product_id
group by u.product_id

小结

本次题目,多余集中到了开窗函数和分组上,结合各种子查询,很容易得到结果。

注意审题,输出信息有时会有要求。注意子查询关联优先级,包含空值时,注意关联方式即可。

行转列文章,可以参考老顾之前的:【新星计划】数据库行列转换初识

聚合函数和开窗函数,可以参考老顾之前的:【新星计划】数据库 排名函数 初识

leetcode数据库题第五弹_第1张图片
可惜的是老顾没有力扣会员,也不明白,这些所谓的困难题目为什么要会员才能刷,真想进去玩玩看啊。

你可能感兴趣的:(数据库,leetcode,数据库,mysql,sqlserver,oracle)