How to do an upsert with SqlAlchemy?

前端 未结 7 1492
别跟我提以往
别跟我提以往 2020-12-08 01:37

I have a record that I want to exist in the database if it is not there, and if it is there already (primary key exists) I want the fields to be updated to the current state

相关标签:
7条回答
  • 2020-12-08 02:28

    The below works fine for me with redshift database and will also work for combined primary key constraint.

    SOURCE : this

    Just few modifications required for creating SQLAlchemy engine in the function def start_engine()

    from sqlalchemy import Column, Integer, Date ,Metadata
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy.dialects.postgresql import insert
    from sqlalchemy import create_engine
    from sqlalchemy.orm import sessionmaker
    from sqlalchemy.dialects import postgresql
    
    Base = declarative_base()
    
    def start_engine():
        engine = create_engine(os.getenv('SQLALCHEMY_URI', 
        'postgresql://localhost:5432/upsert'))
         connect = engine.connect()
        meta = MetaData(bind=engine)
        meta.reflect(bind=engine)
        return engine
    
    
    class DigitalSpend(Base):
        __tablename__ = 'digital_spend'
        report_date = Column(Date, nullable=False)
        day = Column(Date, nullable=False, primary_key=True)
        impressions = Column(Integer)
        conversions = Column(Integer)
    
        def __repr__(self):
            return str([getattr(self, c.name, None) for c in self.__table__.c])
    
    
    def compile_query(query):
        compiler = query.compile if not hasattr(query, 'statement') else 
      query.statement.compile
        return compiler(dialect=postgresql.dialect())
    
    
    def upsert(session, model, rows, as_of_date_col='report_date', no_update_cols=[]):
        table = model.__table__
    
        stmt = insert(table).values(rows)
    
        update_cols = [c.name for c in table.c
                       if c not in list(table.primary_key.columns)
                       and c.name not in no_update_cols]
    
        on_conflict_stmt = stmt.on_conflict_do_update(
            index_elements=table.primary_key.columns,
            set_={k: getattr(stmt.excluded, k) for k in update_cols},
            index_where=(getattr(model, as_of_date_col) < getattr(stmt.excluded, as_of_date_col))
            )
    
        print(compile_query(on_conflict_stmt))
        session.execute(on_conflict_stmt)
    
    
    session = start_engine()
    upsert(session, DigitalSpend, initial_rows, no_update_cols=['conversions'])
    
    0 讨论(0)
提交回复
热议问题