使用Liquibase向PostgreSQL关联表导入CSV数据,如何关联父表ID?
解决PostgreSQL关联表通过Liquibase从CSV导入数据并关联父表ID的问题
核心思路是通过业务关联字段建立临时映射表,先将table1生成的ID与原CSV中的唯一业务标识绑定,再导入table2时通过该映射表匹配对应的父表ID,具体步骤如下:
1. 准备临时表与CSV导入
首先用Liquibase创建临时表,将CSV数据导入临时表(临时表无需ID字段,只需保留CSV中的业务字段,以及能关联table1和table2的唯一标识):
<changeSet id="import-temp-data" author="your-team"> <!-- 创建table1临时表 --> <createTable tableName="table1_temp"> <column name="field1" type="varchar"/> <column name="field2" type="varchar"/> </createTable> <!-- 导入table1的CSV数据 --> <loadData tableName="table1_temp" file="data/table1_data.csv" separator=","> <column name="field1"/> <column name="field2"/> </loadData> <!-- 创建table2临时表,需包含能关联table1的业务字段 --> <createTable tableName="table2_temp"> <column name="field1" type="varchar"/> <!-- 和table1的field1对应 --> <column name="field2" type="varchar"/> <!-- 和table1的field2对应 --> <column name="field3" type="varchar"/> </createTable> <!-- 导入table2的CSV数据 --> <loadData tableName="table2_temp" file="data/table2_data.csv" separator=","> <column name="field1"/> <column name="field2"/> <column name="field3"/> </loadData> </changeSet>
注:这里用
field1+field2作为table1的唯一业务标识,你可以替换成CSV中实际存在的、能唯一区分table1记录的字段(比如单独的业务编码)。
2. 插入table1并建立ID映射表
通过INSERT ... RETURNING将table1生成的ID与原业务标识存入临时映射表,后续table2导入时用这个映射表匹配父ID:
<changeSet id="insert-table1-and-create-map" author="your-team"> <sql> -- 创建临时映射表,存储业务标识与生成的table1 ID CREATE TEMP TABLE table1_id_map ( origin_field1 varchar, origin_field2 varchar, table1_id numeric ); -- 插入table1数据,同时将生成的ID和业务标识写入映射表 INSERT INTO table1 (id, field1, field2) SELECT nextval('table1_sequence'), field1, field2 FROM table1_temp RETURNING field1, field2, id INTO table1_id_map; </sql> </changeSet>
3. 插入table2并关联父表ID
通过JOIN映射表,将table2临时表中的业务标识对应到table1的ID,同时生成table2的自增ID:
<changeSet id="insert-table2-with-parent-id" author="your-team"> <sql> INSERT INTO table2 (id, table1_id, field3) SELECT nextval('table2_sequence'), m.table1_id, t.field3 FROM table2_temp t JOIN table1_id_map m ON t.field1 = m.origin_field1 AND t.field2 = m.origin_field2; </sql> <!-- 清理临时表 --> <dropTable tableName="table1_temp"/> <dropTable tableName="table2_temp"/> <sql>DROP TABLE table1_id_map;</sql> </changeSet>
关键注意事项
- 确保你选择的业务关联字段(比如
field1+field2)在table1中是唯一的,否则JOIN会出现重复匹配,导致table2数据错误。 - 序列名称要和数据库中实际的序列名一致(比如你的table1序列如果是
table1_id_seq,就替换nextval('table1_sequence')为nextval('table1_id_seq'))。 - 临时表仅在当前会话有效,清理步骤可根据需求调整,不影响数据库永久结构。
内容的提问来源于stack exchange,提问作者sticky_elbows
相关产品推荐
相关产品推荐

