20 mysql postgresql count group-by
我玩了一场篮球比赛,它允许将其统计数据输出为数据库文件,因此可以从中计算出游戏中未实现的统计数据。到目前为止,我在计算我想要的统计数据时没有遇到任何问题,但现在我遇到了一个问题:从他的比赛统计数据中计算一个球员在整个赛季中取得的双打和/或三双的数量。
双双和三双的定义如下:
双双:
两双是指球员在一场比赛中在五个统计类别中的两个类别(得分、篮板、助攻、抢断和盖帽)中累积达到两位数的总和的表现。
三双:
三双被定义为球员在一场比赛中在五个统计类别中的三个——得分、篮板、助攻、抢断和盖帽——中累计达到两位数的表现。
四双(添加澄清)
四双被定义为球员在一场比赛中在五个统计类别中的四个类别(得分、篮板、助攻、抢断和盖帽)中累计达到两位数的表现。
“PlayerGameStats”表存储玩家玩的每个游戏的统计数据,如下所示:
CREATE TABLE PlayerGameStats AS SELECT * FROM ( VALUES
( 1, 1, 1, 'Nuggets', 'Cavaliers', 6, 8, 2, 2, 0 ),
( 2, 1, 2, 'Nuggets', 'Clippers', 15, 7, 0, 1, 3 ),
( 3, 1, 6, 'Nuggets', 'Trailblazers', 11, 11, 1, 2, 1 ),
( 4, 1, 10, 'Nuggets', 'Mavericks', 8, 10, 2, 2, 12 ),
( 5, 1, 11, 'Nuggets', 'Knicks', 23, 12, 1, 0, 0 ),
( 6, 1, 12, 'Nuggets', 'Jazz', 8, 8, 11, 1, 0 ),
( 7, 1, 13, 'Nuggets', 'Suns', 7, 11, 2, 2, 1 ),
( 8, 1, 14, 'Nuggets', 'Kings', 10, 15, 0, 3, 1 ),
( 9, 1, 15, 'Nuggets', 'Kings', 9, 7, 5, 0, 4 ),
(10, 1, 17, 'Nuggets', 'Thunder', 13, 10, 10, 1, 0 )
) AS t(id,player_id,seasonday,team,opponent,points,rebounds,assists,steals,blocks);
Run Code Online (Sandbox Code Playgroud)
我想要实现的输出如下所示:
| player_id | team | doubleDoubles | tripleDoubles |
|-----------|---------|---------------|---------------|
| 1 | Nuggets | 4 | 1 |
Run Code Online (Sandbox Code Playgroud)
到目前为止,我发现的唯一解决方案太糟糕了,它让我呕吐......;o)......看起来像这样:
SELECT
player_id,
team,
SUM(CASE WHEN(points >= 10 AND rebounds >= 10) OR
(points >= 10 AND assists >= 10) OR
(points >= 10 AND steals >= 10)
THEN 1
ELSE 0
END) AS doubleDoubles
FROM PlayerGameStats
GROUP BY player_id
Run Code Online (Sandbox Code Playgroud)
……现在您在阅读本文后可能也会呕吐(或大笑)。我什至没有写出获得所有双双组合所需的一切,并且省略了三双的 case 语句,因为它更荒谬。
有一个更好的方法吗?使用我拥有的表结构或新的表结构(我可以编写一个脚本来转换表)。
我可以使用 MySQL 5.5 或 PostgreSQL 9.2。
这是 SqlFiddle 的链接,其中包含示例数据和我在上面发布的糟糕解决方案:http ://sqlfiddle.com/#!2/af6101/3
请注意,我对四双(见上文)并不真正感兴趣,因为据我所知,它们不会出现在我玩的游戏中,但如果查询很容易扩展而无需大量重写帐户,那将是一个加分对于四双。
小智 9
不知道这是不是最好的方法。我首先做了一个选择,以确定一个统计数据是否为两位数,如果是,则为其分配一个 1。将所有这些加起来以找出每场比赛的两位数总数。从那里总结所有的双打和三打。似乎工作
select a.player_id,
a.team,
sum(case when a.doubles = 2 then 1 else 0 end) as doubleDoubles,
sum(case when a.doubles = 3 then 1 else 0 end) as tripleDoubles
from
(select *,
(case when points > 9 then 1 else 0 end) +
(case when rebounds > 9 then 1 else 0 end) +
(case when assists > 9 then 1 else 0 end) +
(case when steals > 9 then 1 else 0 end) +
(case when blocks > 9 then 1 else 0 end) as Doubles
from PlayerGameStats) a
group by a.player_id, a.team
Run Code Online (Sandbox Code Playgroud)
试试这个(在 MySQL 5.5 上对我有用):
SELECT
player_id,
team,
SUM(
( (points >= 10)
+ (rebounds >= 10)
+ (assists >= 10)
+ (steals >= 10)
+ (blocks >= 10)
) = 2
) double_doubles,
SUM(
( (points >= 10)
+ (rebounds >= 10)
+ (assists >= 10)
+ (steals >= 10)
+ (blocks >= 10)
) = 3
) triple_doubles
FROM PlayerGameStats
GROUP BY player_id, team
Run Code Online (Sandbox Code Playgroud)
或者更短,从他的答案中公然撕掉 JChao 的代码,但是去掉不需要的CASE
语句,因为当 {True,False} 时 boolean expr 计算为 {1,0}:
select a.player_id,
a.team,
sum(a.doubles = 2) as doubleDoubles,
sum(a.doubles = 3) as tripleDoubles
from
(select *,
(points > 9) +
(rebounds > 9) +
(assists > 9) +
(steals > 9) +
(blocks > 9) as Doubles
from PlayerGameStats) a
group by a.player_id, a.team
Run Code Online (Sandbox Code Playgroud)
基于上面的代码不会在 PostgreSQL 中运行的评论,因为不喜欢做 boolean + boolean。我还是不喜欢CASE
。这是 PostgreSQL (9.3) 的出路,通过强制转换为int
:
select a.player_id,
a.team,
sum((a.doubles = 2)::int) as doubleDoubles,
sum((a.doubles = 3)::int) as tripleDoubles
from
(select *,
(points > 9)::int +
(rebounds > 9)::int +
(assists > 9)::int +
(steals > 9)::int +
(blocks > 9)::int as Doubles
from PlayerGameStats) a
group by a.player_id, a.team
Run Code Online (Sandbox Code Playgroud)
这是对这个问题的另一种看法。
我的想法是,您实际上是在处理当前问题的透视数据,因此首先要做的是取消透视它。不幸的是 PostgreSQL 没有提供很好的工具来做到这一点,所以无需进入 PL/PgSQL 中的动态 SQL 生成,我们至少可以这样做:
SELECT player_id, seasonday, 'points' AS scoretype, points AS score FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'rebounds' AS scoretype, rebounds FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'assists' AS scoretype, assists FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'steals' AS scoretype, steals FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'blocks' AS scoretype, blocks FROM playergamestats
Run Code Online (Sandbox Code Playgroud)
这使数据具有更具延展性的形式,尽管它肯定不漂亮。这里我假设 (player_id, seasonday) 足以唯一标识球员,即球员 ID 在团队中是唯一的。如果不是,您需要包含足够的其他信息以提供唯一密钥。
有了这些未经透视的数据,现在可以以有用的方式对其进行过滤和聚合,例如:
SELECT
player_id,
count(CASE WHEN doubles = 2 THEN 1 END) AS doubledoubles,
count(CASE WHEN doubles = 3 THEN 1 END) AS tripledoubles
FROM (
SELECT
player_id, seasonday, count(*) AS doubles
FROM
(
SELECT player_id, seasonday, 'points' AS scoretype, points AS score FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'rebounds' AS scoretype, rebounds FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'assists' AS scoretype, assists FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'steals' AS scoretype, steals FROM playergamestats
UNION ALL
SELECT player_id, seasonday, 'blocks' AS scoretype, blocks FROM playergamestats
) stats
WHERE score >= 10
GROUP BY player_id, seasonday
) doublestats
GROUP BY player_id;
Run Code Online (Sandbox Code Playgroud)
这远非漂亮,而且可能没有那么快。不过,它是可维护的,只需进行最少的更改即可处理新类型的统计信息、新列等。
所以这更像是一个“嘿,你想到了吗”而不是一个严肃的建议。目标是建模 SQL 以尽可能直接地对应问题陈述,而不是使其快速。
通过在面向 MySQL 的 SQL 中使用合理的多值插入和 ANSI 引用,这变得更加容易。谢谢; 很高兴一次没有看到反引号。我只需要更改合成密钥生成。
什么@Joshua显示为MySQL,Postgres里的工作为好。Boolean
值可以强制转换integer
和累加。不过,演员阵容需要明确。使代码非常短:
SELECT player_id, team
, count(doubles = 2 OR NULL) AS doubledoubles
, count(doubles = 3 OR NULL) AS tripledoubles
FROM (
SELECT player_id, team,
(points > 9)::int +
(rebounds > 9)::int +
(assists > 9)::int +
(steals > 9)::int +
(blocks > 9)::int AS doubles
FROM playergamestats
) a
GROUP BY 1, 2;
Run Code Online (Sandbox Code Playgroud)
SELECT
. 但是,CASE
即使更冗长,通常也快一点。更便携,如果这很重要:
SELECT player_id, team
, count(doubles = 2 OR NULL) AS doubledoubles
, count(doubles = 3 OR NULL) AS tripledoubles
FROM (
SELECT player_id, team,
CASE WHEN points > 9 THEN 1 ELSE 0 END +
CASE WHEN rebounds > 9 THEN 1 ELSE 0 END +
CASE WHEN assists > 9 THEN 1 ELSE 0 END +
CASE WHEN steals > 9 THEN 1 ELSE 0 END +
CASE WHEN blocks > 9 THEN 1 ELSE 0 END AS doubles
FROM playergamestats
) a
GROUP BY 1, 2;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4642 次 |
最近记录: |