DuckDB 0.7.1加载嵌套JSON时Struct数组类型报错求助
解决DuckDB导入嵌套JSON时Struct数组报错及分表方案
核心问题排查
你遇到的Unsupported result column Struct()[]错误,大概率是手动声明Schema时Struct数组的语法格式错误,或者JSON结构与Schema定义不匹配导致的。DuckDB对Struct数组的正确格式要求是ARRAY<STRUCT<字段名: 数据类型, ...>>,而非其他写法。
分步解决方案
1. 先确认JSON统一结构
先通过json_structure确认所有25000个文件的JSON结构是否一致,避免因个别文件结构差异导致导入失败:
SELECT json_structure(read_json('你的JSON文件路径/*.json'));
根据返回的结构结果,精准定义后续的Schema。
2. 正确导入嵌套JSON(两种方式)
方式一:自动推断Schema(推荐)
让DuckDB自动识别JSON结构,避免手动写Schema出错:
-- 创建临时表存储原始JSON数据 CREATE TABLE raw_replays AS SELECT * FROM read_json( '你的JSON文件路径/*.json', auto_detect=true, ignore_errors=true -- 可选:跳过结构异常的文件 );
导入后可以用DESCRIBE raw_replays;查看自动推断的Schema,确认Struct数组类型是否正确识别。
方式二:手动指定正确的Schema
如果自动推断不符合预期,按照ARRAY<STRUCT<...>>的格式手动编写Schema:
CREATE TABLE raw_replays AS SELECT * FROM read_json( '你的JSON文件路径/*.json', schema='''{ "ReplayID": VARCHAR, "GameMode": VARCHAR, "MapID": INTEGER, "Players": ARRAY<STRUCT< "PlayerID": VARCHAR, "TeamID": INTEGER, "HeroID": VARCHAR, "Talents": ARRAY<STRUCT< "TalentID": VARCHAR, "Level": INTEGER >> >>, "Draft": ARRAY<STRUCT< "PickOrder": INTEGER, "HeroID": VARCHAR, "Team": VARCHAR >> -- 其他字段按json_structure结果补充 }''' );
注意:Schema字符串要用三重引号包裹,避免内部引号冲突;字段名和类型要与JSON结构完全匹配(包括大小写)。
3. 拆分出目标表
导入完成后,通过UNNEST操作拆分嵌套数组,生成Replay、ReplayPlayers、PlayerTalents等表:
① 生成Replay主表(非嵌套字段)
CREATE TABLE Replay AS SELECT ReplayID, GameMode, MapID, GameDuration, -- 所有顶层非数组、非嵌套字段 FROM raw_replays;
② 生成ReplayPlayers表(展开Players数组)
CREATE TABLE ReplayPlayers AS SELECT r.ReplayID, p.PlayerID, p.TeamID, p.HeroID, p.IsWinner, -- Players结构体中的其他字段 FROM raw_replays r, UNNEST(r.Players) p;
③ 生成PlayerTalents表(展开Players里的Talents数组)
CREATE TABLE PlayerTalents AS SELECT r.ReplayID, p.PlayerID, t.TalentID, t.Level, t.SelectedTime, -- Talents结构体中的其他字段 FROM raw_replays r, UNNEST(r.Players) p, UNNEST(p.Talents) t;
4. 解决from_json测试失败问题
如果单独用from_json解析Struct数组失败,检查以下两点:
- 确保Schema字符串格式正确:比如
'ARRAY<STRUCT<PickOrder: INTEGER, HeroID: VARCHAR>>' - 确保待解析的JSON字符串没有格式错误(比如缺失字段、类型不匹配)
测试示例:
-- 取一条数据测试from_json SELECT from_json( Draft, 'ARRAY<STRUCT<PickOrder: INTEGER, HeroID: VARCHAR, Team: VARCHAR>>' ) FROM raw_replays LIMIT 1;
内容的提问来源于stack exchange,提问作者Mitchell Hamann
相关产品推荐
相关产品推荐

