SQL/Presto:有多个条件的排名(一个条件是检查行是否在同一个标​​签中)

SQL/Presto: rank with multiple conditions (one condition is checking if rows is in the same tag)

我有如下数据 (dt):

  group_id    customer_id  tag     score   phase
  1           a             l1     0       2020
  1           b             l2     0       2021
  2           a             l4     1       2019
  2           e             l3     1       2019
  2           d             l3     1       2018
  3           q                    1       2020
  3           w                    1       2019
  3           z             l5     1       2019
  3           x             l5     1       2019
  3           c             l6     1       2019

我想

  1. 在一组中对他们进行排名,首先按分数(分数越低越好)
  2. 然后连接 customer_id 如果 2 位客户在同一组且得分相同,标签相同(非空)
  3. 我需要按阶段对它们进行排名(首选较旧的阶段)以生成最终列表。

因此,所需的输出是:

 group_id    customer_id   tag     score     phase          rank
  1           a             l1     0         2020           1    
  1           b             l2     0         2021           2
  2           a             l4     1         2019           2
  2           e,d           l3     1        2019, 2018      1
  3           q                    1         2020           2
  3           w                    1         2019           1
  3           z,x           l5     1       2019, 2019       1
  3           c             l6     1       2019             1         
 

我已经编写了以下查询,但我不确定如何合并检查标签中是否有 2 个客户的条件并进一步添加阶段比较条件。

  SELECT group_id, customer_id, tag, score, phase, 
  RANK() OVER (PARTITION BY group_id ORDER BY score) AS temp_rank
  FROM dt

我用 ROW_NUMBER() 而不是 RANK()。以下查询 returns 你想要的输出。我用 sql 测试了这个查询。在内置子查询中,我按 tag 分组,并使用 STRING_AGG() 函数将相同的值放入列中。然后我将结果加入到主 table.

select t.group_id,t.customer_id,t.tag,t.score,t.phase,ROW_NUMBER() OVER (PARTITION BY t.group_id ORDER BY t.score) AS rank
from
  (select distinct t1.*,t2.group_id,t2.score
  from
     (SELECT tag, STRING_AGG(customer_id, ',') AS customer_id,STRING_AGG(phase, ',') AS phase
      FROM dt
      group by tag) t1 join dt t2 on t1.tag = t2.tag) t
order by t.group_id,t.customer_id

结果 sql:https://dbfiddle.uk/sql

postgre 中的结果sql:https://dbfiddle.uk/postgresql

您必须 group by group_id, tag, score 并使用 array_join(array_agg()) 连接 customer_idphase 用于具有非 NULL 标记的行。
然后对带有 NULL 标记的行使用 UNION ALL
然后使用 RANK() 而不是 DENSE_RANK() window 函数:

SELECT group_id, customer_id, tag, score, phase,
       DENSE_RANK() OVER (PARTITION BY group_id ORDER BY score, min_phase) temp_rank
FROM (
  SELECT group_id, 
         array_join(array_agg(customer_id), ',') customer_id, 
         tag, 
         score, 
         array_join(array_agg(phase), ',') phase,
         MIN(phase) min_phase
  FROM dt
  WHERE tag IS NOT NULL
  GROUP BY group_id, tag, score
  UNION ALL
  SELECT group_id, customer_id, tag, score, phase, phase
  FROM dt
  WHERE tag IS NULL
) t

参见 demo(对于 Postgresql)。
结果:

group_id customer_id tag score phase temp_rank
1 a l1 0 2020 1
1 b l2 0 2021 2
2 e,d l3 1 2019,2018 1
2 a l4 1 2019 2
3 w null 1 2019 1
3 c l6 1 2019 1
3 z,x l5 1 2019,2019 1
3 q null 1 2020 2