如何用Pandas和SQLAlchemy导入Excel实现PostgreSQL一对多数据插入?
解决PostgreSQL一对多关系的批量插入问题
针对你遇到的一对多数据插入需求,这里提供两种可行方案,根据数据量大小选择即可:
方案一:逐行ORM插入(适合小数据量)
直接利用SQLAlchemy的ORM会话,逐行处理Excel数据,插入Body后立即获取ID,再关联插入标签。这种方式逻辑简单,不需要依赖额外唯一标识,适合数据量不大的场景。
假设你的SQLAlchemy模型如下(和你已配置的一致):
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship Base = declarative_base() class Body(Base): __tablename__ = 'body' id = Column(Integer, primary_key=True, autoincrement=True) body = Column(String) add_date = Column(DateTime) tags = relationship("BodyTags", back_populates="body") class BodyTags(Base): __tablename__ = 'body_tags' id = Column(Integer, primary_key=True, autoincrement=True) body_id = Column(Integer, ForeignKey('body.id')) tag = Column(String) body = relationship("Body", back_populates="tags")
处理代码:
import pandas as pd from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker # 初始化数据库连接 engine = create_engine('postgresql://用户名:密码@主机:端口/数据库名') Session = sessionmaker(bind=engine) session = Session() # 读取Excel数据 df = pd.read_excel('你的文件.xlsx') # 遍历每一行数据 for _, row in df.iterrows(): # 创建Body对象并提交,获取自动生成的ID new_body = Body(body=row['body'], add_date=row['add_date']) session.add(new_body) session.commit() # 处理三个标签,跳过空值 for tag_col in ['tag1', 'tag2', 'tag3']: tag_value = row[tag_col] if pd.notna(tag_value): new_tag = BodyTags(body_id=new_body.id, tag=tag_value) session.add(new_tag) session.commit() session.close()
方案二:批量插入后关联ID(适合大数据量)
如果数据量较大,逐行插入效率低,可以先批量插入Body表,再通过唯一字段关联获取ID,最后批量插入标签表。这种方式效率更高,但需要保证Body表有能匹配原数据的唯一标识(比如body+add_date的组合)。
处理代码:
import pandas as pd from sqlalchemy import create_engine # 初始化数据库连接 engine = create_engine('postgresql://用户名:密码@主机:端口/数据库名') # 读取Excel数据 df = pd.read_excel('你的文件.xlsx') # 1. 批量插入Body表 body_data = df[['body', 'add_date']].copy() body_data.to_sql('body', engine, if_exists='append', index=False) # 2. 查询已插入的Body数据,关联原DataFrame获取对应ID # 假设body+add_date是唯一组合,能精准匹配 inserted_bodies = pd.read_sql("SELECT id, body, add_date FROM body", engine) merged_df = pd.merge(df, inserted_bodies, on=['body', 'add_date'], how='left') # 3. 构造标签数据并批量插入 tag_records = [] for _, row in merged_df.iterrows(): body_id = row['id'] # 遍历三个标签列,收集非空标签 for col in ['tag1', 'tag2', 'tag3']: tag = row[col] if pd.notna(tag): tag_records.append({'body_id': body_id, 'tag': tag}) tag_df = pd.DataFrame(tag_records) tag_df.to_sql('body_tags', engine, if_exists='append', index=False)
注意事项
- 如果
body+add_date不是唯一组合,可以在插入Body时额外保留原Excel的行号(比如新增row_num列),查询后通过行号关联ID。 - 批量操作时建议加上事务控制,避免部分插入失败导致数据不一致,可以用
with engine.begin() as conn:来管理事务。
内容的提问来源于stack exchange,提问作者uncrayon
相关产品推荐
相关产品推荐

