4

我有一个包含这些列的表:

  • ID
  • 用户身份
  • player_in
  • player_out
  • 日期

我需要制作一份报告,计算每个“玩家”在 player_in 字段中的重复次数,如在 player_out 字段中。例如,如果我在表中有这 2 行(按相应的顺序)。

id user_id player_in player_out
1  1       88        56
2  7       77        88

玩家 88 的结果将是 2,而玩家 56 和 77 的结果将是 1

4

2 回答 2

3

Use a subquery that employs union all to get the two column into one column, then use a standard count(*):

Note: Thus query included individual totals for ins and outs as per further request in comments to this answer.

select
  player_id,
  count(*) as total,
  sum(ins) as ins,
  sum(outs) as outs
from (
  select
    player_in as player_id,
    1 as ins,
    0 as outs
  from mytable
  union all
  select player_out, 0, 1
  from mytable
) x
group by player_id

Note: you must use union all (not just union), because union removes duplicates whereas union all does not.

于 2013-07-07T14:48:32.057 回答
2

您可以使用交叉连接到 2 行虚拟表来取消透视player_*列,然后对结果进行分组,如下所示:

SELECT
  player,
  COUNT(*) AS total_count
FROM (
  SELECT
    CASE WHEN x.is_in THEN t.player_in ELSE t.player_out END AS player
  FROM mytable t
  CROSS JOIN (SELECT TRUE AS is_in UNION ALL SELECT FALSE) x
) s
GROUP BY
  player
;

也就是说,原始表的每一行本质上都是重复的,并且行的每个副本都提供player_inplayer_out,这取决于派生表的is_in列是TRUE还是FALSE,以形成单个player列。这种反透视方法可能比@Bohemian 建议的 UNION 方法执行得更好,因为这种方式(物理)表只传递一次(但您需要测试和比较这两种方法以确定这种方法是否有任何实质性好处你的具体情况)。

要计算进出计数,正如您在对上述答案的评论之一中所要求的那样,您可以像这样扩展我原来的建议:

SELECT
  player,
  COUNT(    is_in OR NULL) AS in_count,
  COUNT(NOT is_in OR NULL) AS out_count,
  COUNT(*)                 AS total_count
FROM (
  SELECT
    x.is_in,
    CASE WHEN x.is_in THEN t.player_in ELSE t.player_out END AS player
  FROM mytable t
  CROSS JOIN (SELECT TRUE AS is_in UNION ALL SELECT FALSE) x
) s
GROUP BY
  player
;

如您所见,派生表现is_in在还单独返回列,并且该列用于两个条件聚合中,用于计算玩家进出的次数。(如果你有兴趣,OR NULL技巧在这里解释。)

您也可以将条目重写为. 这肯定会缩短这两种表达方式,有些人还发现计数方法更清晰/更优雅。无论哪种情况,性能都可能没有差异,因此请选择更适合您口味的方法。COUNT(condition OR NULL)SUM(condition)SUM

可以在此处找到第二个查询的 SQL Fiddle 演示。

于 2013-07-10T00:21:59.523 回答