SQL查找一起参加会议最多的两个人

Posted

技术标签:

【中文标题】SQL查找一起参加会议最多的两个人【英文标题】:SQL to find two people who participated in the most meetings together 【发布时间】:2021-03-16 06:54:27 【问题描述】:

我有如下三张表:

由此我得找出一起参加会议最多的两个人。

【问题讨论】:

这里的大多数人希望样本表数据和预期结果为格式化文本,而不是图像(或图像链接)。还向我们展示您当前的查询尝试。 minimal reproducible example 此截屏直接来自在线代码测试,违反了您在测试开始时达成的协议 【参考方案1】:

这只是一个自我加入会议:

select top (1) with ties p1.person_id, p2.person_id,
       count(*) as num_meetings
from participant p1 join
     participant p2
     on p1.meeting_id = p2.meeting_id
group by p1.person_id, p2.person_id
order by count(*) desc;

这会返回人员 ID,这会回答您的问题。如果您想了解有关person 表中人员的更多信息,则可以将此类信息加入其中。

【讨论】:

【参考方案2】:

这应该能让你继续前进。

样本数据

create table person
(
  id int,
  name nvarchar(10)
);    
insert into person (id, name) values
(1, 'Alice'),
(2, 'Bob'),
(3, 'Charlie'),
(4, 'David'),
(5, 'Eric');

create table meeting
(
  id int,
  title nvarchar(30)
);    
insert into meeting (id, title) values
(100, 'Corporate training'),
(200, 'Weekly sales'),
(300, 'Welcome introduction'),
(400, 'Evaluation');

create table participant
(
  idMeeting int,
  idPerson int
);    
insert into participant (idMeeting, idPerson) values
(100,1), (100,2), (100,3), (100,4), (100,5),
(200,1), (200,2),
         (300,2), (300,3), (300,4),
                  (400,3),          (400,5),
                  (500,3),          (500,5);

解决方案

通过加入具有相同会议 ID (pa2.idMeeting = pa1.idMeeting) 的参与者行来查找共享会议。

select me.title,
       pe1.name,
       pe2.name
from participant pa1
join participant pa2
  on  pa2.idMeeting = pa1.idMeeting
  and pa2.idPerson <> pa1.idPerson
join meeting me
  on me.id = pa1.idMeeting
join person pe1
  on pe1.id = pa1.idPerson
join person pe2
  on pe2.id = pa2.idPerson;

这将为您提供许多重复项,例如 Alice 转到 Corporate trainingBobBob 转到 Corporate trainingAlice。这些当然是相同的情况。我们可以通过说参与者不仅必须不同(pa2.idPerson &lt;&gt; pa1.idPerson),还必须“排序”(pa2.idPerson &gt; pa1.idPerson)来过滤重复。

select me.title,
       pe1.name,
       pe2.name
from participant pa1
join participant pa2
  on  pa2.idMeeting = pa1.idMeeting
  and pa2.idPerson > pa1.idPerson
join meeting me
  on me.id = pa1.idMeeting
join person pe1
  on pe1.id = pa1.idPerson
join person pe2
  on pe2.id = pa2.idPerson;

这为您提供了所有会议的所有独特组合。会议详细信息可以从结果中排除(删除join meeting)。对唯一组合 (group by pe1.name, pe2.name) 进行分组会给出一个计数 (count(1) as SharedMeetings)。

select pe1.name as Person1,
       pe2.name as Person2,
       count(1) as SharedMeetings
from participant pa1
join participant pa2
  on  pa2.idMeeting = pa1.idMeeting
  and pa2.idPerson > pa1.idPerson
join person pe1
  on pe1.id = pa1.idPerson
join person pe2
  on pe2.id = pa2.idPerson
group by pe1.name,
         pe2.name
order by SharedMeetings desc,
         pe1.name,
         pe2.name;

结果

对于最终查询:

Person1  Person2  SharedMeetings
-------  -------  --------------
Charlie  Eric     3
Alice    Bob      2
Bob      Charlie  2
Bob      David    2
Charlie  David    2
Alice    Charlie  1
Alice    David    1
Alice    Eric     1
Bob      Eric     1
David    Eric     1

