MySQL - 如何分组更多列和SUM()每个组?

时间:2013-08-14 17:53:40

标签: mysql join group-by sum multiple-columns

目前我的查询如下:

SELECT alias.name killer,
       SUM(kill_stats.amount) amount
FROM kill_stats
        JOIN pickup ON pickup.logfile = 'CTFCL-20130813-1456-shutdown2'
        JOIN account ON account.steam_id = '0:1:705272'
        JOIN player victim ON victim.pickup_id = pickup.id AND victim.account_id = account.id
        JOIN player killer ON killer.pickup_id = pickup.id AND kill_stats.killer_id = killer.id
        JOIN alias ON killer.alias_id = alias.id
WHERE kill_stats.victim_id = victim.id AND NOT killer.team_id = victim.team_id
GROUP BY kill_stats.killer_id
ORDER BY amount DESC

kill_stats表格布局:

CREATE TABLE `kill_stats` (
  `killer_id` int(11) UNSIGNED NOT NULL,
  `victim_id` int(11) UNSIGNED NOT NULL,
  `weapon_id` int(11) UNSIGNED NOT NULL,
  `conced` bit(1) NOT NULL,
  `fc` bit(1) NOT NULL,
  `amount` int(11) UNSIGNED NOT NULL,
  PRIMARY KEY(`killer_id`, `victim_id`, `weapon_id`, `conced`, `fc`),
  CONSTRAINT `Ref_Killer` FOREIGN KEY (`killer_id`)
    REFERENCES `player`(`id`)
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  CONSTRAINT `Ref_Victim` FOREIGN KEY (`victim_id`)
    REFERENCES `player`(`id`)
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  CONSTRAINT `Ref_Weapon` FOREIGN KEY (`weapon_id`)
    REFERENCES `weapon`(`id`)
    ON DELETE CASCADE
    ON UPDATE CASCADE
)
ENGINE=INNODB
CHARACTER SET utf8 
COLLATE utf8_unicode_ci ;

这是一个更可读的视图,用虚拟数据替换外键:

+-----------+-----------+-----------+--------+----+--------+
| killer_id | victim_id | weapon_id | conced | fc | amount |
+-----------+-----------+-----------+--------+----+--------+
| Josephine |   Frank   |    RPG    |   NO   | NO |   14   |
+-----------+-----------+-----------+--------+----+--------+
| Josephine |   Frank   |  Shotgun  |   YES  | NO |   5    |
+-----------+-----------+-----------+--------+----+--------+
| Josephine |   Frank   |  Shotgun  |   NO   | NO |   3    |
+-----------+-----------+-----------+--------+----+--------+
| Miguel    |   Frank   |   Knife   |   NO   | NO |   1    |
+-----------+-----------+-----------+--------+----+--------+

使用此示例表,上面的查询将返回如下表:

+-----------+--------+
|  killer   | amount |
+-----------+--------+
| Josephine |   22   |
+-----------+--------+
|  Miguel   |   1    |
+-----------+--------+

我希望输出的是:

+-----------+-------------+--------------+-----------------+
|  killer   | total_kills | conced_kills | victim_had_flag |
+-----------+-------------+--------------+-----------------+
| Josephine |      22     |      5       |        0        |
+-----------+-------------+--------------+-----------------+
|  Miguel   |      1      |      0       |        0        |
+-----------+-------------+--------------+-----------------+

显示某位玩家被其他玩家杀死的频率,他们杀死他的总次数,被杀的数量以及玩家被他们杀死时旗帜的持续时间。

我不确定如何实现这一目标,我尝试了GROUP BY kill_stats.killer_id, kill_stats.conced,但结果是:

+-----------+--------+
|   killer  | amount |
+-----------+--------+
| Josephine |   14   |  -> the ones with kill_stats.conced = NO
+-----------+--------+
| Josephine |   5    |  -> the ones with kill_stats.conced = YES
+-----------+--------+
| Miguel    |   1    |  -> the ones with kill_stats.conced = NO (only row for that `killer_id`)
+-----------+--------+

我为killer_id获取了多行,并且我希望每个killer_id一行行包含所有数据。

Ike Walker 的解决方案几乎就是我一直在寻找的,最终的查询让它按照我想要的方式工作:

SELECT alias.name killer,
       SUM(kill_stats.amount) as total_kills ,
       SUM(CASE WHEN kill_stats.conced then kill_stats.amount ELSE 0 END) as conced_kills ,
       SUM(CASE WHEN kill_stats.fc then kill_stats.amount ELSE 0 END) as victim_had_flag 
    FROM kill_stats
        JOIN pickup ON pickup.logfile = 'CTFCL-20130813-1456-shutdown2'
        JOIN account ON account.steam_id = '0:1:705272'
        JOIN player victim ON victim.pickup_id = pickup.id AND victim.account_id = account.id
        JOIN player killer ON killer.pickup_id = pickup.id AND kill_stats.killer_id = killer.id
        JOIN alias ON killer.alias_id = alias.id
WHERE kill_stats.victim_id = victim.id AND NOT killer.team_id = victim.team_id
GROUP BY kill_stats.killer_id
ORDER BY amount DESC

最终让我走上正轨的他的解决方案的不同之处在于,我总是需要将SUM() kill_stats.amount 添加到新列conced_kills中将BIT(1)列设置为1。

2 个答案:

答案 0 :(得分:1)

执行此操作的标准方法是将SUM()CASE合并为您的辅助计数。

以下是您通过这种方式重写的示例查询,以便为您提供所需的输出:

SELECT alias.name killer,
       SUM(kill_stats.amount) as total_kills ,
       SUM(CASE WHEN kill_stats.conced then 1 ELSE 0 END) as conced_kills ,
       SUM(CASE WHEN kill_stats.fc then 1 ELSE 0 END) as victim_had_flag 
FROM kill_stats
        JOIN pickup ON pickup.logfile = 'CTFCL-20130813-1456-shutdown2'
        JOIN account ON account.steam_id = '0:1:705272'
        JOIN player victim ON victim.pickup_id = pickup.id AND victim.account_id = account.id
        JOIN player killer ON killer.pickup_id = pickup.id AND kill_stats.killer_id = killer.id
        JOIN alias ON killer.alias_id = alias.id
WHERE kill_stats.victim_id = victim.id AND NOT killer.team_id = victim.team_id
GROUP BY kill_stats.killer_id
ORDER BY amount DESC

答案 1 :(得分:0)

尝试将查询的SELECT列表更改为:

SELECT alias.name killer,
   SUM(kill_stats.amount) amount,
   SUM(kill_stats.conced) conced_kills,
   SUM(kill_stats.fc) victim_had_flag

...然后选择FROM kill_stats并完成发布时的完成。我假设conced如果为真则为1,如果为假则为0;与fc相同。我还假设fc表示“受害者有旗帜”。