当左表没有按列分组时,左连接

时间:2017-03-20 12:54:18

标签: sql hive

我发现准确地说出这个问题有点困难。

所以,为了简化:我有两个表,称之为event_typeplayer_events。第一个表是事件类型(字符串)列表,调用列event_type.name

player_events是各个玩家事件的列表。某些玩家可能会丢失某些事件,并且同一玩家可能会多次发生事件。因此,player_events具有相关列player_events.player_idplayer_events.event_type_name,以及处理创建时间等的其他列,但后者无关紧要。

我想要一个玩家事件类型计数,包括零。我需要区分每个玩家的不同事件类型。所以最后我应该得到这样的东西:

player_id event_type_name player_event_count 0 LoginEvent 1 0 ProfileChangedEvent 0 1 LoginEvent 5 1 ProfileChangedEvent 1 ...

我在考虑将event_type表格加入player_events表并以某种方式对player_events.player_idplayer_events.event_type_name进行分组,但我无法将其转到工作

类似于此的东西错过了零:

select player_id, event_type_name, count(event_type_name) as player_event_count from player_events group by player_id, event_type_name

这样的事情怎么做得最好?

2 个答案:

答案 0 :(得分:0)

如果您有一个PLAYER表(PLAYER_EVENT_TYPES的父级,其中PLAYER_ID是主键),那么这样做的好方法是:

select p.player_id, et.event_type_name, count(*) as player_event_count
from event_type et 
     cross join players p 
     left join player_events pe on pe.player_id = p.player_id and pe.event_type_name = et.event_type_name
group by p.player_id, et.event_type_name;

更新基于现有的PLAYER表...

由于您没有PLAYER表,您可以这样做,而不是:

SELECT pe.player_id,
       et.event_type_name,
       COUNT (CASE WHEN pe.event_type_name = et.event_type_name THEN 1 ELSE NULL END) cnt
FROM   player_events pe CROSS JOIN event_types et
GROUP BY pe.player_id, et.event_type_name
ORDER BY pe.player_id, et.event_type_name

(对不起,我不知道“HIVE”你必须在该数据库中使用等效的CASE。)

我更喜欢拥有PLAYER表,因为这对我来说不太清楚。

答案 1 :(得分:0)

我实际上更喜欢九十年代早期可能的风格 - 在CASE WHEN条款可用之前:

这里的诀窍是在一个(临时)表中获取所有可能的player_id - s,在另一个表中获取所有event_type_name - s,并将CROSS JOIN连接在一起,最后LEFT JOIN到player_events表。然后计算来自event_type_name表的player_events - s。 event_type_name的NULL出现只是不计算。

如果您可以依赖player_id中所有event_type_name - 和所有player_events - s的事实,那么您可以这样做:

WITH
-- input data for player_events, don't use in query
player_events(player_id,tm,event_type_name) AS (
          SELECT 0,TIME '00:01:01','LoginEvent'
UNION ALL SELECT 1,TIME '00:01:12','LoginEvent'
UNION ALL SELECT 1,TIME '00:01:12','LoginEvent'
UNION ALL SELECT 1,TIME '00:01:12','LoginEvent'
UNION ALL SELECT 1,TIME '00:01:12','LoginEvent'
UNION ALL SELECT 1,TIME '00:01:12','LoginEvent'
UNION ALL SELECT 1,TIME '00:01:12','ProfileChangedEvent'
)
-- real query starts here - replace the comma below with WITH
,
-- all distinct player_id-s from player_events
players AS (
SELECT DISTINCT player_id FROM player_events
)
,
-- all distinct event_type_name-s from player_events
all_event_types AS (
SELECT DISTINCT event_type_name FROM player_events
)
SELECT
  p.player_id
, a.event_type_name
, COUNT(e.event_type_name) AS player_event_count
FROM players         p
CROSS JOIN all_event_types a
LEFT JOIN player_events   e USING(player_id,event_type_name)
GROUP BY
  p.player_id
, a.event_type_name
ORDER BY
  p.player_id
;

如果有player_id - s或event_type_name - s在player_events表中没有任何条目,则必须为player_id创建一个SELECT - s和event_type_name - 保证返回所有可能的事件,并替换我使用的那些SELECT DISTINCT。

祝你好运 -