簡體   English   中英

當左表沒有所有按列分組時的左聯接

[英]Left join when left table does not have all group by columns

我發現很難用精確的措詞來表達這個問題。

因此,為簡化起見:我有兩個表,將它們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上分組,但是我無法player_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

最好的事情是如何做到的?

如果您有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桌子,因為(對我而言)這還不清楚。

實際上,我更喜歡90年代早期的樣式-在CASE WHEN子句可用之前:

這里的技巧是在一個(臨時)表中獲取所有可能的player_id -s,在另一個表中獲取所有event_type_name -s,並將CROSS JOIN一起使用,最后將LEFT JOIN player_eventsplayer_events表中。 然后計算來自player_events表的event_type_name -s。 event_type_name的NULL出現根本不算在內。

如果您可以依賴於event_type_name中存在所有player_id -s和所有event_type_name -s的player_events ,請執行以下操作:

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_events表中沒有任何條目的player_id -s或event_type_name -s,則必須為player_id -s和event_type_name -s創建一個SELECT,確保它們返回所有可能的出現,並替換SELECT DISTINCT -s我用那些。

祝好運 -

馬爾科

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM