sql - 如何从按索引存储数组元素的规范化表中获取数组?

标签 sql arrays postgresql aggregate-functions generate-series

我有一个表,按数组元素所属的数组存储数组元素, 他们在数组中的索引。这看起来很聪明,因为阵列是 预计是稀疏的,并单独更新它们的元素。 假设这是表格:

CREATE TABLE values (
    pk TEXT,
    i INTEGER,
    value REAL,
    PRIMARY KEY (pk, i)
);

 pk | i | value
----+---+-------
 A  | 0 | 17.5
 A  | 1 | 32.7
 A  | 3 | 5.3
 B  | 1 | 13.5
 B  | 2 | 4.8
 B  | 4 | 89.1

现在我想将它们作为真正的数组获取,即 {17.5, 32.7, NULL, 53}对于 A 和 {NULL, 13.5, 4.8, NULL, 89.1}对于 B.

我原以为分组查询很容易实现 和适当的聚合函数。然而,原来有 没有这样的函数可以通过其索引将元素放入数组(或 下标,正如 postgres 所说的那样)。如果 元素是连续的 - 我本来可以使用 array_aggORDER BY i .但我想要结果中的空值 数组。

我最终得到的是这个怪物:

SELECT
  pk,
  ARRAY( SELECT
    ( SELECT value
      FROM values innervals
      WHERE innervals.pk = outervals.pk AND i = generate_series
    )
    FROM generate_series(0, MAX(i))
    ORDER BY generate_series -- is this really necessary?
  )
FROM values outervals
GROUP BY pk;

不得不 SELECT … FROM values两次是丑陋的,查询规划器似乎无法对此进行优化。

有没有一种简单的方法可以将分组的行作为子查询中的关系来引用,这样我就可以 SELECT value FROM generate_series(0, MAX(i)) LEFT JOIN ??? ?

通过定义 custom aggregate function 来解决这个问题是否更合适? ?


编辑:看来我正在寻找的东西可以通过多参数 unnest 实现和 array_agg ,虽然不是特别优雅:

SELECT
  pk,
  ARRAY( SELECT val
    FROM generate_series(0, MAX(i)) AS series (series_i)
    LEFT OUTER JOIN
      unnest( array_agg(value ORDER BY i),
              array_agg(i ORDER BY i) ) AS arr (val, arr_i)
      ON arr_i = series_i
    ORDER BY series_i
  )
FROM values
GROUP BY pk;

查询规划器甚至似乎意识到它可以进行排序合并 JOIN在排序series_iarr_i ,虽然我需要付出更多努力才能真正理解 EXPLAIN输出。 编辑 2:它实际上是 series_i 之间的散列连接和 arr_i ,只有外部组聚合使用“排序”策略。

最佳答案

不确定这是否符合“更简单”的条件 - 我个人认为它更容易理解:

with idx as (
  select pk, 
         generate_series(0, max(i)) as i
  from "values"
  group by pk
)
select idx.pk, 
       array_agg(v.value order by idx.i) as vals
from idx 
  left join "values" v on v.i = idx.i and v.pk = idx.pk
group by idx.pk;

CTE idx 为每个 PK 值生成所有可能的索引值,然后使用它来聚合值

Online example

关于sql - 如何从按索引存储数组元素的规范化表中获取数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58026300/

相关文章:

更改字符串的大小写

sql - 带额外时间的字符串到日期的转换

php - 即使在 PHP 脚本插入数据停止后,数据仍被插入到数据库中

mysql - 如何加速多连接的sql查询的执行?

php - 更新时 SQL 语法错误

SQL:检查数组中是否至少有一个元素在子查询中

sql - 表记录相互要求的多对一

python - 在一维数组中查找对角线边界

c - 一个用 C 语言计算 NxM 数组中 0 到 9 的数字个数的程序?

sql - INSERT [...] ON CONFLICT 可以用于外键违规吗?