UNNEST不能用于INSERT ... VALUES,必须配合INSERT ... SELECT;正确写法是INSERT INTO t SELECT UNNEST(arr),并用WITH ORDINALITY保留顺序、LATERAL处理关联、COALESCE或LEFT JOIN应对空数组,二维数组需降维展开。

UNNEST展开后直接INSERT到目标表,必须用FROM子句
UNNEST不能写在INSERT ... VALUES里——INSERT INTO t(col) VALUES (UNNEST(arr))会报错“function cannot be used in VALUES clause”。PostgreSQL要求VALUES列表中每个值必须是标量,而UNNEST返回的是行集。
正确路径只有一条:把UNNEST放在INSERT ... SELECT的SELECT部分,并确保整个查询结构落在FROM上下文中。
- ✅ 正确:
INSERT INTO target_table(col) SELECT UNNEST(ARRAY[1,2,3]); - ✅ 带来源表:
INSERT INTO target_table(user_id, tag) SELECT u.id, t.tag FROM users u, LATERAL UNNEST(u.tags) AS t(tag); - ❌ 错误:
INSERT INTO t VALUES (UNNEST(ARRAY[1,2,3]));(语法错误) - ❌ 错误:
INSERT INTO t SELECT (SELECT UNNEST(u.tags)) FROM users u;(子查询多行报错)
插入时保留原始数组索引位置,必须用WITH ORDINALITY
如果原数组顺序有意义(比如时间序列、权重向量、步骤列表),光用UNNEST会导致顺序丢失。PostgreSQL不保证默认输出顺序,尤其在并发或优化器介入时。
WITH ORDINALITY是唯一可靠方式,它把每个元素的位置作为整数下标返回,且该序号严格对应原始数组索引(从1开始)。
PostgreSQL 18.4 官方 Ubuntu 安装包现已发布,这是目前最新的稳定版本。推荐通过官方 APT 仓库安装:先执行 sudo apt update 更新索引,再运行 sudo apt install postgresql-18 即可完成部署。新版本引入了异步 I/O 子系统,在顺序扫描与 VACUUM 场景下性能提升显著,同时支持 UUID v7 原生生成函数与虚拟生成列。
- 示例:
INSERT INTO steps(order_id, step_name, pos) SELECT 101, s.name, s.ord FROM UNNEST(ARRAY['init','validate','commit']) WITH ORDINALITY AS s(name, ord); - 注意:
ord字段名可自定义,但必须紧跟在AS s(name, ord)里声明两个别名,否则会报“column reference 'ord' is ambiguous” - 不能和
LATERAL混用WITH ORDINALITY再套一层子查询——会丢掉ord;必须让UNNEST(...) WITH ORDINALITY直接出现在FROM中
处理空数组或NULL数组时,INSERT会漏行
UNNEST(NULL)或UNNEST(ARRAY[]::text[])结果是零行,不是一行NULL。这意味着INSERT SELECT UNNEST(...)对空数组不会写入任何记录,容易造成数据丢失却无提示。
若业务要求“空数组也要占一行(如标记为缺失)”,需主动补NULL:
- 用
COALESCE(arr, ARRAY[NULL::text])强行转成单元素数组(慎用,类型需明确) - 更稳妥:
SELECT COALESCE(NULLIF(arr, ARRAY[]::text[]), ARRAY[NULL::text]),先判空再替换 - 或改用LEFT JOIN模式:
INSERT INTO t SELECT u.id, COALESCE(t.tag, 'MISSING') FROM users u LEFT JOIN LATERAL UNNEST(u.tags) AS t(tag) ON true;
二维数组不能直接UNNEST,INSERT前必须降维
UNNEST(ARRAY[[1,2],[3,4]])只会返回两行:[1,2]和[3,4](即子数组本身),不是四行数字。PostgreSQL不支持自动展开嵌套结构。
要插入扁平化结果(如把matrix INTEGER[][]转成row_i, col_j, value三列),得手动控制维度:
- 先用
generate_subscripts生成坐标:SELECT i, j, matrix[i][j] FROM (SELECT matrix, generate_subscripts(matrix, 1) AS i) AS r, LATERAL (SELECT generate_subscripts(matrix, 2) AS j) AS c; - 或分两层LATERAL:
SELECT outer.idx AS row_num, inner.val AS cell FROM UNNEST(matrix) WITH ORDINALITY AS outer(subarr, idx), LATERAL UNNEST(outer.subarr) WITH ORDINALITY AS inner(val, col_idx); - 注意:第二层
UNNEST(outer.subarr)必须用LATERAL才能引用上层别名,否则报“subarr does not exist”
SELECT预览展开结果,而不是直接套INSERT。

















