【问题标题】:How to count number of different items in SQL如何计算SQL中不同项目的数量
【发布时间】:2009-01-22 21:56:17
【问题描述】:

数据库结构:

Clubs: ID, ClubName
Teams: ID, TeamName, ClubID
Players: ID, Name
Registrations: PlayerID, TeamID, Start_date, End_date, SeasonID

俱乐部拥有几支球队。球员可能会在一年内注册到几支球队(同一俱乐部内或不同俱乐部)。 我必须生成一个查询来列出在一个赛季中注册到不同俱乐部的所有球员。因此,如果球员交换了属于同一俱乐部的球队,则不算数。

到目前为止我的尝试:

SELECT
c.short_name,
p.surname,
r.start_date,
r.end_date,
(select count(r2.id) from ejl_registration as r2
    where r2.player_id=r.player_id and r2.season=r.season) as counter
FROM
ejl_registration AS r
left Join ejl_players AS p ON p.id = r.player_id
left Join ejl_teams AS t ON r.team_id = t.id
left Join ejl_clubs AS c ON t.club_id = c.id
WHERE
r.season =  '2008'
having counter >1

我不知道如何计算和只显示不同的俱乐部......(现在想清楚已经太迟了)。我使用 MySQL。

报告应该是这样的:球员姓名、俱乐部名称、开始日期、结束日期

【问题讨论】:

    标签: sql


    【解决方案1】:

    这是对这个答案的第二次尝试,将其简化为仅计算不同的俱乐部,而不是报告俱乐部名称的列表。

    SELECT p.surname, r.start_date, r.end_date, COUNT(DISTINCT c.id) AS counter
    FROM ejl_players p
     JOIN ejl_registration r ON (r.player_id = p.id)
     JOIN ejl_teams t ON (r.team_id = t.id)
     JOIN ejl_clubs c ON (t.club_id = c.id)
    WHERE r.season = '2008'
    GROUP BY p.id
    HAVING counter > 1;
    

    请注意,由于您使用的是 MySQL,因此对于选择列表中的列与 GROUP BY 子句中的列不匹配,您可以非常灵活。其他品牌的 RDBMS 对单值规则更为严格。

    没有理由像您的示例中那样使用 LEFT JOIN。


    好的,这是查询的第一个版本:

    您有如下关系链:

    club1 <-- team1 <-- reg1 --> player <-- reg2 --> team2 --> club2
    

    这样 club1 不能与 club2 相同。

    SELECT p.surname,
      CONCAT_WS(',', GROUP_CONCAT(DISTINCT t1.team_name), 
        GROUP_CONCAT(DISTINCT t2.team_name)) AS teams,
      CONCAT_WS(',', GROUP_CONCAT(DISTINCT c1.short_name), 
        GROUP_CONCAT(DISTINCT c2.short_name)) AS clubs
    FROM ejl_players p
     -- Find a club where this player is registered
     JOIN ejl_registration r1 ON (r1.player_id = p.id)
     JOIN ejl_teams t1 ON (r1.team_id = t1.id)
     JOIN ejl_clubs c1 ON (t1.club_id = c1.id)
     -- Now find another club where this player is registered in the same season
     JOIN ejl_registration r2 ON (r2.player_id = p.id AND r1.season = r2.season)
     JOIN ejl_teams t2 ON (r2.team_id = t2.id)
     JOIN ejl_clubs c2 ON (t2.club_id = c2.id)
    -- But the two clubs must not be the same (use < to prevent duplicates)
    WHERE c1.id < c2.id
    GROUP BY p.id;
    

    【讨论】:

    • 很有趣 - 但它回答了一个相当复杂的问题:列出在一个赛季中在两个或更多俱乐部注册的球员,并包括每个此类球员的俱乐部和球队详细信息以及每个此类不同的球员一对球杆。
    • 您不必简化它 - 需要俱乐部名称列表。
    • 我已经恢复了第一个答案并粘贴在上面。
    • 谢谢!很遗憾,我只能给你 +1。
    • 似乎此查询仅适用于 2 个俱乐部。当用户在 Club1(team1)->Club1(team2)->Club2(team3) 中跳跃时,我会列出 4 个名称:Club1、Club1、Club2、Club2。当他跳 Club1->Club2->Club3 时,重复的结果会变得更长
    【解决方案2】:

    这是一个赛季的球员名单。

    SELECT sub.PlayerId
    FROM
    (
      SELECT
        r.PlayerId,
        (SELECT t.ClubID FROM Teams t WHERE r.TeamID = t.ID) as ClubID
      FROM Registrations r
      WHERE r.Season = '2008'
    ) as sub
    GROUP BY PlayerId
    HAVING COUNT(DISTINCT sub.ClubID) > 1
    

    这是所有赛季的球员和赛季列表。

    SELECT PlayerId, Season
    FROM
    (
    SELECT
      r.PlayerId,
      r.Season,
      (SELECT t.ClubID FROM Teams t WHERE r.TeamID = t.ID) as ClubID
    FROM Registrations r
    ) as sub
    GROUP BY PlayerId, Season
    HAVING COUNT(DISTINCT sub.ClubID) > 1
    

    顺便说一句,这在 MS SQL 中有效。

    【讨论】:

    • 'AS sub'表表达式中的相关子选择有点笨拙;为什么不使用联接?
    • 婚前加入是违反我的宗教信仰的。它可以作为一个加入,因为没有一个团队有超过 1 个俱乐部......另外 - MS Sql 不在乎你用哪种方式表达这个,它会在执行计划中显示左加入。
    【解决方案3】:
    SELECT p.Name, x.PlayerID, x.SeasonID
      FROM (SELECT DISTINCT r.PlayerID, r.SeasonID, t.ClubID
              FROM Registrations r
              JOIN Teams t ON t.ID = r.TeamID) x
      JOIN Players p ON p.ID = x.PlayerID
     GROUP BY p.rName, x.PlayerID, x.SeasonID
    HAVING COUNT(*) > 1
    

    【讨论】:

    • 这只是列出了球员。甚至我的查询也这样做了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-19
    • 1970-01-01
    • 2020-07-19
    • 2018-08-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多