Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Como upsert pandas DataFrame para a tabela do Microsoft SQL Server?


Existem duas opções:
  1. Use um MERGE instrução em vez de INSERT ... ON CONFLICT .
  2. Usar uma UPDATE instrução com um JOIN , seguido por um INSERT condicional .

A documentação T-SQL para MERGE diz:

Dica de desempenho:O comportamento condicional descrito para a instrução MERGE funciona melhor quando as duas tabelas têm uma mistura complexa de características correspondentes. Por exemplo, inserir uma linha se ela não existir ou atualizar uma linha se ela corresponder. Ao simplesmente atualizar uma tabela com base nas linhas de outra tabela, melhore o desempenho e a escalabilidade com instruções básicas INSERT, UPDATE e DELETE.

Em muitos casos é mais rápido e menos complicado simplesmente usar o UPDATE separado e INSERT declarações.
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')]