PEP 249 compliant DB-API driver for Excel files
Project description
excel-dbapi
A local-first Python DB-API 2.0 connector for Excel files.
Use SQL to query, insert, update, and delete rows in .xlsx workbooks — no database server required.
Limitations
Before you begin, understand what excel-dbapi is not:
- No JOIN, GROUP BY, HAVING, DISTINCT, or subqueries — single-table operations only
- No concurrent writes — use a single-writer model
- Not for large datasets — if your Excel file has 100k+ rows, use pandas directly or a database
- No transactional rollback guarantees — rollback restores an in-memory snapshot, not a WAL
- PandasEngine rewrites workbooks — formatting, charts, images, and formulas are dropped
If you need relational features, use SQLite or PostgreSQL.
See the full SQL Specification for the exact SQL subset supported.
Who is this for?
- Data analysts who want to query Excel files with SQL instead of manual filtering
- Citizen developers automating small workflows with familiar SQL syntax
- Educators teaching SQL concepts without setting up a database
- Prototypers building quick data pipelines before moving to a real database
Installation
pip install excel-dbapi
See CHANGELOG for release history.
Quick Start
from excel_dbapi.connection import ExcelConnection
# Open an Excel file and query it
with ExcelConnection("sample.xlsx") as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM Sheet1")
print(cursor.fetchall())
Insert, Update, Delete
with ExcelConnection("sample.xlsx") as conn:
cursor = conn.cursor()
# Insert with parameter binding (recommended)
cursor.execute("INSERT INTO Sheet1 (id, name) VALUES (?, ?)", (1, "Alice"))
# Update
cursor.execute("UPDATE Sheet1 SET name = 'Ann' WHERE id = 1")
# Delete
cursor.execute("DELETE FROM Sheet1 WHERE id = 2")
Create and Drop Sheets
with ExcelConnection("sample.xlsx") as conn:
cursor = conn.cursor()
cursor.execute("CREATE TABLE NewSheet (id, name)")
cursor.execute("DROP TABLE NewSheet")
Engine Options
| Engine | Description | Dependency |
|---|---|---|
| openpyxl (default) | Fast sheet access | openpyxl |
| pandas | DataFrame-based operations | pandas, openpyxl |
conn = ExcelConnection("sample.xlsx", engine="openpyxl") # default
conn = ExcelConnection("sample.xlsx", engine="pandas")
WHERE Operators
| Operator | Example | Description |
|---|---|---|
=, !=, <> |
WHERE id = 1 |
Equality / inequality |
>, >=, <, <= |
WHERE score >= 80 |
Comparison |
IS NULL / IS NOT NULL |
WHERE name IS NOT NULL |
NULL checks |
IN |
WHERE name IN ('Alice', 'Bob') |
Set membership |
BETWEEN |
WHERE score BETWEEN 70 AND 90 |
Inclusive range |
LIKE |
WHERE name LIKE 'A%' |
Pattern matching |
AND / OR |
WHERE x = 1 AND y = 2 |
Logical connectives |
LIKE patterns: % matches any sequence of characters, _ matches any single character.
with ExcelConnection("sample.xlsx") as conn:
cursor = conn.cursor()
# IN operator
cursor.execute("SELECT * FROM Sheet1 WHERE name IN ('Alice', 'Bob')")
# BETWEEN operator
cursor.execute("SELECT * FROM Sheet1 WHERE score BETWEEN 70 AND 90")
# LIKE operator
cursor.execute("SELECT * FROM Sheet1 WHERE name LIKE 'A%'")
# All operators support parameter binding
cursor.execute("SELECT * FROM Sheet1 WHERE name IN (?, ?)", ("Alice", "Bob"))
cursor.execute("SELECT * FROM Sheet1 WHERE score BETWEEN ? AND ?", (70, 90))
cursor.execute("SELECT * FROM Sheet1 WHERE name LIKE ?", ("A%",))
Safety Defaults
Formula Injection Defense
By default, excel-dbapi sanitizes cell values on write (INSERT/UPDATE) to prevent
formula injection attacks.
Strings starting with =, +, -, @, \t, or \r are automatically prefixed
with a single quote (') so they are stored as plain text, not executed as formulas.
# Default: sanitization ON (recommended)
with ExcelConnection("sample.xlsx") as conn:
cursor = conn.cursor()
cursor.execute("INSERT INTO Sheet1 (id, name) VALUES (?, ?)",
(1, "=SUM(A1:A10)"))
# Stored as: '=SUM(A1:A10) (safe, not executed as formula)
# Opt out if you intentionally write formulas
with ExcelConnection("sample.xlsx", sanitize_formulas=False) as conn:
cursor = conn.cursor()
cursor.execute("INSERT INTO Sheet1 (id, formula) VALUES (?, ?)",
(1, "=SUM(A1:A10)"))
# Stored as: =SUM(A1:A10) (executed as formula in Excel)
Transaction Example
with ExcelConnection("sample.xlsx", autocommit=False) as conn:
cursor = conn.cursor()
cursor.execute("UPDATE Sheet1 SET name = 'Ann' WHERE id = 1")
conn.rollback()
When autocommit is enabled, rollback() is not supported.
Cursor Metadata
with ExcelConnection("sample.xlsx") as conn:
cursor = conn.cursor()
cursor.execute("SELECT id, name FROM Sheet1")
print(cursor.description)
print(cursor.rowcount)
Troubleshooting
"Column 'xyz' not found"
The column name in your SQL doesn't match any header in the sheet.
ProgrammingError: Column 'nmae' not found in Sheet1. Available columns: ['id', 'name', 'email']
Fix: Check the spelling. Column names must match the first row (header) of the sheet exactly.
"Table 'SheetX' not found"
The sheet name in your SQL doesn't match any sheet in the workbook.
ProgrammingError: Table 'Shee1' not found. Available sheets: ['Sheet1', 'Sheet2']
Fix: Check the sheet name spelling. Use the exact sheet name (case-sensitive) shown in your Excel file.
PandasEngine drops formatting
PandasEngine reads data into a DataFrame and writes it back. This process drops
Excel formatting, charts, images, and formulas.
Fix: Use the default openpyxl engine if you need to preserve formatting.
Integer vs. string comparison (Pandas)
The Pandas engine preserves Python types. If a column contains integers,
WHERE id = '2' (string) won't match — use WHERE id = 2 (no quotes).
Fix: Omit quotes around numeric values in WHERE clauses when using the Pandas engine.
Experimental: Remote Excel via Microsoft Graph API
Status: Experimental — API may change in future releases.
excel-dbapi can access remote Excel files on OneDrive/SharePoint via the Microsoft Graph API.
pip install excel-dbapi[graph]
from excel_dbapi.connection import ExcelConnection
conn = ExcelConnection(
"msgraph://drives/{drive_id}/items/{item_id}",
engine="graph",
credential=your_credential,
autocommit=True,
)
cursor = conn.cursor()
cursor.execute("SELECT * FROM Sheet1")
print(cursor.fetchall())
conn.close()
The Graph backend is read-only by default. Write operations require explicit opt-in and a valid Azure credential with appropriate Graph API permissions.
For details, see the Usage Guide.
Related Projects
- sqlalchemy-excel — SQLAlchemy dialect that uses excel-dbapi as its DB-API 2.0 driver. Use
create_engine("excel:///file.xlsx")for full ORM support.
Documentation
- SQL Specification
- Usage Guide
- Development Guide
- Project Roadmap
- 10-Minute Quickstart
- Operations Notes
Examples
examples/basic_usage.pyexamples/write_operations.pyexamples/transactions.pyexamples/advanced_query.pyexamples/pandas_engine.py
License
MIT License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file excel_dbapi-0.4.0.tar.gz.
File metadata
- Download URL: excel_dbapi-0.4.0.tar.gz
- Upload date:
- Size: 94.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6495fc22935c8d3cc39e30365d92494ae2a80c2e6dc3b838e1e267ca1e4ec01e
|
|
| MD5 |
5396e7ff5261c4d04a9ef665b1b7098e
|
|
| BLAKE2b-256 |
b107b68ef9195cc1b89b16344f922c63f8db81e8bb657697a21e1703d48d22cc
|
Provenance
The following attestation bundles were made for excel_dbapi-0.4.0.tar.gz:
Publisher:
publish-pypi.yml on yeongseon/excel-dbapi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
excel_dbapi-0.4.0.tar.gz -
Subject digest:
6495fc22935c8d3cc39e30365d92494ae2a80c2e6dc3b838e1e267ca1e4ec01e - Sigstore transparency entry: 1293630065
- Sigstore integration time:
-
Permalink:
yeongseon/excel-dbapi@e35bcd22326e3c4aee66d8f99e6a5b7ebfea9c95 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/yeongseon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@e35bcd22326e3c4aee66d8f99e6a5b7ebfea9c95 -
Trigger Event:
release
-
Statement type:
File details
Details for the file excel_dbapi-0.4.0-py3-none-any.whl.
File metadata
- Download URL: excel_dbapi-0.4.0-py3-none-any.whl
- Upload date:
- Size: 43.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
876a1d73cd502b01301c172746091813c0027c8422dd73387ec6d0c6c95b350f
|
|
| MD5 |
225631089ab4ad5f8d57560b5d052744
|
|
| BLAKE2b-256 |
c5a8dc544d79ab7a29d038df6eb3bbf41abf7d33b388bacf2a19df084beee01c
|
Provenance
The following attestation bundles were made for excel_dbapi-0.4.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on yeongseon/excel-dbapi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
excel_dbapi-0.4.0-py3-none-any.whl -
Subject digest:
876a1d73cd502b01301c172746091813c0027c8422dd73387ec6d0c6c95b350f - Sigstore transparency entry: 1293630078
- Sigstore integration time:
-
Permalink:
yeongseon/excel-dbapi@e35bcd22326e3c4aee66d8f99e6a5b7ebfea9c95 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/yeongseon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@e35bcd22326e3c4aee66d8f99e6a5b7ebfea9c95 -
Trigger Event:
release
-
Statement type: