21

我使用 postgreSQL 9.1。在我的数据库中有一个看起来像的表

id | ... | values
-----------------------
1  | ... | {1,2,3}
2  | ... | {}

其中 id 是一个整数,而 values 是一个整数数组。数组可以为空。

我需要取消嵌套此列表。如果我查询

select id, ..., unnest(values)
from table

我得到 id = 1 的三行(如预期的那样),没有 id = 2 的行。有没有办法得到类似的结果

id  | ... | unnest
-------------------
1   | ... | 1
1   | ... | 2
1   | ... | 3
2   | ... | null

即一个查询,它还包含有一个空数组的行?

4

5 回答 5

23
select id, 
       case 
         when int_values is null or array_length(int_values,1) is null then null
         else unnest(int_values)
       end as value
from the_table;

(请注意,我将列重命名valuesint_valuesasvalues是保留字,不应用作列名)。

SQLFiddle:http ://sqlfiddle.com/#!1/a0bb4/1


Postgres 10 不再允许这样使用unnest()

您需要使用横向连接:

select id, t.i
from the_table
   cross join lateral unnest(coalesce(nullif(int_values,'{}'),array[null::int])) as t(i);

在线示例:http ://rextester.com/ALNX23313


当使用左连接而不是交叉连接时,它可以进一步简化:

select id, t.i
from the_table
 left join lateral unnest(int_values) as t(i) on true;

在线示例:http ://rextester.com/VBO52351

于 2013-03-02T14:24:41.347 回答
14

这也适用于 Postgres 10:

SELECT id, UNNEST(CASE WHEN "values" <> '{}' THEN "values" ELSE '{null}' END)
于 2018-04-09T15:37:00.207 回答
4

在重新审视这个问题时,我觉得这可以更简单、更快。
通过@a_horse颠倒当前接受的解决方案的逻辑

SELECT id, CASE WHEN values <> '{}' THEN unnest(values) END AS value
FROM   tbl
  • 对于空数组和数组,这将返回一行NULL,因为只有包含元素的数组才会在 test中产生。valueNULLTRUEvalues <> '{}'

  • 适用于任何类型的数组,因为文字“{}”会自动强制转换为匹配类型。

  • 如果没有明确的ELSE分支,就会CASE返回NULL,这就是我们想要的。

  • 无论如何,带有NULL元素的数组都将返回行。
    然而。我在那里发现了一个异常并发布了一个关于此的问题:

    原来是在我报告 pg 9.3+ 后修复的错误。

于 2013-05-08T22:43:30.383 回答
1
select id,
    unnest (
        "values"
        ||
        (array[null]::integer[])[1:(array_upper("values", 1) is null)::integer]
    )
from "table"
于 2013-03-02T15:31:35.447 回答
0

您将需要使用 self LEFT JOIN,像这样(也在SQL Fiddle上):

SELECT t.id, u.u
  FROM tab t
  LEFT JOIN (SELECT id, unnest(vals) u FROM tab) u
    USING (id);

请注意,对于更大的表查询将表现不佳。

于 2013-03-02T14:18:04.983 回答