【问题标题】:SQL Query optimization written for an Hacker Rank Challenge为 Hacker Rank Challenge 编写的 SQL 查询优化
【发布时间】:2020-04-18 01:45:58
【问题描述】:

对于黑客级别的 SQL 挑战,我编写了生成所需结果的 SQL 脚本。但是我过度使用了太多的子查询,我想知道代码是否可以优化。下面是 SQL 挑战的链接 https://www.hackerrank.com/challenges/challenges/problem.

简单的挑战细节:

“写一个查询来打印hacker_id、姓名和每个学生创建的挑战总数。按挑战总数降序排列你的结果。如果多个学生创建了相同的数字的挑战,然后按hacker_id对结果进行排序。如果多个学生创建了相同数量的挑战并且计数小于创建的挑战的最大数量,则将这些学生排除在结果之外。”

这是我为上述挑战编写的代码:

SELECt
   h.hacker_id,
   h.name,
   t.tot_ch 
from
   hackers h,
   (
      Select
         c.hacker_id,
         count(c.challenge_id) Tot_ch 
      from
         challenges c 
      Group by
         hacker_id 
   )
   T,
   (
      SELect
         tot_ch,
         count(tot_ch) DUPS 
      from
         (
            Select
               c.hacker_id,
               count(c.challenge_id) Tot_ch 
            from
               challenges c 
            Group by
               hacker_id 
         )
     group by tot_ch 
   )
   D 
Where
   h.hacker_id = t.hacker_id 
   And d.tot_ch = t.tot_ch 
   AND 
   (
      CASe
         when
            d.dups < 2 
         then
            1 
         ELSE
( 
            case when 
               t.tot_ch = 
               (
                  select
                     MAX(T1.tot_ch) 
                  from
                     (
                        Select
                           c.hacker_id,
                           count(c.challenge_id) Tot_ch 
                        from
                           challenges c 
                        Group by
                           hacker_id 
                     )
                     T1 
               )
            then
               1 
            End
) 
      end
   )
   = 1 
ORDER BY
   t.tot_ch desc, h.hacker_id;

【问题讨论】:

  • 您应该从学习使用现代、明确、标准 JOIN 语法开始。在担心子查询之前获取正确的语法。
  • 查询不是脚本。
  • 了解 ctes、left join、union 和 except/minus(以及用于 except/minus 的 left join idms)。 (左连接是内连接联合所有不匹配的左表行由空值扩展。)

标签: sql oracle join case


【解决方案1】:

您可以使用analytical function 的组合如下:

Select hacker_id, name, cnt 
from
(Select t.*,
        count(1) over (partition by cnt) as same_cnt,
        Max(cnt) over () as max_cnt
   from
   (Select h.hacker_id, 
           h.name,
           Count(1) as cnt
      From hackers h
      Join challenges c 
        On h.hacker_id = c.hacker_id
  Group by h.hacker_id, h.name) t)
     Where same_cnt = 1 
        or cnt = max_cnt

干杯!!

【讨论】:

    【解决方案2】:

    您可以使用公用表表达式将重复的子查询转换为内联视图,您可以像查询普通视图一样查询:

    WITH cteCount AS (SELECT c.HACKER_ID,
                             COUNT(c.CHALLENGE_ID) TOT_CH
                        FROM CHALLENGES c
                        GROUP BY HACKER_ID),
         cteDups AS (SELECT TOT_CH,
                            COUNT(TOT_CH) AS DUPS 
                       FROM cteCount
                       GROUP BY TOT_CH)
    SELECT h.HACKER_ID,
           h.NAME,
           t.TOT_CH 
      FROM HACKERS h
      INNER JOIN cteCount t
        ON t.HACKER_ID = h.HACKER_ID
      INNER JOIN cteDups d
        ON d.TOT_CH = t.TOT_CH
      WHERE CASE
              WHEN d.DUPS < 2
                THEN 1
              WHEN t.TOT_CH = (SELECT MAX(TOT_CH)
                                 FROM cteCount)
                THEN 1
            END = 1
      ORDER BY t.TOT_CH DESC,
               h.HACKER_ID;
    

    【讨论】:

      【解决方案3】:
      with 
      cte1 as (select hacker_id, count(challenge_id) as challenges_created 
               from Challenges
               group by hacker_id
               order by hacker_id
      ),
      cte2 as (select c.hacker_id, h.name, c.challenges_created 
               from cte1 c 
               left join Hackers h
               on c.hacker_id = h.hacker_id
      ),
      cte3 as (select max(challenges_created) as max_challenges 
               from cte2
      ),
      cte4 as (select challenges_created, count(hacker_id) as  hack_count_same
               from cte2 
               where challenges_created not in(select max_challenges from cte3)
               group by challenges_created
               order by challenges_created
      ),
      cte5 as (select hacker_id, name, challenges_created 
               from cte2
               where challenges_created not in(select challenges_created from cte4 where hack_count_same > 1)
      ),
      cte6 as (select hacker_id, name, challenges_created 
               from cte5
               union all 
               select hacker_id, name, challenges_created 
               from cte2
               where challenges_created  in(select max_challenges from cte3)
               and hacker_id not in(select hacker_id from cte5)
      )
               select * 
               from cte6
               order by challenges_created desc, hacker_id;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-10
        • 2012-03-24
        • 2013-01-10
        相关资源
        最近更新 更多