【问题标题】:Convert multi-dimensional array to records将多维数组转换为记录
【发布时间】:2013-08-09 06:42:29
【问题描述】:

给定:{{1,"a"},{2,"b"},{3,"c"}}
期望:

 foo | bar
-----+------
  1  |  a
  2  |  b
  3  |  c

您可以通过以下查询获得预期结果;但是,最好有一些随数组大小缩放的东西。

SELECT arr[subscript][1] as foo, arr[subscript][2] as bar
FROM  ( select generate_subscripts(arr,1) as subscript, arr
        from (select '{{1,"a"},{2,"b"},{3,"c"}}'::text[][] as arr) input 
      ) sub;

【问题讨论】:

  • 没有办法动态改变SQL查询返回的列数。
  • 我想要回滚的唯一一件事是在标题中添加“标签:”,这是您已恢复的编辑。请不要在标题中添加标签。从您的编辑评论看来,您正在寻找此搜索:stackoverflow.com/search?q=infavorites%3A183181+[postgres]。您也可以使用 infavorites:mine 作为快捷方式。
  • @Flexo:你太棒了。是的,这是我不知道的东西,可能几年前就可以使用了。也许我应该更经常地在 Meta 上闲逛。你赢了:)
  • 如果将每个{ 替换为[ 并将} 替换为],它就会变成JSON,可以通过pl/pgsql json 解析器进行解析。这对您来说是一个可行的解决方案吗?
  • @funkwurm 不幸的是不是,除非它是仍在维护的最新香草 Postgres (8.4) 的一部分。我也可以创建一个临时表,或者使用VALUES (..),(...),但这都不够。

标签: sql arrays postgresql unnest


【解决方案1】:

这行得通:

select key as foo, value as bar
from json_each_text(
  json_object('{{1,"a"},{2,"b"},{3,"c"}}')
);

结果:

 foo | bar
-----+------
  1  |  a
  2  |  b
  3  |  c

Docs

【讨论】:

    【解决方案2】:

    不确定您所说的“最好有一些可以随数组大小缩放的东西”到底是什么意思。当然,随着内部数组大小的增长,您不能将额外的列添加到结果集中,因为 postgresql 必须知道查询的确切列执行之前(所以在它开始读取字符串之前)。

    但我想建议将字符串转换为矩阵的正常关系表示:

    select i, j, arr[i][j] a_i_j from (
     select i, generate_subscripts(arr,2) as j, arr from (
      select generate_subscripts(arr,1) as i, arr
      from (select ('{{1,"a",11},{2,"b",22},{3,"c",33},{4,"d",44}}'::text[][]) arr) input
     ) sub_i
    ) sub_j
    

    这给出了:

    i | j | a_i_j
    --+---+------
    1 | 1 | 1
    1 | 2 | a
    1 | 3 | 11
    2 | 1 | 2
    2 | 2 | b
    2 | 3 | 22
    3 | 1 | 3
    3 | 2 | c
    3 | 3 | 33
    4 | 1 | 4
    4 | 2 | d
    4 | 3 | 44
    

    我认为这样的结果在进一步的数据处理中可能相当有用。

    当然,这样的查询只能处理具有预定义维数的数组,但其所有维数的所有数组大小都可以在不重写查询的情况下更改,因此这是一种更灵活的方法。

    补充: 是的,使用with recursive 可以构建类似查询,能够处理任意维度的数组。尽管如此,没有办法克服来自关系数据模型的限制——必须在查询解析时定义精确的列集,并且没有办法将其延迟到执行时。因此,我们不得不使用另一个数组将所有索引存储在一列中。

    这是从任意多维数组中提取所有元素及其从零开始的索引(存储在另一个一维数组中)的查询:

    with recursive extract_index(k,idx,elem,arr,n) as (
     select (row_number() over())-1 k, idx, elem, arr, n from (
      select array[]::bigint[] idx, unnest(arr) elem, arr, array_ndims(arr) n 
      from ( select '{{{1,"a"},{11,111}},{{2,"b"},{22,222}},{{3,"c"},{33,333}},{{4,"d"},{44,444}}}'::text[] arr ) input
     ) plain_indexed
    union all
     select k/array_length(arr,n)::bigint k, array_prepend(k%array_length(arr,2),idx) idx, elem, arr, n-1 n 
     from extract_index
     where n!=1
    )
    select array_prepend(k,idx) idx, elem from extract_index where n=1
    

    这给出了:

    idx     | elem
    --------+-----
    {0,0,0} | 1
    {0,0,1} | a
    {0,1,0} | 11
    {0,1,1} | 111
    {1,0,0} | 2
    {1,0,1} | b
    {1,1,0} | 22
    {1,1,1} | 222
    {2,0,0} | 3
    {2,0,1} | c
    {2,1,0} | 33
    {2,1,1} | 333
    {3,0,0} | 4
    {3,0,1} | d
    {3,1,0} | 44
    {3,1,1} | 444
    

    从形式上看,这似乎证明了这个概念,但我想知道一个真正的实际用途是什么 :)

    【讨论】:

    • 妈妈,我不确定这是否正确。我想我可以结合WITH RECURSIVE 语法来查找数组的暗淡和上限.. 并拥有更多动态的东西。但是,在测试中,我注意到使用这种语法将字符串转换为数组非常慢(但这不是重点——这是一个概念证明)
    • 是的,这样的解决方案是存在的,但它看起来并不实用。 SQL 只是做这种非关系性事情的不合适的工具,所以任何 SQL 解决方案都注定是缓慢而模糊的。
    • 稍后我将使用 SQLFiddle 进行检查
    猜你喜欢
    • 2023-03-26
    • 2019-06-29
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多