具有多列的表中每个组的第一个非空值

时间:2020-04-19 14:57:27

标签: sql pandas postgresql

在SO上已广泛讨论了寻找第一个非空值的问题,但是由于某些原因,所有的解决方案都是有问题的,可能是由于我对PostgreSQL的经验不足。表格中的结构如下:

group           submitted   num1  num2  num3  str1  str2  str3 ...
   32  14:04:21 4.5.2020.      2     1  Null  Null  Null  Null
   32  13:01:23 4.5.2020.   Null     1     0   abc   def  Null
   37  15:01:44 3.2.2020.      2  Null     0  Null  Null   aar
   37  03:04:21 2.1.2020.   Null     1     0   abc   def  Null
   37  23:04:00 1.1.2020.      2  Null     0   trt   def   abg
   ...

上面示例的预期结果是:

group  num1  num2  num3  str1  str2  str3 ...
   32     2     1     0   abc   def  Null
   37     2     1     0   abc   def   aar
...

有40多个列,性能很重要。我需要每组一行包含最新的非空值,或者在上面(排序的)数据集中的第一个非空。到目前为止,我尝试过的是:

1)按提交的,分组的组进行排序,然后找不到用于查找第一个非空值的聚合函数。有没有办法以某种方式创建自定义聚集功能?

2)使用具有窗口功能的解决方案:

...
first_value(education) OVER (PARTITION BY CASE ORDER BY submitted WHEN education IS NOT NULL THEN submitted END) as education,
...

非常慢(比使用MAX的groupby慢数百倍),我觉得因为所有表都具有相同的分区,所以不应为每一列重复此操作。有没有一种方法可以对整个表进行分区,然后查找每列的第一个值?

3)一些解决方案提到了ROWNUM。这个问题(以及大多数解决方案)的问题在于,在进行第一次排序和分区之后,无需遍历该列中的所有值。

我希望的解决方案是熊猫first的类似物。

1 个答案:

答案 0 :(得分:3)

有一个技巧,就是使用array_agg()并删除null。那应该是:

select groupid,
       (array_remove(array_agg(num1 order by submitted desc), null))[1] as num1,
       (array_remove(array_agg(num2 order by submitted desc), null))[1] as num2,
       . . .
from t
group by groupid;

Here是db <>小提琴。