我有一个包含这些列的表:
- 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
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.
您可以使用交叉连接到 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_in
或player_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 演示。