【问题标题】:get sum of the each possibility based on the column value in hive - Aggregate table根据 hive 中的列值获取每种可能性的总和 - 聚合表
【发布时间】:2020-11-18 14:16:59
【问题描述】:

我有以下列的表格。

对于上表,我需要按日期获取每个 cd 的计数取决于 ind 值组合,并期待下面的输出表。

对于输出表中的 row2,id 45 有一个 OK,一个 no,因此需要将日期 2020-02-24 的计数作为 1,因为它有 1 个 ok

同样,对于第 4 行,它有 notok 和 no,所以对于这种组合,我们需要将 notok 作为 id 30 的最大日期

我需要在 hive 中开发它,有人可以建议我们如何实现它。我尝试编写单独的子查询,但由于许多连接而导致性能下降(我正在编写单独的查询来分别计算每个组合并连接结果)

针对其他场景更新:

我在表格中有以下数据。

当我们给权重时,它看起来如下

第一种情况:当我们按日期分组时,对于 2020 年 1 月 1 日,我得到的计数是 1,这是正确的

第二种情况:对于日期 2020 年 1 月 2 日,我们假设为 notOk 仅获得计数 1,但它给出 2(因为它正在为 cd 1 寻找 2020 年 1 月 2 日的第一种情况行。

还有另一个场景:

当我在不同日期对同一张 cd 有多个记录时,没有给出正确的结果。

我在不同的日期有 2 个 cd 1 的“ok”。所以我们只需要考虑计数 1,我们需要删除其他 ok,即 2020 年 1 月 1 日或 2020 年 1 月 2 日,因为它是相同的 cd。

非常感谢您的帮助。

谢谢, 巴布

【问题讨论】:

    标签: sql hive pivot hiveql greatest-n-per-group


    【解决方案1】:

    如果您需要对给定 ID 的最新日期进行 ind 计数,则查询将如下所示

    select dt,count(case when ind='ok' then 1 end) as ok_count,
    count(case when ind='No' then 1 end) as No_count,
    count(case when ind='not ok' then 1 end) as not_ok_count 
    from mytable_test where dt in (select max(dt) from mytable_test group by cd) group by dt;
    

    但是,如果存在某些真值表条件,例如:对于给定的 ID,
    - 如果它同时具有 OK 和 No,则选择 OK。 - 如果它有No和not ok,就选not ok。

    那么它可能不是一个非常有效的方法,但可以正常工作。

    select dt,count(case when ind='ok' then 1 end) as ok_count,
    count(case when ind='No' then 1 end) as No_count,
    count(case when ind='not ok' then 1 end) as not_ok_count 
    from mytable_test where dt in (
    select max(a.dt) from mytable_test a,(select cd, (case when ind_to_consider=0 then 'No' when ind_to_consider=1 then 'ok' when ind_to_consider=2 then 'not ok' end ) as decoeded_ind from  (select cd,max(ind_wt) as ind_to_consider from (select dt,cd,ind,(case when ind='ok' then 1 when ind='No' then 0 when ind='not ok' then 2 end ) as ind_wt from  mytable_test) wt group by cd) decoder) k where a.cd=k.cd and a.ind=k.decoeded_ind group by a.cd,a.ind)  group by dt;
    

    解释

    首先对您提供的 ind 条件提供一些权重。 在这种情况下,根据您的示例,我假设 NOK 的重量最小,中等,而不是最高

    select dt,cd,ind,(case when ind='ok' then 1 when ind='No' then 0 when ind='not ok' then 2 end ) as ind_wt from  mytable_test
    
        +-------------+-----+---------+---------+--+
        |     dt      | cd  |   ind   | ind_wt  |
        +-------------+-----+---------+---------+--+
        | 2020-08-24  | 10  | ok      | 1       |
        | 2020-02-21  | 45  | No      | 0       |
        | 2020-02-24  | 45  | ok      | 1       |
        | 2020-08-25  | 20  | No      | 0       |
        | 2020-10-09  | 30  | not ok  | 2       |
        | 2020-10-13  | 30  | not ok  | 2       |
        | 2020-10-21  | 30  | No      | 0       |
        | 2020-10-23  | 30  | No      | 0       |
        | 2020-09-14  | 12  | No      | 0       |
        +-------------+-----+---------+---------+--+
    

    接下来获取每张 CD 的最大权重(在 wt 块中)

    select cd,max(ind_wt) as ind_to_consider from (select dt,cd,ind,(case when ind='ok' then 1 when ind='No' then 0 when ind='not ok' then 2 end ) as ind_wt from  mytable_test) wt group by cd
    
    +-----+------------------+--+
    | cd  | ind_to_consider  |
    +-----+------------------+--+
    | 10  | 1                |
    | 12  | 0                |
    | 20  | 0                |
    | 30  | 2                |
    | 45  | 1                |
    +-----+------------------+--+
    

    现在您必须将权重解码回指标,以便您可以获得每个 cd 和 max 指标的最新日期。

    select max(a.dt) from mytable_test a,(select cd, (case when ind_to_consider=0 then 'No' when ind_to_consider=1 then 'ok' when ind_to_consider=2 then 'not ok' end ) as decoeded_ind from  (select cd,max(ind_wt) as ind_to_consider from (select dt,cd,ind,(case when ind='ok' then 1 when ind='No' then 0 when ind='not ok' then 2 end ) as ind_wt from  mytable_test) wt group by cd) decoder) k where a.cd=k.cd and a.ind=k.decoeded_ind group by a.cd,a.ind
    
    +-------------+--+
    |     _c0     |
    +-------------+--+
    | 2020-08-24  |
    | 2020-09-14  |
    | 2020-08-25  |
    | 2020-10-13  |
    | 2020-02-24  |
    +-------------+--+
    

    然后使用这些日期来获取枢轴

    select dt,count(case when ind='ok' then 1 end) as ok_count,
    count(case when ind='No' then 1 end) as No_count,
    count(case when ind='not ok' then 1 end) as not_ok_count 
    from mytable_test where dt in (
    select max(a.dt) from mytable_test a,(select cd, (case when ind_to_consider=0 then 'No' when ind_to_consider=1 then 'ok' when ind_to_consider=2 then 'not ok' end ) as decoeded_ind from  (select cd,max(ind_wt) as ind_to_consider from (select dt,cd,ind,(case when ind='ok' then 1 when ind='No' then 0 when ind='not ok' then 2 end ) as ind_wt from  mytable_test) wt group by cd) decoder) k where a.cd=k.cd and a.ind=k.decoeded_ind group by a.cd,a.ind)  group by dt;
    
    
    
    +-------------+-----------+-----------+---------------+--+
    |     dt      | ok_count  | no_count  | not_ok_count  |
    +-------------+-----------+-----------+---------------+--+
    | 2020-02-24  | 1         | 0         | 0             |
    | 2020-08-24  | 1         | 0         | 0             |
    | 2020-08-25  | 0         | 1         | 0             |
    | 2020-09-14  | 0         | 1         | 0             |
    | 2020-10-13  | 0         | 0         | 1             |
    +-------------+-----------+-----------+---------------+--+
    

    【讨论】:

    • 感谢您的快速回复。我不能接受最大日期。无论我们在哪里看到相同 ID 的 ok 和 No 组合,我都需要为它具有“ok”的行获取日期并将其显示在报告中。如果我们看到“no”和“notok”,我需要在我们有“no”行的地方记录日期。
    • 按照原始要求,对于Id=4和cd=30,输出应该产生2020-10-13 "not ok"= 1 原始答案中提供的代码是这样做的(解释区上方的代码 sn-p) 。你的要求有什么变化吗?您能否进一步详细说明您的问题?请注意,我使用的是 Dt 列而不是日期
    • 我已经实现了这个并且它工作正常。非常感谢您提供详细的解决方案,非常感谢。还要考虑一件事,如果我们在多天有相同的 ind,我们只需将其视为一天,我们需要计算一个。例如,在同一个“id”上,我已经“ok”了三天。所以我只需要考虑一个“好的”就可以了。您是否认为该解决方案也适用于该场景。我希望我们正在接受 max(date) 但只是为了确认...非常感谢您的帮助。
    • 只要您没有重复的日期代码和指标组合,它应该可以工作。如果您有重复的条目,则在 wt 部分添加 distinct 关键字 ..e.g -> (select distinct dt,cd,ind,(case when ind='ok' then 1 when ind='No' then 0 when ind='not ok' then 2 end ) as ind_wt from mytable_test) wt
    • 您好 Rajat,非常感谢您的帮助。您正在花时间回答我的每个问题。真的谢谢。当我们有不同日期的相同 cd 时,它不起作用。请在原帖中查看我更新的笔记,并请让我知道我缺少什么来涵盖这 2 个场景。
    【解决方案2】:

    使用条件聚合:

    select date,
        sum(case when ind = 'ok'     then 1 else 0 end) ok_count,
        sum(case when ind = 'No'     then 1 else 0 end) no_count,
        sum(case when ind = 'not ok' then 1 else 0 end) not_ok_count
    from mytable
    group by date
    

    或者,如果您只想考虑每个 id 的最新行,我们可以先使用 row_number() 进行预过滤:

    select date,
        sum(case when ind = 'ok'     then 1 else 0 end) ok_count,
        sum(case when ind = 'No'     then 1 else 0 end) no_count,
        sum(case when ind = 'not ok' then 1 else 0 end) not_ok_count
    from (
        select t.*, row_number() over(partition by id order by date desc) rn
        from mytable t
    ) t
    where rn = 1
    group by date
    

    【讨论】:

      猜你喜欢
      • 2018-11-07
      • 1970-01-01
      • 2018-05-22
      • 1970-01-01
      • 1970-01-01
      • 2019-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多