Skip to main content

dbmerge logo

DBMerge is a Python library that provides a simplified interface for performing UPSERT (Insert/Update/Delete) operations.
Built on top of SQLAlchemy, it abstracts away engine-specific SQL MERGE or ON CONFLICT statements.

PyPI version Python versions

PostgreSQL MariaDB SQLite MS SQL CockroachDB

Overview

Common problems solved

  • Efficient bulk upsert with conflict resolution - Insert or update records in bulk without writing complex SQL. DBMerge automatically handles primary key conflicts: existing rows are updated, new rows are inserted.
  • Update rows only when values change - Automatically compares source data against the target table and skips writes for unchanged rows, reducing database load and I/O.
  • Materialize complex views - Persist results of heavy computations to a physical table for fast querying, supporting also partial data updates.

DBMerge accepts multiple data sources as input:

  • Pandas/Polars DataFrame
  • Lists of dictionaries / Dictionary of Lists
  • Database table or view

DBMerge automates data update process by comparing your source data against the target table and automatically performing the required operations.

  • Insert new records that do not exist in the target table.
  • Update existing records only if their values have changed.
  • Delete (or mark) existing records in the target table that are no longer present in the source data.

To ensure optimal performance, the library loads your data into a temporary table first, and then executes bulk synchronization queries.

Supported Databases

Tested and verified with:

  • PostgreSQL
  • MariaDB / MySQL
  • SQLite
  • MS SQL Server
  • CockroachDB

Installation

pip install dbmerge

Quick Start Example

The library uses a context manager to handle database connections and ensure resources are safely released.

from sqlalchemy import create_engine
from datetime import date
from dbmerge import dbmerge

# 1. Initialize DB engine
engine = create_engine("sqlite://")

# 2. Prepare your source data
data = [
    {'Shop': '123', 'Product': 'A1', 'Date': date(2025, 1, 1), 'Qty': 2, 'Price': 50.10},
    {'Shop': '124', 'Product': 'A1', 'Date': date(2025, 1, 1), 'Qty': 1, 'Price': 100.50}
]

# 3. Execute the merge operation
# The table will be created automatically if it doesn't exist.
with dbmerge(engine=engine, data=data, table_name="Facts", 
             key=['Shop', 'Product', 'Date']) as merge:
    result = merge.exec()

Key Features

  • Database Agnostic: Write your synchronization logic once and run it across different SQL databases without modifying the code.
  • High Performance: Uses temporary staging tables for fast bulk operations rather than slow row-by-row changes.
  • Smart Deletion: Supports scoped deletion. You can pass a SQLAlchemy logical expression to delete missing data only within a specific timeframe or subset (e.g., updating only a single month).
  • Auto-Schema Management: Automatically creates missing tables or columns in the database.
  • Audit: Optional parameters to automatically add merged_on and inserted_on timestamps to track when rows were created or modified.
  • Statistics: Measures number of updated/inserted/deleted rows, total time and time for each operation step.

Benchmark

DBMerge handles the entire reconciliation process (staging, comparing, updating, inserting) with solid performance, scaling well even for larger datasets.

Here is a rough performance comparison for synchronizing data of different sizes using DBMerge (measured on a standard developer laptop):

Database DBMerge (100k rows) DBMerge (1mil rows)
PostgreSQL ~2.0s ~19.8s
MySQL / MariaDB ~1.0s ~11.1s
SQLite ~0.7s ~7.6s
CockroachDB ~8.6s ~2m 49s
MS SQL Server* ~22.4s ~4m 23s

* Note: MS SQL Server bulk operations take longer due to inherent limitations in the pyodbc driver

Database-Specific Notes & Limitations

  • PostgreSQL:
    • Staging tables are real TEMPORARY tables, they are invisible to other connections and vanish with the session. temp_schema does not apply here and is quietly ignored — PostgreSQL keeps temporary tables in its own session schema.
    • JSONB type is supported, but not JSON (as it cannot be compared to detect changes).
  • MariaDB / MySQL:
    • Does not detect changes in uppercase vs. lowercase or space padding by default (e.g., 'test' == ' Test'). If this is important, you need to change the collation settings in your database.
    • The schema is treated the same as the database, but schema settings are still supported by this library.
    • A string column of the merge key needs an explicit length, because InnoDB shares one 3072-byte index budget between all columns of the key (e.g., data_types={'Your Key Field': String(100)}). Other string columns are created as LONGTEXT automatically.
    • Timezone-aware datetimes lose their UTC offset: no MySQL/MariaDB type stores one. Normalize to UTC before merging if the offset matters.
    • A BOOLEAN column is stored as TINYINT(1), so a delete_mark_field there holds 0/1 rather than False/True.
  • SQLite: Does not support schemas. If a schema setting is provided, it is automatically reset to None with a warning.
  • MS SQL Server: Bulk insert operations may have lower performance due to specific pyodbc driver limitations.
  • CockroachDB: Uses the official sqlalchemy-cockroachdb dialect (over psycopg2); speaks the PostgreSQL wire protocol.
    • exec(commit_all_steps=False) is noticeably faster here. On a single-node instance, merging 200 000 rows took ~6s against ~16s with the default, because one commit costs a consensus round regardless of how much it carries. The update phase showed no difference. It also makes the merge all-or-nothing; the trade-off is one larger transaction, which raises the chance of a serialization retry.
  • Oracle: Currently not supported (missing support for JOIN operations in UPDATE statements within the oracledb module).
  • DuckDB: Currently not supported (due to a bug in duckdb_engine regarding table definition loading).

Data Loss Risks

DBMerge modifies your target table in bulk, and three deliberate design trade-offs that may have negative effects on your data:

  • delete_mode='delete' without delete_condition treats the source as a complete snapshot (an empty source wipes the table).
  • automatic schema creation with default can_create_table=True and can_create_columns=True infers column types from a sample of your data.
  • default commit_all_steps=True commits each phase separately, so a failure leaves a partial result.

Read Data Loss Risks for the full list and the pre-merge checklist.

Documentation

Metadata

Release files for dbmerge 1.0.24

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dbmerge 1.0.24
File Size Uploaded
dbmerge-1.0.24.tar.gz 43.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dbmerge 1.0.24
File Interpreter ABI Platform
dbmerge-1.0.24-py3-none-any.whl Python 3 none any Details

Total release size: 70.6 kB

Release files / dbmerge-1.0.24.tar.gz

Download URL dbmerge-1.0.24.tar.gz
Size 43.3 kB
Tags Source
SHA-256 checksum
How to use checksums
b8e9e2a88f882203428a8f26206c4777b443635435bae23de5b18d3766aebe8e
BLAKE2b-256 checksum
How to use checksums
c26d089151b4e7eaa189ebadd021bbb3fa7a6c1c94ebc7c57cc51c0f32d8db6a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Release files / dbmerge-1.0.24-py3-none-any.whl

Download URL dbmerge-1.0.24-py3-none-any.whl
Size 27.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
adea3e0b04531e83378ac1597268161f5cad3966d5d8499fede6aaf1f8c4c6c7
BLAKE2b-256 checksum
How to use checksums
35787cba4ab43b96622ddc873112ff26b852eb7bed47a916a8661cb91d201588
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Release history Release notifications | RSS feed

This release

1.0.24 This release

2 release files

1.0.23

2 release files

1.0.22

2 release files

1.0.21

2 release files

1.0.19

2 release files

1.0.18

2 release files

1.0.14

2 release files

1.0.13

2 release files

1.0.12

2 release files

1.0.9

2 release files

1.0.8

2 release files

1.0.7

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page