使用Trino向PostgreSQL插入含Null值数据时遇io.trino.spi.type.IntegerType错误
问题:Trino读取Parquet插入PostgreSQL时Null值触发类型错误
报错与排查
执行插入操作时触发如下错误:
Query 20250413_125415_00070_tsd8v failed: io.trino.spi.type.IntegerType
经排查,问题出在user_id列的Null值,但PostgreSQL本身支持Null;即使将Trino中该列类型改为VARCHAR,仍会出现同类VARCHAR相关错误。
相关代码与数据
Trino外部表Schema
./trino --execute " CREATE SCHEMA IF NOT EXISTS minio.data WITH (location = 's3a://data/'); CREATE TABLE minio.data.main ( project_name VARCHAR, id_list ARRAY(INTEGER), user_id INTEGER ) WITH ( format = 'parquet', external_location = 's3a://data/' );"
PostgreSQL插入语句
./trino --execute " INSERT INTO postgres.public.data SELECT project_name, ARRAY_JOIN(id_list, ',') AS id_list, user_id --this column caused problem FROM minio.data.main;"
原始JSON样本
[ { "project_name": "Ring", "id_list": [ 1111, 2222, 3333 ], "user_id": 9999 }, { "project_name": "Square", "id_list": [ 11, 12 ], "user_id": null } ]
原因分析
- Trino表Schema与Parquet实际存储不匹配:JSON转Parquet时,包含Null的列会被标记为可空类型,但Trino创建外部表时显式声明
user_id INTEGER(默认非可空),导致Trino读取Parquet时类型校验失败。 - 类型转换的底层兼容性问题:即使修改为VARCHAR,若Parquet中该列的Null存储格式不符合Trino对VARCHAR类型的预期,同样会触发类型错误。
解决方法
1. 修正Trino表Schema,显式声明列可空
将user_id INTEGER改为user_id INTEGER NULL,重新创建外部表:
./trino --execute " CREATE SCHEMA IF NOT EXISTS minio.data WITH (location = 's3a://data/'); DROP TABLE IF EXISTS minio.data.main; -- 先删除原表 CREATE TABLE minio.data.main ( project_name VARCHAR, id_list ARRAY(INTEGER), user_id INTEGER NULL -- 显式标记该列允许Null ) WITH ( format = 'parquet', external_location = 's3a://data/' ); "
2. 验证Parquet文件的列类型
使用parquet-tools工具查看Parquet文件的实际schema,确认列的可空属性:
parquet-tools schema s3a://data/*.parquet
输出中若user_id列带有(nullable=true),则说明存储格式正确,只需调整Trino表Schema即可。
3. 修复JSON转Parquet的转换逻辑
确保转换工具(如Spark、Pandas)生成Parquet时正确处理可空列:
- 用Spark转换时,设置
spark.sql.parquet.writeLegacyFormat=false,避免旧格式导致的类型不兼容; - 用Pandas转换时,确保
user_id列的dtype为Int64(可空整数类型)而非int64(非可空)。
4. 插入时显式处理Null(可选)
如果仍有兼容性问题,可在SELECT语句中显式处理Null值,比如替换为业务允许的默认值:
./trino --execute " INSERT INTO postgres.public.data SELECT project_name, ARRAY_JOIN(id_list, ',') AS id_list, COALESCE(user_id, 0) AS user_id -- 用0替代Null,可根据业务需求调整 FROM minio.data.main;"
内容的提问来源于stack exchange,提问作者Prof.Plague
相关产品推荐
相关产品推荐

