我可以避免 unnest() 跳过未设置的数组元素吗?

问题描述 投票:0回答:1

我原本期望

unnest()
返回数组中索引 1 到
array_length()
的一行,但显然情况并非如此。考虑这个例子:

create table T (
    id int,
    list int[]
);

insert into T values
    (1, array[null, 42]),   -- filled from the start
    (2, array[]::int[]);    -- we'll fill this later as we get values

update T set list[2] = 42 where id = 2;  -- we got a value for id 2 now

select x.* from T, unnest(T.list) with ordinality as x (val, idx) where id = 1;
select x.* from T, unnest(T.list) with ordinality as x (val, idx) where id = 2;

两个

select
的输出为:

 val | idx 
-----+-----
     |   1
  42 |   2

 val | idx 
-----+-----
  42 |   1

这是不幸的,因为在我的例子中元素的位置很重要。第二个查询显示值 42 的索引为 1,这打破了我想要做的事情。

我实际上很高兴 PostgreSQL 不会盲目地用

NULL
填充未设置的数组索引,因为这可能会节省大量存储空间(第二个数组存储为
[2:2]={42}
而不是
{NULL,42}
)。但在这种情况下,很不方便。

解决这个问题的最佳方法是什么?

背景:我们需要存储数十亿个 float8 值。它们以 EAV 格式(实体-属性-值)到达,我们按实体将它们聚合到数组中,属性提供数组索引。这已经不再是合理的了,但是庞大的数据量很难以其他方式进行管理。


编辑:我不知道为什么 StackOverflow 不断将“稀疏数组”标签更改为“稀疏矩阵”。这与多维数组无关。

arrays postgresql sparse-matrix unnest
1个回答
1
投票

不确定为什么它是单独记录的而不是与数组函数一起记录,但您可以使用

generate_subscripts
函数来实现此目的。与
WITH ORDINALITY
不同,它不会产生排序,而是产生可用于索引数组的实际下标:

SELECT list[x.idx] AS val, x.*
FROM T, generate_subscripts(T.list, 1) WITH ORDINALITY AS x (idx, ord);

(在线演示)

但是,请注意 Postgres 数组 实际上并不稀疏 - 它们只是具有任意(下限和上限)边界。我不确定这样做的目的是什么 - 也许它与数组切片的表示方式有关,也许它是为了支持基于 0 的索引(尽管这会导致比值更混乱),但是无论哪种情况

[当]分配给尚未存在的元素时[,]先前存在的元素和新分配的元素之间的任何位置都将用空值填充。

如果您确实需要一些稀疏的东西,可以插入任意键并且中间不占用任何空间,请查看 hstorejsonb

© www.soinside.com 2019 - 2024. All rights reserved.