SQL Server Union 全部在 2 个表上,除此之外

Posted

技术标签:

【中文标题】SQL Server Union 全部在 2 个表上,除此之外【英文标题】:SQL Server Union All on 2 tables and Except 【发布时间】:2020-04-30 02:09:40 【问题描述】:

我有 2 张表黑客和挑战。黑客创建挑战,这些挑战使用hacker_id 存储在挑战表中。

Hackers:hacker_id是黑客的id,name是黑客的名字
 ___________________
|Column    | Type   |
|-------------------|
|hacker_id |integer |
|-------------------|
|name      |string  |
_____________________
挑战:challenge_id 是挑战的 ID,hacker_id 是创建挑战的学生的 ID。
 ______________________
|Column       | Type   |
|----------------------|
|challenge_id |integer |
|----------------------|
|name         |string  |
________________________

如果多个黑客创建了相同数量的挑战,并且计数小于创建的最大挑战数量,那么我必须将这些黑客排除在结果之外。

我想使用 SET 理论的概念来解决它,我想首先使用 UNION ALL 来计算相等的挑战,然后使用减号将其从主表中排除。

这是我尝试过的:

SELECT H.name, C.Hacker_id, count(C.challenge_id) AS total_cnt
FROM Hackers H INNER JOIN Challenges C 
ON H.Hacker_id= C.hacker ID
GROUP BY C.hacker_id, H.name

Except 

Select * FROM
(
   (SELECT H2.name, C2.Hacker_id, count(C2.challenge_id) AS total_cnt2
   FROM Hackers H2 INNER JOIN Challenges C2 
   ON H2.Hacker_id= C2.hacker ID
   where total_cnt2!= max(count(C.challenge_id))
   GROUP BY C2.hacker_id, H2.name) t1

 UNION ALL 

   (SELECT H.name, C.Hacker_id, count(C.challenge_id) AS total_cnt3
   FROM Hackers H INNER JOIN Challenges C 
   ON H.Hacker_id= C.hacker ID
   where total_cnt3!= max(count(C.challenge_id))
   GROUP BY C.hacker_id, H.name) t2
)
/* I know this is not correct but I want only where count of challenge is same*/
WHERE t1. total_cnt2= t2. total_cnt3
;

加入后的样本输入为:

我想要这个确切的第一个表 Except 挑战计数,它们的计数相等(Rose 为 4,Frank 为 4)。

问题来自 Hackerrank 挑战之一 (https://www.hackerrank.com/challenges/challenges/problem?isFullScreen=true)

【问题讨论】:

在 MS SQL Server 上,MINUS 被称为 EXCEPT: docs.microsoft.com/en-us/sql/t-sql/language-elements/… 【参考方案1】:

相当有趣的挑战。

我不确定在这种特定情况下使用 EXCEPT 是否真的能为您带来任何好处,至少我无法解决,因为您可以将 EXISTS(参见下面的脚本)更改为 NOT EXISTS 而无需使用除了,但您的结果可能会有所不同。

这是一个使用 EXCEPT 满足要求的 SQL:

SELECT hacker_ID, [Name], total_cnt FROM 
(
    SELECT H.[Name], C.Hacker_id, COUNT(C.challenge_id) AS total_cnt
    FROM Hackers H INNER JOIN Challenges C 
    ON H.Hacker_id = C.hacker_ID
    GROUP BY C.hacker_id, H.[Name]
) t1

EXCEPT

SELECT hacker_ID, [Name], total_cnt FROM 
(
    SELECT H.[Name], C.Hacker_id, COUNT(C.challenge_id) AS total_cnt
    FROM Hackers H INNER JOIN Challenges C 
    ON H.Hacker_id = C.hacker_ID
    GROUP BY C.hacker_id, H.[Name]
) t2
WHERE EXISTS (SELECT 1 FROM (SELECT H2.[Name], C2.Hacker_ID, COUNT(C2.challenge_id) AS total_cnt
                             FROM Hackers H2 INNER JOIN Challenges C2 
                             ON H2.Hacker_id = C2.hacker_ID
                             GROUP BY C2.hacker_id, H2.[Name]) T3 WHERE T2.Hacker_ID <> T3.Hacker_ID AND T2.total_cnt = T3.total_cnt
                             AND T3.total_cnt < (SELECT MAX(total_cnt) FROM (SELECT COUNT(*) AS total_cnt 
                                                                    FROM Hackers H3 INNER JOIN Challenges C3 
                                                                    ON H3.Hacker_id = C3.hacker_ID
                                                                    GROUP BY C3.hacker_id, H3.[Name]) T4))
ORDER BY total_cnt DESC, hacker_id 

我在其他用户的其他解决方案中找到的最简洁的答案如下:https://www.hackerrank.com/rest/contests/master/challenges/challenges/hackers/dotnokato/download_solution?primary=true

【讨论】:

谢谢!我已经使用常规方法解决了这个问题,但想要一种集合论方法,因为我认为这样做会很有趣!

以上是关于SQL Server Union 全部在 2 个表上,除此之外的主要内容,如果未能解决你的问题,请参考以下文章

sql server 查询 order by 与 union 并替换多个列的空值

sql中用union all最多可以合并几个表

sql server 中union的用法?

sql server 2000返回在第一个表中但不在第二个表中的数据

SQL Server学习笔记——单表查询

SQL Server学习笔记——单表查询