You might also consider something like this:
- create transaction
- rename old table to tempy table
- df to sql fail
- insert data from old table
- drop tempy table
- commit transaction
note that this way will fail when you remove columns while the pd.concat option will merge the schema
also this will probably only work in databases which support transactional DDL https://wiki.postgresql.org/wiki/Transactional_DDL_in_PostgreSQL:_A_Competitive_Analysis
dependency: https://github.com/rvkulikov/pg-deps-management
import sqlalchemy
from sqlalchemy import text, sql
try:
df.to_sql(
table_name,
con=engine,
if_exists="append",
index=False,
chunksize=70,
method="multi",
)
except:
auto_add_new_columns(engine, table_name, df)
finally:
print("Finished updating db")
def auto_add_new_columns(engine, table_name, df, schema="public"):
with engine.connect() as conn:
with conn.begin() as transaction:
md = sqlalchemy.MetaData()
table = sqlalchemy.Table(table_name, md, autoload=True, autoload_with=conn)
conn.execute(
f"select deps_save_and_drop_dependencies('{schema}', '{table}')"
)
conn.execute(
text(
"alter table "
+ sql.quoted_name(table_name, quote=False)
+ " rename to "
+ sql.quoted_name(table_name + "_backup", quote=False)
)
)
df.to_sql(
table_name,
con=conn,
if_exists="fail",
index=False,
chunksize=70,
method="multi",
)
cols_list = [column.key for column in table.columns]
conn.execute(
text(
"insert into "
+ sql.quoted_name(table_name, quote=False)
+ f" ({','.join(cols_list)}) "
+ " select "
+ f" {','.join(cols_list)} "
+ "from "
+ sql.quoted_name(table_name + "_backup", quote=False)
)
)
conn.execute(
text(
"drop table " + sql.quoted_name(table_name + "_backup", quote=False)
)
)
conn.execute(f"select deps_restore_dependencies('{schema}', '{table}')")
transaction.commit()
or perhaps a better way would be to make a map between postgres and sqlalchemy types then zip together and run DDL commands