聚合来自数组列的不同元素的单个数组,不包括 NULL

Aggregate single array of distinct elements from array column, excluding NULL

我正在尝试汇总存储在 PostgreSQL 9.6 数据库列中的时间戳的不同非空值。

所以给定一个包含以下内容的 table:

date_array
------------------------
{2019-10-21 00:00:00.0}
{2019-08-06 00:00:00.0,2019-08-05 00:00:00.0}
{2019-08-05 00:00:00.0}
(null)
{2019-08-01 00:00:00.0,2019-08-06 00:00:00.0,null}

期望的结果是:

{2019-10-21 00:00:00.0, 2019-08-06 00:00:00.0, 2019-08-05 00:00:00.0, 2019-08-01 00:00:00.0}

数组的大小可以不同,因此我尝试过的大多数解决方案最终都会 运行 变成代码 0:

SQL State: 2202E  
ERROR: cannot accumulate arrays of different dimensionality.

其他一些注意事项:

数组可以为空,数组可以包含空。它们恰好是日期的时间戳(例如,没有时间或时区)。但是在尝试简化问题时,我没有运气将示例数据更改为字符串(例如 {foo, bar, (null)}, {foo,baz})——只是为了关注问题并消除我 miss/don 不了解的任何问题时间戳 w/o 时区。

下面的 SQL 是我最接近的(它解决了除不同维度问题之外的所有问题):

SELECT 
   ARRAY_REMOVE ( ARRAY ( SELECT DISTINCT UNNEST ( ARRAY_AGG ( CASE WHEN ARRAY_NDIMS(example.date_array) > 0 AND example.date_array IS NOT NULL THEN example.date_array ELSE '{null}' END ) ) ), NULL) as actualDates
FROM example;

我创建了以下数据库 fiddle,其中包含说明问题的示例数据(如果缺少上述内容):https://www.db-fiddle.com/f/8m469XTDmnt4iRkc5Si1eS/0

此外,我仔细阅读了关于这个问题的 Whosebug(以及 PostgreSQL 文档)并且有类似的问题和答案,但我发现 none 表达的是相同的我遇到的问题。

FROM 子句中使用 unnest()(在横向连接中):

select array_agg(distinct elem order by elem desc) as result
from example
cross join unnest(date_array) as elem
where elem is not null

DB Fiddle.

中测试

一般说明。使用数组构造函数的替代解决方案效率更高,尤其是在描述的那么简单的情况下。就个人而言,我更喜欢使用聚合函数,因为这种查询结构更通用、更灵活,易于扩展以处理更复杂的问题(例如,必须聚合多个列、按另一列分组等)。在这些重要的情况下,性能差异往往会减小,但使用聚合的代码仍然更清晰、更具可读性。当您必须维护非常大且复杂的项目时,这是一个极其重要的因素。

另见

Plain array_agg() 对数组执行此操作:

Concatenates all the input arrays into an array of one higher dimension. (The inputs must all have the same dimensionality, and cannot be empty or null.)

不是你需要的。参见:

  • Is there something like a zip() function in PostgreSQL that combines two arrays?

你需要这样的东西:unnest(), process and sort elements an feed the resulting set to an ARRAY constructor:

SELECT ARRAY(
   SELECT DISTINCT elem::date
   FROM  (SELECT unnest(date_array) FROM example) AS e(elem)
   WHERE  elem IS NOT NULL
   ORDER  BY elem DESC
   );

db<>fiddle here

需要说明的是:我们可以使用 array_agg()(采用非数组输入,与您不正确的使用不同)而不是最终的 ARRAY 构造函数。但后者更快(也更简单,IMO)。

They happen to be timestamps of just dates (eg without time or timezone)

因此投射到 date 和 trim 噪音。

应该是最快的方法:

  • 相关子查询比 LATERAL 快一点(并且完成简单的工作)。
  • ARRAY 构造函数比聚合函数快一点 array_agg()(并且完成简单的工作)。
  • 最重要的是,在子查询中排序和应用 DISTINCT 通常比聚合函数中的内联 ORDER BYDISTINCT 更快(并且完成简单的工作)。

参见:

性能比较:

db<>fiddle here