【问题标题】:Need help understanding COUNT and <> operators (Hackerrank SQL Challenges question)需要帮助理解 COUNT 和 <> 运算符(Hackerrank SQL 挑战问题)
【发布时间】:2019-06-14 13:39:25
【问题描述】:

我正在使用 MySQL,目前正试图了解一段代码的工作原理。这是关于Hackerrank SQL question titled "Challenges"。问题陈述如下

Julia 要求她的学生创造一些编码挑战。写一个 查询以打印hacker_id、名称和挑战总数 由每个学生创建。按总人数对结果进行排序 挑战按降序排列。如果不止一名学生创建了 相同数量的挑战,然后按hacker_id对结果进行排序。如果更多 比一个学生创造了相同数量的挑战和计数 小于创建的最大挑战数,则排除 结果中的那些学生。

我找到了一个有效的 MySQL 解决方案 courtesy of this page,它使用以下代码:

SELECT c.hacker_id, h.name, COUNT(c.challenge_id) AS cnt 
FROM Hackers AS h JOIN Challenges AS c ON h.hacker_id = c.hacker_id
GROUP BY c.hacker_id, h.name HAVING
cnt = (SELECT COUNT(c1.challenge_id) FROM Challenges AS c1 GROUP BY c1.hacker_id ORDER BY COUNT(*) DESC LIMIT 1) OR
cnt NOT IN (SELECT COUNT(c2.challenge_id) FROM Challenges AS c2 GROUP BY c2.hacker_id HAVING c2.hacker_id <> c.hacker_id)
ORDER BY cnt DESC, c.hacker_id;

到目前为止,我理解问题陈述,直到“如果多个学生创建了相同数量的挑战并且计数小于创建的挑战的最大数量,则将这些学生排除在结果。”我根本不知道如何构建查询来解决该语句。

在上面提供的代码中,我理解它在本节之前所做的一切

 cnt NOT IN (SELECT COUNT(c2.challenge_id) FROM Challenges AS c2 GROUP BY c2.hacker_id HAVING c2.hacker_id <> c.hacker_id)

谁能帮我理解这条线完成了什么以及它背后的逻辑?具体来说,我不知道 c2.hacker_id c.hacker_id 应该做什么。我猜整行选择了由不是同一个人的特定hacker_ids完成的challenge_ids的数量,但我不知道如何解决查询。

【问题讨论】:

  • c2.hacker_id &lt;&gt; c.hacker_id 这里&lt;&gt; 表示!= (not equals to)
  • 请告诉我们正在使用的 MySQL HackerRank 版本。如果您可以访问 MySQL 8+,您的问题将大大简化。

标签: mysql


【解决方案1】:

假设您在没有此子句的情况下从查询中获得了黑客 id 和子计数的列表:

hacker, counter 
1, 10
2, 9
3, 9

2 和 3 不应该在其中,因为它们在计数上并列,因此我们可以将其实现为排除任何计数为 9 的人

考虑到从概念上讲,数据库将对结果中的每一行运行查询:当处理黑客 2 行时,查询会获取一个挑战计数列表,其中有人 id 不是 2。这意味着在考虑黑客 2 时,dB 将拉返回以下计数的列表:

10,  --it comes from hacker 1
9     --it comes from hacker 3

然后数据库进入“我正在处理黑客 2,其计数为 9。如果黑客 2 的计数 (9) 不在以下值列表中,我可能只会在结果中包含黑客 2:10、9。哦, 9 在禁止值列表中。我将从结果中排除黑客 2

对黑客 3 重复,这次 9 计数来自黑客 2,所以 3 也被排除在外

【讨论】:

    【解决方案2】:

    分析函数非常对这样的问题有帮助,所以我将提供一个使用 MySQL 8+ 的解决方案,向前看,这将是您问题的读者可能会使用的数据库(而且 HackerRank 在某些时候也会使用 MySQL 8+)。

    WITH cte AS (
        SELECT
            c.hacker_id,
            h.name,
            COUNT(c.challenge_id) AS cnt,
            ROW_NUMBER() OVER (ORDER BY COUNT(c.challenge_id) DESC) rn,
            MIN(c.hacker_id) OVER (PARTITION BY COUNT(c.challenge_id)) hacker_id_min,
            MAX(c.hacker_id) OVER (PARTITION BY COUNT(c.challenge_id)) hacker_id_max
        FROM Hackers AS h
        INNER JOIN Challenges AS c
            ON h.hacker_id = c.hacker_id
        GROUP BY
            c.hacker_id,
            h.name
    )
    
    SELECT
        hacker_id,
        name,
        cnt
    FROM cte
    WHERE
        rn = 1 OR hacker_id_min = hacker_id_max
    ORDER BY
        cnt DESC,
        c.hacker_id;
    

    这通过计算行号来回答单词,按计数降序排序。它还计算每个挑战计数分区的最小和最大hacker_id 值。如果记录属于最高计数,则保留记录,无论第一名如何。如果给定计数仅与单个用户相关联,也会保留记录。

    【讨论】: