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

kzipqqlq  于 2023-08-04  发布在  PostgreSQL
关注(0)|答案(1)|浏览(116)

我曾期望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})。但在这种情况下,这是不方便的。
最好的解决办法是什么?
背景:我们需要存储数十亿个float 8值。它们以EAV格式(实体-属性-值)到达,我们按实体将它们聚合到数组中,属性提供数组索引。这几乎不再是相对合理的了,但是大量的数据很难以其他方式管理。

  • 编辑:我不知道为什么StackOverflow一直把“sparse-array”标签改为“sparse-matrix”。这与多维数组无关。*
hc8w905p

hc8w905p1#

不知道为什么它是documented separately而不是the array functions,但你可以使用generate_subscripts函数来实现。与WITH ORDINALITY不同,它不产生排序,而是产生实际的下标,你可以用它来索引数组:

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

字符串
online demo
但是,请注意,Postgres arrays实际上并不是稀疏的-它们只是具有任意的(下限和上限)边界。我不确定这样做的目的是什么-也许它与数组切片的表示方式有关,也许它旨在支持0-based indexing(尽管这会导致more confusion than value),但无论是哪种情况。
[当]赋值给尚未存在的元素[,]之前存在的元素和新赋值的元素之间的任何位置都将填充空值。
如果你真的需要一些稀疏的东西,可以插入任意的键,并且中间没有任何空间,看看hstorejsonb

相关问题