UNNEST 是 PostgreSQL、BigQuery、Trino、Snowflake 等支持的数组展开函数,用于将 ARRAY 类型转为多行;MySQL、SQL Server、SQLite 不原生支持,Oracle 用 TABLE() 模拟。

UNNEST 是什么,哪些数据库支持
UNNEST 不是 SQL 标准函数,而是 PostgreSQL、BigQuery、Trino(Presto)、Snowflake 等现代分析型数据库提供的扩展函数,用于将数组(ARRAY 类型)“展开”成多行。MySQL、SQL Server、SQLite 原生不支持 UNNEST;Oracle 用 TABLE() 模拟类似行为,但语法和语义不同。
- PostgreSQL:原生支持,最常用,
UNNEST可单独使用或与JOIN配合 - BigQuery:支持
UNNEST,但必须出现在FROM子句中(不能像 PostgreSQL 那样直接在SELECT里用) - Snowflake:支持,但要求数组字段为
VARIANT或ARRAY类型,且需配合LATERAL或直接JOIN
PostgreSQL 中 UNNEST 的基本用法和常见错误
PostgreSQL 允许把 UNNEST 当作集合返回函数,在 SELECT 或 FROM 中使用。最容易踩的坑是忽略“行数对齐”规则:多个 UNNEST 并列时,长度不一致会自动补 NULL,而不是报错。
- 如果只展开一个数组,直接写
UNNEST(array_column)即可 - 多个数组并列展开(如
UNNEST(arr1, arr2)),它们会被按索引位置配对,短数组末尾补NULL - 用
UNNEST展开时,原表的其他字段不会自动复制到结果中——必须显式JOIN或用LATERAL
SELECT id, elem FROM users, LATERAL UNNEST(hobbies) AS elem;
上面这段等价于:
SELECT id, unnest(hobbies) AS elem FROM users;
但后者在较新版本中已被标记为“不推荐”,因为隐式逗号 JOIN 易引发歧义。
BigQuery 中 UNNEST 必须嵌套在 FROM,且不能单独 SELECT
BigQuery 强制要求 UNNEST 出现在 FROM 子句,并且只能作用于重复字段(REPEATED)或 ARRAY 类型列。你不能写 SELECT UNNEST(my_array) —— 这会报错:Function not found: UNNEST(如果上下文不对)或更具体的 UNNEST operator must be used in FROM clause。
- 正确写法必须带别名,且用
CROSS JOIN或隐式逗号连接 - 若数组为空或为
NULL,默认该行被丢弃;加LEFT JOIN可保留空数组对应行(BigQuery 支持LEFT JOIN UNNEST)
SELECT user_id, hobby FROM `project.dataset.users` CROSS JOIN UNNEST(hobbies) AS hobby;
若想保留 hobbies 为 NULL 或空数组的用户记录:
SELECT user_id, hobby FROM `project.dataset.users` LEFT JOIN UNNEST(hobbies) AS hobby;
UNNEST 性能与数据倾斜风险
UNNEST 本质是爆炸操作(exploding operation),会显著增加中间行数。比如 100 行数据,每行 hobbies 平均含 5 项,UNNEST 后变成约 500 行——这会影响后续聚合、JOIN 和内存占用。
- 数组长度差异极大时(例如有的含 1 项,有的含 10000 项),容易触发单节点 OOM 或严重数据倾斜
- PostgreSQL 中,大数组建议配合
LIMIT或先过滤再展开;BigQuery 中可考虑用ARRAY_LENGTH预筛 - 避免在
WHERE条件里对UNNEST结果做复杂计算(如嵌套函数调用),应尽量下推到展开前
-- ❌ 不推荐:先展开再过滤,可能爆炸后才裁剪 SELECT * FROM t, UNNEST(tags) AS tag WHERE LENGTH(tag) > 10; <p>-- ✅ 推荐:先限制数组长度,再展开 SELECT * FROM t WHERE ARRAY_LENGTH(tags, 1) 10;</p>
真正难处理的是嵌套数组深度超过 2 层,或者需要同时展开多个层级——这时候得靠递归 CTE(PostgreSQL)或自定义 UDF(BigQuery),UNNEST 本身不支持递归展开。










