• LeetCode:1179.重新格式化部门表


    题目链接:https://leetcode-cn.com/problems/reformat-department-table/

    题目

    部门表 Department

    +---------------+---------+
    | Column Name | Type |
    +---------------+---------+
    | id | int |
    | revenue | int |
    | month | varchar |
    +---------------+---------+
    (id, month) 是表的联合主键。
    这个表格有关于每个部门每月收入的信息。
    月份(month)可以取下列值 ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]。

    编写一个 SQL 查询来重新格式化表,使得新的表中有一个部门 id 列和一些对应 每个月 的收入(revenue)列。

    查询结果格式如下面的示例所示:

    Department 表:
    +------+---------+-------+
    | id | revenue | month |
    +------+---------+-------+
    | 1 | 8000 | Jan |
    | 2 | 9000 | Jan |
    | 3 | 10000 | Feb |
    | 1 | 7000 | Feb |
    | 1 | 6000 | Mar |
    +------+---------+-------+

    查询得到的结果表:
    +------+-------------+-------------+-------------+-----+-------------+
    | id | Jan_Revenue | Feb_Revenue | Mar_Revenue | ... | Dec_Revenue |
    +------+-------------+-------------+-------------+-----+-------------+
    | 1 | 8000 | 7000 | 6000 | ... | null |
    | 2 | 9000 | null | null | ... | null |
    | 3 | null | 10000 | null | ... | null |
    +------+-------------+-------------+-------------+-----+-------------+

    注意,结果表有 13 列 (1个部门 id 列 + 12个月份的收入列)。

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/reformat-department-table
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    解答

    第一感觉就是Python或者R中的长宽表转换。
    R中可以使用Reshape2包中的dcast函数进行处理。
    SQL中考虑用case when进行行列转换。

    本地oracle环境进行测试。

    -- 创建中间表
    create table temp_cwh_department
    (
      id int,
      revenue int,
      month varchar2(10)
    )
    
    -- 插入测试数据
    insert into temp_cwh_department values(1, 8000, 'Jan');
    insert into temp_cwh_department values(2, 9000, 'Jan');
    insert into temp_cwh_department values(3, 10000, 'Feb');
    insert into temp_cwh_department values(1, 7000, 'Feb');
    insert into temp_cwh_department values(1, 6000, 'Mar');
    
    -- 查询
    select * from temp_cwh_department
    
    -- 测试
    select id,
           max(case when month = 'Jan' then revenue else null end) as Jan_Revenue,
           max(case when month = 'Feb' then revenue else null end) as Feb_Revenue,
           max(case when month = 'Mar' then revenue else null end) as Mar_Revenue,
           max(case when month = 'Apr' then revenue else null end) as Apr_Revenue,
           max(case when month = 'May' then revenue else null end) as May_Revenue,
           max(case when month = 'Jun' then revenue else null end) as Jun_Revenue,
           max(case when month = 'Jul' then revenue else null end) as Jul_Revenue,
           max(case when month = 'Aug' then revenue else null end) as Aug_Revenue,
           max(case when month = 'Sep' then revenue else null end) as Sep_Revenue,
           max(case when month = 'Oct' then revenue else null end) as Oct_Revenue,
           max(case when month = 'Nov' then revenue else null end) as Nov_Revenue,
           max(case when month = 'Dec' then revenue else null end) as Dec_Revenue
    from temp_cwh_department
    group by id
    
    

    LeetCode提交

    ---- oracle ----
    /* Write your PL/SQL query statement below */
    select id,
           max(case when month = 'Jan' then revenue else null end) as Jan_Revenue,
           max(case when month = 'Feb' then revenue else null end) as Feb_Revenue,
           max(case when month = 'Mar' then revenue else null end) as Mar_Revenue,
           max(case when month = 'Apr' then revenue else null end) as Apr_Revenue,
           max(case when month = 'May' then revenue else null end) as May_Revenue,
           max(case when month = 'Jun' then revenue else null end) as Jun_Revenue,
           max(case when month = 'Jul' then revenue else null end) as Jul_Revenue,
           max(case when month = 'Aug' then revenue else null end) as Aug_Revenue,
           max(case when month = 'Sep' then revenue else null end) as Sep_Revenue,
           max(case when month = 'Oct' then revenue else null end) as Oct_Revenue,
           max(case when month = 'Nov' then revenue else null end) as Nov_Revenue,
           max(case when month = 'Dec' then revenue else null end) as Dec_Revenue
    from Department
    group by id ---- 887ms
    

    看看解答、评论,再学习一番。

    改用sum,速度快一点。

    ---- oracle ----
    ---- oracle ----
    /* Write your PL/SQL query statement below */
    select id,
           sum(case when month = 'Jan' then revenue else null end) as Jan_Revenue,
           sum(case when month = 'Feb' then revenue else null end) as Feb_Revenue,
           sum(case when month = 'Mar' then revenue else null end) as Mar_Revenue,
           sum(case when month = 'Apr' then revenue else null end) as Apr_Revenue,
           sum(case when month = 'May' then revenue else null end) as May_Revenue,
           sum(case when month = 'Jun' then revenue else null end) as Jun_Revenue,
           sum(case when month = 'Jul' then revenue else null end) as Jul_Revenue,
           sum(case when month = 'Aug' then revenue else null end) as Aug_Revenue,
           sum(case when month = 'Sep' then revenue else null end) as Sep_Revenue,
           sum(case when month = 'Oct' then revenue else null end) as Oct_Revenue,
           sum(case when month = 'Nov' then revenue else null end) as Nov_Revenue,
           sum(case when month = 'Dec' then revenue else null end) as Dec_Revenue
    from Department
    group by id ---- 603ms
    

    利用decode进行修改,再次提交。

    ---- oracle ----
    /* Write your PL/SQL query statement below */
    select id,
           sum(decode(month, 'Jan', revenue, null)) as Jan_Revenue,
    	   sum(decode(month, 'Feb', revenue, null)) as Feb_Revenue,
    	   sum(decode(month, 'Mar', revenue, null)) as Mar_Revenue,
    	   sum(decode(month, 'Apr', revenue, null)) as Apr_Revenue,
    	   sum(decode(month, 'May', revenue, null)) as May_Revenue,
    	   sum(decode(month, 'Jun', revenue, null)) as Jun_Revenue,
    	   sum(decode(month, 'Jul', revenue, null)) as Jul_Revenue,
    	   sum(decode(month, 'Aug', revenue, null)) as Aug_Revenue,
    	   sum(decode(month, 'Sep', revenue, null)) as Sep_Revenue,
    	   sum(decode(month, 'Oct', revenue, null)) as Oct_Revenue,
    	   sum(decode(month, 'Nov', revenue, null)) as Nov_Revenue,
    	   sum(decode(month, 'Dec', revenue, null)) as Dec_Revenue
    from Department
    group by id  ---- 947ms
    

    记录一个MySQL的用法。

    ---- MySQL ----
    # Write your MySQL query statement below
    select 
        `id`,
        max(if(`month` = 'Jan', revenue, null)) as "Jan_Revenue",
        max(if(`month` = 'Feb', revenue, null)) as "Feb_Revenue",
        max(if(`month` = 'Mar', revenue, null)) as "Mar_Revenue",
        max(if(`month` = 'Apr', revenue, null)) as "Apr_Revenue",
        max(if(`month` = 'May', revenue, null)) as "May_Revenue",
        max(if(`month` = 'Jun', revenue, null)) as "Jun_Revenue",
        max(if(`month` = 'Jul', revenue, null)) as "Jul_Revenue",
        max(if(`month` = 'Aug', revenue, null)) as "Aug_Revenue",
        max(if(`month` = 'Sep', revenue, null)) as "Sep_Revenue",
        max(if(`month` = 'Oct', revenue, null)) as "Oct_Revenue",
        max(if(`month` = 'Nov', revenue, null)) as "Nov_Revenue",
        max(if(`month` = 'Dec', revenue, null)) as "Dec_Revenue"
    from
        Department
    group by `id`; ---- 229ms
    

    思考

    通过case when进行判断的时候,例如:case when month = 'Jan' then revenue else null end as Jan_Revenue,会导致每一条记录产生一行,与原来表格的行数一致,因为需要通过group byid进行分组,但是分组之后一定需要一个聚合函数进行计算,此处就用max即可。

    oracle中if/else功能的实现方法

    1.标准的SQL规范

    -- 单个if
    if a = xxx then
    ......
    end if;
    
    -- 多个条件
    if a = xxx then
    ......
    else
    ......
    end if;
    
    -- 多个if
    if a = xxx then
    ......
    elsif a = xxx then
    ......
    end if;
    ---- 测试:在oracle中不用用于select中,只能用于存储过程
    

    2.decode函数

    语法decode(value, if1, then1, if2, then2, if3, then3,..., else)

    解释:如果value等于if1时,decode函数的结果返回then1,...,如果不等于任何一个if值,则返回else。

    3.case when

    case when a = '1' then 'xxxx'
         when a = '2' then 'yyyy'
    else 
         'zzzz'
    end as column
    

    注意点:

    • 以 case 开头,以 end 结尾;
    • 分支中 when 后跟条件,then 为显示结果;
    • else 为除此之外的默认情况,类似于高级语言程序中 switch case 的 default,可以不加;
    • end 后跟别名
  • 相关阅读:
    680C. Bear and Prime 100 数学
    Codeforces 681C. Heap Operations 优先队列
    Codeforces C. NP-Hard Problem 搜索
    Codeforces 689C. Mike and Chocolate Thieves 二分
    Codeforces 689B. Mike and Shortcuts SPFA/搜索
    Codeforces Round #223 (Div. 2) E. Sereja and Brackets 线段树区间合并
    Educational Codeforces Round 1 E. Chocolate Bar dp
    Testing Round #12 A,B,C 讨论,贪心,树状数组优化dp
    Educational Codeforces Round 2 E. Lomsat gelral 启发式合并map
    hdu 3706 Second My Problem First 单调队列
  • 原文地址:https://www.cnblogs.com/hider/p/11730444.html
Copyright © 2020-2023  润新知