Fiddle 查看实际情况(中间版本)。

【讨论】:

【参考方案3】:
SELECT  TOP(1)
        partnerA.person_id,
        partnerB.person_id,
        (
            SELECT  COUNT(*)
            FROM    meeting
            WHERE   EXISTS(SELECT 1 FROM participant WHERE participant.meeting_id = meeting.meeting_id AND participant.person_id = partnerA.person_id)
            AND     EXISTS(SELECT 1 FROM participant WHERE participant.meeting_id = meeting.meeting_id AND participant.person_id = partnerB.person_id)
        )   AS      participated_together

FROM        person  partnerA
CROSS JOIN  person  partnerB
WHERE       partnerA.person_id  <   partnerB.person_id

ORDER BY    participated_together   DESC

这仅显示 1 对与大多数会议一起,

但您可以更改它以显示更多 - 只需更改 TOP(1)

【讨论】:

【参考方案4】:

这是为了防止多对人参加相同的最大会议次数

with t1 as (select a.person_id, b.person_id, count(*) as cnt
       from meetings a join meetings b
       on a.meeting_id = b.meeting_id
       and a.person_id < b.person_id
       group by 1, 2)
       
       select concat(a.first_name, ' ', a.last_name) as person1,
       concat(b.first_name, ' ', b.last_name) as person2
       from t1 join person a
       on t1.person_id = a.person_id
       join person b
       on t1.person_id = b.person_id
       where cnt = (select max(cnt) from t1)

【讨论】:

【参考方案5】:

给你:

WITH OUTE AS
(SELECT CONCAT(D.FIRST_NAME,' ',D.LAST_NAME) FIRST_PERSON,
    CONCAT(E.FIRST_NAME,' ',E.LAST_NAME) SECOND_PERSON,
    C.TITLE
  FROM  PARTICIPANT A
    JOIN PARTICIPANT B
       ON A.MEETING_ID=B.MEETING_ID
      AND A.PERSON_ID !=B.PERSON_ID
      AND A.PERSON_ID < B.PERSON_ID
    JOIN PERSON D
       ON A.PERSON_ID=D.PERSON_ID
    JOIN PERSON E
       ON B.PERSON_ID=E.PERSON_ID
    JOIN MEETING C
       ON A.MEETING_ID=C.MEETING_ID
 ),

OUTE2 AS

(SELECT FIRST_PERSON,
    SECOND_PERSON,
    COUNT(*) MEETINGS
FROM OUTE
GROUP BY FIRST_PERSON,
         SECOND_PERSON)
,
OUTE3 AS
(SELECT X.FIRST_PERSON,
    X.SECOND_PERSON,
    X.TITLE,
    Y.MEETINGS
FROM OUTE X 
    JOIN OUTE2 Y
         ON X.FIRST_PERSON=Y.FIRST_PERSON
        AND X.SECOND_PERSON=Y.SECOND_PERSON
    ORDER BY Y.MEETINGS DESC)

SELECT FIRST_PERSON,
         SECOND_PERSON,
         TITLE
FROM OUTE3
    WHERE MEETINGS = (SELECT MEETINGS FROM OUTE3 LIMIT 1)
    ORDER BY TITLE;

解决方案有待改进。

【讨论】:

欢迎来到 SO。在大多数情况下,纯代码答案缺乏解释;考虑解释这如何回答问题,以便为未来的其他用户增加价值。 @ConnorLow,感谢您的评论。我将在下一次编辑中添加完整的解释。

以上是关于SQL查找一起参加会议最多的两个人的主要内容,如果未能解决你的问题,请参考以下文章

查找出现次数最多的数

查询 CSV::Table 以在普通的旧 ruby​​ 脚本中查找两个给定日期之间销售额最多的项目

如何使用数据透视查找填充列最多的记录?

sql语句,求出现次数最多的组中,出现次数最多的一条数据

在 SUM WinSQL 之后查找 MAX - 项目数量最多的分支

js查找数组中出现次数最多的元素