PySpark向含Identity列的Delta表插入DataFrame报错求助
问题场景
创建包含自动生成Identity列的Delta表:
create table sample.table ( id bigint generated always as identity (start with 1 increment by 1), name string, address string ) using delta
使用PySpark写入时遇到两种错误:
- 当DataFrame排除
id列直接写入时,触发Schema不匹配错误:
AnalysisException: 写入Delta表时检测到架构不匹配(表ID: b83f1234-a178-486f-be53-2478cb4a1234)。要使用DataFrameWriter或DataStreamWriter启用架构迁移,请设置:'.option("mergeSchema", "true")'。对于其他操作,请设置会话配置spark.databricks.delta.schema.autoMerge.enabled为"true"。有关详细信息,请参阅特定操作的文档。
表架构:
root
-- id: long (nullable = false)
-- name: string (nullable = true)
-- address: string (nullable = true)
数据架构:
root
-- name: string (nullable = true)
-- address string (nullable = true)
要覆盖架构或更改分区,请设置:'.option("overwriteSchema", "true")'。
注意:使用'replaceWhere'时无法覆盖架构。
- 当手动添加
lit(None).alias("id")列时,触发不允许为Identity列赋值错误:
不支持向GENERATED ALWAYS AS IDENTITY列pk_part_current提供值。
解决方案
方法1:使用Spark SQL的INSERT INTO语句
将DataFrame注册为临时视图,通过SQL指定插入的列(排除Identity列),由Delta表自动生成ID值:
# 将DataFrame注册为临时视图 df.createOrReplaceTempView("temp_data") # 追加数据到表中 spark.sql("INSERT INTO sample.table (name, address) SELECT name, address FROM temp_data") # 若需覆盖表中现有数据(保留原表结构) spark.sql("INSERT OVERWRITE sample.table (name, address) SELECT name, address FROM temp_data")
方法2:使用insertInto方法写入
insertInto会根据列名自动匹配,忽略Identity列,由Delta表自动生成ID:
# 追加数据到现有表 df.write.mode("append").insertInto("sample.table") # 覆盖现有表的数据(保留原表架构) df.write.mode("overwrite").insertInto("sample.table")
错误原因说明
- 使用
saveAsTable+overwrite模式:该操作会尝试用DataFrame的架构重新创建表,与原表含Identity列的架构不匹配,因此报错。 - 手动添加
null值的Identity列:由于该列是GENERATED ALWAYS类型,Delta Lake禁止手动提供任何值(包括null),因此触发错误。
内容的提问来源于stack exchange,提问作者bwr

