Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Come eseguire l'upsert dei panda DataFrame nella tabella di Microsoft SQL Server?

Ci sono due opzioni:

  1. Utilizza un MERGE istruzione invece di INSERT ... ON CONFLICT .
  2. Utilizza un UPDATE dichiarazione con un JOIN , seguito da un condizionale INSERT .

La documentazione T-SQL per MERGE dice:

Suggerimento per le prestazioni:il comportamento condizionale descritto per l'istruzione MERGE funziona meglio quando le due tabelle hanno una combinazione complessa di caratteristiche corrispondenti. Ad esempio, inserendo una riga se non esiste o aggiornando una riga se corrisponde. Quando aggiorni semplicemente una tabella in base alle righe di un'altra tabella, migliora le prestazioni e la scalabilità con le istruzioni INSERT, UPDATE e DELETE di base.

In molti casi è più veloce e meno complicato usare semplicemente il separato UPDATE e INSERT dichiarazioni.

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')]