Има две опции:
- Използвайте
MERGE
изявление вместоINSERT ... ON CONFLICT
. - Използвайте
UPDATE
изявление сJOIN
, последвано от условенINSERT
.
Документацията на T-SQL за MERGE казва:
Съвет за производителност:Условното поведение, описано за оператора MERGE, работи най-добре, когато двете таблици имат сложна смес от съвпадащи характеристики. Например вмъкване на ред, ако не съществува, или актуализиране на ред, ако съвпада. Когато просто актуализирате една таблица въз основа на редовете на друга таблица, подобрете производителността и мащабируемостта с основни изрази INSERT, UPDATE и DELETE.
В много случаи е по-бързо и по-малко сложно просто да използвате отделния UPDATE
и INSERT
изявления.
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')]