关于sql:Mysql count id 出现在2列

Mysql count id that appear in 2 columns

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

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

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

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

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


使用使用 union all 的子查询将两列合并为一列,然后使用标准 count(*):

注意:因此,根据对此答案的评论中的进一步要求,查询包括进出的个人总数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

注意:您必须使用 union all(而不仅仅是 union),因为 union 会删除重复项,而 union all 不会。


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

1
2
3
4
5
6
7
8
9
10
11
12
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 方法执行得更好,因为这种方式(物理)表只传递一次(但您需要测试和比较这两种方法以确定这种方法是否有任何实质性好处您的具体情况)。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 演示。