unnest() 如何处理 NULL 值和空数组?

use*_*521 5 postgresql join array postgresql-9.4

我正在尝试LEFT JOIN使用数组unnest()函数实现类似的功能。如果数组为空,我希望查询返回具有空值的行。因此,通过使用CASE构造,如果源数组为空,我想传递具有单个空元素的假数组,但它无法按预期工作:

查询 1

select element 
from (
  select array['a']::text[] as arr --< single non-null element
) sub, unnest(
  (
    case when array_length(sub.arr, 1) <= 0 then (array[null])::text[] 
    else sub.arr 
    end
  )
) element
-- returns 1 row with element = "a"
Run Code Online (Sandbox Code Playgroud)

查询 2

select element 
from (
  select array[]::text[] as arr --< empty array
) sub, unnest(
  (
    case when array_length(sub.arr, 1) <= 0 then (array[null])::text[] 
    else sub.arr 
    end
  )
) element
-- returns 0 rows (should return 1 row with element = NULL?)
Run Code Online (Sandbox Code Playgroud)

查询 3

select element 
from (
  select array[null]::text[] as arr --< single null element
) sub, unnest(
  (
    case when array_length(sub.arr, 1) <= 0 then (array[null])::text[] 
    else sub.arr 
    end
  )
) element
-- return single row with element = NULL
Run Code Online (Sandbox Code Playgroud)

刚刚发现select array_length(array[]::text[], 1)返回NULL- 我的问题是为什么?

Erw*_*ter 8

在 pgsql-hackers 上的线程“Should array_length() Return NULL”中引用Tom Lane

问题是该语法创建了一个零维数组,而不是一个具有 1 维和零元素的数组。所以“0”是不正确的。

很难说是否array_length()应该返回NULL0为空数组维度......

解决方案

仅当长度为 时,您才能反转逻辑并处理原始源数组>= 1

WITH tbl(id, arr) AS (
   VALUES
     (1, '{a}'::text[])
   , (2, '{NULL}'::text[])
   , (3, '{}'::text[])
   , (4, '{x,y,z}'::text[])
   )
SELECT id, elem
FROM   tbl t
     , unnest (
          CASE WHEN array_length(t.arr, 1) >= 1
               THEN t.arr
               ELSE '{null}'::text[] END
       ) elem;
Run Code Online (Sandbox Code Playgroud)

为每个源行返回至少一行。

或者,更简单的是,使用实际的LEFT JOINFROM子句中的逗号是 的简写CROSS JOIN):

SELECT id, elem
FROM   tbl t
LEFT   JOIN LATERAL unnest(t.arr) elem ON true;
Run Code Online (Sandbox Code Playgroud)

如果未找到匹配项,则会自动为右表的列填充 NULL 值。正是您想要实现的目标。
有关的:

db<>在这里摆弄