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

我有如下三张表:

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

【问题讨论】:

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

标签: sql tsql


【解决方案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,感谢您的评论。我将在下一次编辑中添加完整的解释。
          猜你喜欢
          • 1970-01-01
          • 2022-12-20
          • 2015-02-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-22
          • 1970-01-01
          • 2022-07-14
          相关资源
          最近更新 更多