【问题标题】:Joining to the same table with different filters使用不同的过滤器加入同一个表
【发布时间】:2021-09-22 03:13:51
【问题描述】:

我正在尝试为每个id 计算用户下载的不同app 的数量,并按类别对计数进行分组。单独查询的示例如下:

SELECT id
,COUNT(DISTINCT app) AS gaming_apps
FROM apps_table 
WHERE app IN ('Clash of Clans', 'Valorant', 'PUBG') 
GROUP BY id 

SELECT id 
,COUNT(DISTINCT app) AS msg_apps
FROM apps_table 
WHERE app IN ('Telegram', 'WhatsApp', 'Signal', 'FBMessenger') 
GROUP BY id 

SELECT id 
,COUNT(DISTINCT app) AS fin_apps
FROM apps_table 
WHERE app IN ('Yahoo Finance', 'Robinhood') 
GROUP BY id 

理想情况下,我想返回一个包含idgaming_appsmsg_appsfin_apps 列的表。我想到了LEFT JOIN 3 个查询,但我不确定如何,并且将每个查询包装为子查询太笨拙了。

我也试过这个,但无济于事,因为每次下载或应用更新都会插入一个新行:

SELECT id
,COUNT(CASE WHEN app IN ('Clash of Clans', 'Valorant', 'PUBG') THEN 1 ELSE NULL END) AS gaming_apps
,COUNT(CASE WHEN app IN ('Telegram', 'WhatsApp', 'Signal', 'FBMessenger')  THEN 1 ELSE NULL END) AS msg_apps
,COUNT(CASE WHEN app IN ('Yahoo Finance', 'Robinhood') THEN 1 ELSE NULL END) AS fin_apps 
FROM apps_table 
GROUP BY id 

【问题讨论】:

  • 签出 COUNT_IF

标签: sql hive cloudera


【解决方案1】:

如果您想要不同的计数,请使用count(distinct)

SELECT id,
       COUNT(DISTINCT CASE WHEN app IN ('Clash of Clans', 'Valorant', 'PUBG') THEN app END) AS gaming_apps,
       COUNT(DISTINCT CASE WHEN app IN ('Telegram', 'WhatsApp', 'Signal', 'FBMessenger') THEN app END) AS msg_apps,
       COUNT(DISTINCT CASE WHEN app IN ('Yahoo Finance', 'Robinhood') THEN app END) AS fin_apps 
FROM apps_table 
GROUP BY id ;

注意ELSE NULL 是多余的,因为如果CASE 表达式中没有匹配项,NULL 是默认值。

【讨论】:

    【解决方案2】:

    您很接近,您可以在查询中使用 SUM 而不是 count。

    SELECT id
    ,SUM(CASE WHEN app IN ('Clash of Clans', 'Valorant', 'PUBG') THEN 1 ELSE 0 END) AS gaming_apps
    ,SUM(CASE WHEN app IN ('Telegram', 'WhatsApp', 'Signal', 'FBMessenger')  THEN 1 ELSE 0 END) AS msg_apps
    ,SUM(CASE WHEN app IN ('Yahoo Finance', 'Robinhood') THEN 1 ELSE 0 END) AS fin_apps 
    FROM apps_table 
    GROUP BY id 
    

    我认为这应该可行。如果它不起作用,那么就像你说的那样做一个左连接。

    SELECT main.id as id,
    gaming_apps,
    msg_apps, 
    ...
    
    FROM apps_table  main
    LEFT OUTER JOIN (
    SELECT id,COUNT(DISTINCT app) AS gaming_apps FROM apps_table  WHERE app IN ('Clash of Clans', 'Valorant', 'PUBG')  GROUP BY id) gaming_apps ON gaming_apps .id=main.id
    LEFT OUTER JOIN (
    SELECT id ,COUNT(DISTINCT app) AS msg_apps FROM apps_table  WHERE app IN ('Telegram', 'WhatsApp', 'Signal', 'FBMessenger')  GROUP BY id) msg_apps ON msg_apps.id=main.id 
    ...
    
    
    

    【讨论】:

      【解决方案3】:

      我发现添加 OVER (PARTITION BY id) 也可以只计算不同的记录(不知道为什么?),尽管根据每个 id 在表中有多少 app 条目返回相同值的重复行。如果没有OVER (PARTITION BY id),它只会计算匹配项而不考虑不同的值,如果id 有多个相同app 的条目,则会增加数字。

      SELECT id
      ,SUM(CASE WHEN app IN ('Clash of Clans', 'Valorant', 'PUBG') THEN 1 ELSE 0 END) OVER (PARTITION BY id) AS gaming_apps
      ,SUM(CASE WHEN app IN ('Telegram', 'WhatsApp', 'Signal', 'FBMessenger')  THEN 1 ELSE 0 END) OVER (PARTITION BY id) AS msg_apps
      ,SUM(CASE WHEN app IN ('Yahoo Finance', 'Robinhood') THEN 1 ELSE 0 END) OVER (PARTITION BY id) AS fin_apps 
      FROM apps_table 
      GROUP BY app, id 
      

      为了删除重复项,我将结果包装为子查询并使用SELECT DISTINCT 或使用ROW_NUMBER() OVER (PARTITION BY id) 创建排名,然后进行过滤。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-12-18
        • 2012-07-09
        • 2019-05-18
        • 1970-01-01
        • 1970-01-01
        • 2016-05-11
        • 1970-01-01
        • 2022-01-23
        相关资源
        最近更新 更多