聚合来自数组列的不同元素的单个数组,不包括 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
中测试
一般说明。使用数组构造函数的替代解决方案效率更高,尤其是在描述的那么简单的情况下。就个人而言,我更喜欢使用聚合函数,因为这种查询结构更通用、更灵活,易于扩展以处理更复杂的问题(例如,必须聚合多个列、按另一列分组等)。在这些重要的情况下,性能差异往往会减小,但使用聚合的代码仍然更清晰、更具可读性。当您必须维护非常大且复杂的项目时,这是一个极其重要的因素。
另见
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 BY
和 DISTINCT
更快(并且完成简单的工作)。
参见:
Unnest arrays of different dimensions
How to select 1d array from 2d array?
Why is array_agg() slower than the non-aggregate ARRAY() constructor?
性能比较:
db<>fiddle here
我正在尝试汇总存储在 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
中测试
一般说明。使用数组构造函数的替代解决方案效率更高,尤其是在描述的那么简单的情况下。就个人而言,我更喜欢使用聚合函数,因为这种查询结构更通用、更灵活,易于扩展以处理更复杂的问题(例如,必须聚合多个列、按另一列分组等)。在这些重要的情况下,性能差异往往会减小,但使用聚合的代码仍然更清晰、更具可读性。当您必须维护非常大且复杂的项目时,这是一个极其重要的因素。
另见
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 BY
和DISTINCT
更快(并且完成简单的工作)。
参见:
Unnest arrays of different dimensions
How to select 1d array from 2d array?
Why is array_agg() slower than the non-aggregate ARRAY() constructor?
性能比较:
db<>fiddle here