How to upsert pandas DataFrame to Microsoft SQL Server table?

后端 未结 1 1939
孤独总比滥情好
孤独总比滥情好 2020-12-04 03:56

I would like to upsert my pandas DataFrame into a SQL Server table. This question has a workable solution for PostgreSQL, but T-SQL does not have an ON CONFLICT

相关标签:
1条回答
  • 2020-12-04 04:47

    There are two options:

    1. Use a MERGE statement instead of INSERT ... ON CONFLICT.
    2. Use an UPDATE statement with a JOIN, followed by a conditional INSERT.

    The T-SQL documentation for MERGE says:

    Performance Tip: The conditional behavior described for the MERGE statement works best when the two tables have a complex mixture of matching characteristics. For example, inserting a row if it doesn't exist, or updating a row if it matches. When simply updating one table based on the rows of another table, improve the performance and scalability with basic INSERT, UPDATE, and DELETE statements.

    In many cases it is faster and less complicated to simply use the separate UPDATE and INSERT statements.

    engine = sa.create_engine(
        connection_uri, fast_executemany=True, isolation_level="SERIALIZABLE"
    )
    
    with engine.begin() as conn:
        # step 0.0 - create test environment
        conn.execute(sa.text("DROP TABLE IF EXISTS main_table"))
        conn.execute(
            sa.text(
                "CREATE TABLE main_table (id int primary key, txt varchar(50))"
            )
        )
        conn.execute(
            sa.text(
                "INSERT INTO main_table (id, txt) VALUES (1, 'row 1 old text')"
            )
        )
        # step 0.1 - create DataFrame to UPSERT
        df = pd.DataFrame(
            [(2, "new row 2 text"), (1, "row 1 new text")], columns=["id", "txt"]
        )
    
        # step 1 - upload DataFrame to temporary table
        df.to_sql("#temp_table", conn, index=False, if_exists="replace")
    
        # step 2 - merge temp_table into main_table
        conn.execute(
            sa.text("""\
                UPDATE main SET main.txt = temp.txt
                FROM main_table main INNER JOIN #temp_table temp
                    ON main.id = temp.id
                """
            )
        )
        conn.execute(
            sa.text("""\
                INSERT INTO main_table (id, txt) 
                SELECT id, txt FROM #temp_table
                WHERE id NOT IN (SELECT id FROM main_table) 
                """
            )
        )
    
        # step 3 - confirm results
        result = conn.execute(sa.text("SELECT * FROM main_table ORDER BY id")).fetchall()
        print(result)  # [(1, 'row 1 new text'), (2, 'new row 2 text')]
    
    0 讨论(0)
提交回复
热议问题