来自多个列的MySQL COUNT次出现

时间:2018-06-14 22:26:25

标签: mysql

我有一张名为games的4人游戏的下表。

+---------+---------+---------+---------+---------+
| game_id | player1 | player2 | player3 | player4 |
+---------+---------+---------+---------+---------+
|    1001 | john    | dave    | NULL    | NULL    |
|    1002 | dave    | john    | mike    | tim     |
|    1003 | mike    | john    | dave    | NULL    |
|    1004 | tim     | dave    | NULL    | NULL    |
+---------+---------+---------+---------+---------+

我希望能够回答两个问题:

  1. 谁参加了大多数比赛? (戴维)
  2. 哪一对队员一起玩过最多的比赛? (John& Dave)
  3. 对于#1我尝试调整我在这里找到的答案:mySQL query to find the most repeated value但它似乎只能回答单个列的问题。这意味着我可以了解谁是player1最多的人,但不是任何玩家在大多数游戏中玩过的人:

    SELECT player1 p1, COUNT(*) p1 FROM games
    GROUP BY p1    
    ORDER BY p1 DESC;
    

    有没有办法将这些列连接在一起,还是我必须在应用程序代码中处理它?<​​/ p>

    不知道从哪里开始#2。我想知道我的桌面结构是否应该将玩家整合到一个列中:

    +----+---------+--------+
    | id | game_id | player |
    +----+---------+--------+
    |  1 |    1001 | john   |
    |  2 |    1001 | dave   |
    |  3 |    1002 | john   |
    |  4 |    1002 | dave   |
    |  5 |    1002 | mike   |
    |  6 |    1002 | tim    |
    +----+---------+--------+
    

2 个答案:

答案 0 :(得分:4)

您最好的选择是规范化数据库。这是一个多对多关系,需要一个链接表来将游戏连接到相应的玩家。然后计算会更容易。尽管如此,您可以将派生表用于问题一,将所有列合并为一个:

SELECT `player`,
       COUNT(*) as `count`
FROM
    (
        SELECT `player1` `player`
        FROM `games`
        UNION ALL
        SELECT `player2` `player`
        FROM `games`
        UNION ALL
        SELECT `player3` `player`
        FROM `games`
        UNION ALL
        SELECT `player4` `player`
        FROM `games`
    ) p
GROUP BY `player` HAVING `player` IS NOT NULL
ORDER BY `count` DESC

请参阅live demo here

对于第二个问题,您必须在派生表上进行内部联接:

SELECT `p`.`player`,
       `p2`.`player`,
       count(*) AS count
FROM
    (
        SELECT `game_id`, `player1` `player`
        FROM `games`
        UNION ALL
        SELECT `game_id`, `player2` `player`
        FROM `games`
        UNION ALL
        SELECT `game_id`, `player3` `player`
        FROM `games`
        UNION ALL
        SELECT `game_id`, `player4` `player`
        FROM `games`
    ) p
INNER JOIN
    (
        SELECT `game_id`, `player1` `player`
        FROM `games`
        UNION ALL
        SELECT `game_id`, `player2` `player`
        FROM `games`
        UNION ALL
        SELECT `game_id`, `player3` `player`
        FROM `games`
        UNION ALL
        SELECT `game_id`, `player4` `player`
        FROM `games`
    ) p2
ON `p`.`game_id` = `p2`.`game_id` AND `p`.`player` < `p2`.`player`
WHERE `p`.`player` IS NOT NULL AND `p2`.`player` IS NOT NULL
GROUP BY `p`.`player`, `p2`.`player`
ORDER BY `count` DESC

请参阅live demo here

答案 1 :(得分:2)

我将从重组您的设计开始并介绍3个表

1)玩家 这将有玩家数据和他们独特的ID

CREATE TABLE players
    (`id` int, `name` varchar(255))
;
INSERT INTO players
    (`id`,  `name`)
VALUES
    (1, 'john'),
    (2, 'dave'),
    (3, 'mike'),
    (4, 'tim');

2)将拥有游戏数据及其独特ID的游戏

CREATE TABLE games
    (`id` int, `name` varchar(25))
;

INSERT INTO games
    (`id`, `name`)
VALUES
    (1001, 'G1'),
    (1002, 'G2'),
    (1003, 'G3'),
    (1004, 'G4');

3)player_games通过联结表将这两个实体关联成多对多关系,这将根据您的样本数据保存游戏ID和玩家ID

CREATE TABLE player_games
    (`game_id` int, `player_id` int(11))
;

INSERT INTO player_games
    (`game_id`, `player_id`)
VALUES
    (1001, 1),
    (1001, 2),
    (1002, 1),
    (1002, 2),
    (1002, 3),
    (1002, 4),
    (1003, 3),
    (1003, 1),
    (1003, 2),
    (1004, 4),
    (1004, 2)
;

对于谁玩过大多数游戏?根据您玩4场比赛的样本数据,它的dave不是john

select t.games_played,group_concat(t.name) players
from (
  select p.name,
  count(distinct pg.game_id) games_played
  from player_games pg
  join players p on p.id = pg.player_id
  group by p.name 
) t
group by games_played
order by games_played desc
limit 1

对于上述查询,可能有超过一个玩家玩过大多数游戏的机会,比如dave玩了4场比赛,蒂姆也打了4场比赛,所以两者都应该被包括在内

Demo

对于哪一对队员一起比赛最多? (约翰和戴夫)

select t.games_played,group_concat(t.player_name) players
from (
  select group_concat(distinct pg.game_id),
  concat(least(p.name, p1.name), ' ', greatest(p.name, p1.name)) player_name,
  count(distinct pg.game_id) games_played
  from player_games pg
  join player_games pg1 on pg.game_id = pg1.game_id
                       and pg.player_id <> pg1.player_id
  join players p on p.id = pg.player_id
  join players p1 on p1.id = pg1.player_id
  group by player_name
) t
group by games_played
order by games_played desc
limit 1;

在上面的查询中,我有自己加入的player_games表,以获得每个游戏的玩家组合,然后为每个唯一的对分组数据,再次遵循相同的逻辑,汉德尔可能有超过一对玩家玩过的机会大多数游戏

Demo