【问题标题】:how to use count with case when如何在大小写时使用计数
【发布时间】:2021-02-07 16:54:32
【问题描述】:

我是 Hivesql 的新手。 我有一个包含 600 万条记录的原始表,如下所示:

我想统计每周对每个 Modem_id 的 IP_address 访问次数。 我想要的结果表会是这样的:

我用左连接完成了它,它有效。但是由于使用 join 会很耗时,所以我想用 case when 语句来做——但我不能写出正确的语句。你有什么想法吗?

这是我使用的连接语句:

select a.modem_id, 
       a.Number_of_IP_in_Day_1, 
       b.Number_of_IP_in_Day_2
from 
(select modem_id,
        count(distinct ip_address) as Number_of_IP_in_Day_1 
  from F_ACS_DEVICE_INFORMATION_NEW 
  where day=1
  group by modem_id) a 
left join 
(select modem_id,
        count(distinct param_value) as Number_of_IP_in_Day_2 
  from F_ACS_DEVICE_INFORMATION_NEW 
  where day=2
  group by modem_id) b 
on a.modem_id= b.modem_id; 

【问题讨论】:

  • 您的输出将天数作为列标题。这是动态的吗,例如,10 天后您想要 10 列,一年后您想要 365 列?
  • 其实,我想统计每周的IP数。所以它只有 4 列 4 周
  • 你有证据表明加入很耗时吗?
  • 您需要这种格式吗?调制解调器 ID、日期、IP 计数是否有效?

标签: sql hive count case grouping


【解决方案1】:

根据您的问题和进一步的 cmets,您希望

  • 每个调制解调器访问的不同 IP 地址的数量
  • 4 周内按周计数(以列形式)

例如,结果将是 5 列

  • modem_id
  • IPs_accessed_week1
  • IPs_accessed_week2
  • IPs_accessed_week3
  • IPs_accessed_week4

我的回答是基于 SQL 知识——我没有使用过 Hive,但它似乎支持我使用的东西(例如 CTE)。您可能需要稍微调整一下答案。

第一个关键步骤是将 day_number 变成 week_number。一个直接的方法是 FLOOR((day_num-1)/7)+1 所以第 1-7 天变成第 1 周,第 8-14 天变成第 2 周,等等。

注意 - 由您来确保 day_nums 是正确的。我猜您实际上想要的是 最后 4 周的信息,而不是前 4 周的数据 - 因此,您可能会将 day_num 计算为 SELECT DATEDIFF(day, IP_access_date, CAST(getdate() AS date)) 之类的东西 - 不管是什么等价物在 Hive 中。

有几种方法可以做到这一点 - 我认为最清楚的是使用 CTE 将数据集转换为您需要的数据,例如,

  • 将 day_nums 转换为 weeknums
  • 在一周内消除重复项(您的代码有 COUNT(DISTINCT ...) - 我认为这是您想要的)- 我正在使用 SELECT DISTINCT 执行此操作(而不是按所有字段分组)

从那里,您可以 PIVOT 数据以将其放入您的表中,或者只使用 CASE 语句的 SUM。我将在这里使用 SUM of CASE,因为我认为它更容易理解。

WITH IPs_per_week AS
    (SELECT DISTINCT 
            modem_id,
            ip_address,
            FLOOR((day-1)/7)+1 AS week_num    -- Note I've referred to it as day_num in text for clarity
     FROM   F_ACS_DEVICE_INFORMATION_NEW
    )
SELECT modem_id,
       SUM(CASE WHEN week_num = 1 THEN 1 ELSE 0 END) AS IPs_access_week1,
       SUM(CASE WHEN week_num = 2 THEN 1 ELSE 0 END) AS IPs_access_week2,
       SUM(CASE WHEN week_num = 3 THEN 1 ELSE 0 END) AS IPs_access_week3,
       SUM(CASE WHEN week_num = 4 THEN 1 ELSE 0 END) AS IPs_access_week4
FROM   IPs_per_week
GROUP BY modem_id;

【讨论】:

    【解决方案2】:

    您可以仅使用聚合来表达您的逻辑:

    select a.modem_id, 
           count(distinct case when date = 1 then ip_address end) as day_1,
           count(distinct case when date = 2 then ip_address end) as day_2
    from F_ACS_DEVICE_INFORMATION_NEW a
    group by a.modem_id;
    

    您显然可以将其延长更多天。

    注意:在编写您的问题和代码时,这假设您的基表只有一周的数据。否则,我会期待一些日期过滤。想必这就是表名上_NEW后缀的意思。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-06
      • 2019-08-22
      • 2018-08-20
      • 1970-01-01
      相关资源
      最近更新 更多