{"id":40507277,"url":"https://github.com/yeongseon/excel-dbapi","last_synced_at":"2026-04-14T11:00:22.344Z","repository":{"id":285163902,"uuid":"957237212","full_name":"yeongseon/excel-dbapi","owner":"yeongseon","description":"PEP 249 (DB-API 2.0) compliant driver for querying Excel files with SQL","archived":false,"fork":false,"pushed_at":"2026-04-12T02:22:20.000Z","size":281,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-12T02:23:44.262Z","etag":null,"topics":["database","db-api","excel","openpyxl","pandas","pep249","python","sql"],"latest_commit_sha":null,"homepage":"https://github.com/yeongseon/excel-dbapi","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yeongseon.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"docs/ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-03-29T21:51:16.000Z","updated_at":"2026-04-12T02:22:27.000Z","dependencies_parsed_at":"2026-03-14T17:03:56.772Z","dependency_job_id":null,"html_url":"https://github.com/yeongseon/excel-dbapi","commit_stats":null,"previous_names":["yeongseon/exceldb"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/yeongseon/excel-dbapi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yeongseon%2Fexcel-dbapi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yeongseon%2Fexcel-dbapi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yeongseon%2Fexcel-dbapi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yeongseon%2Fexcel-dbapi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yeongseon","download_url":"https://codeload.github.com/yeongseon/excel-dbapi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yeongseon%2Fexcel-dbapi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31707954,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-12T06:22:27.080Z","status":"ssl_error","status_checked_at":"2026-04-12T06:21:52.710Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","db-api","excel","openpyxl","pandas","pep249","python","sql"],"created_at":"2026-01-20T19:41:14.293Z","updated_at":"2026-04-14T11:00:22.315Z","avatar_url":"https://github.com/yeongseon.png","language":"Python","readme":"\u003cp align=\"left\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/yeongseon/excel-dbapi/main/logo.svg\" alt=\"excel-dbapi\" width=\"48\" height=\"48\" align=\"middle\" /\u003e\n  \u003cstrong style=\"font-size: 2em;\"\u003eexcel-dbapi\u003c/strong\u003e\n\u003c/p\u003e\n\n![CI](https://github.com/yeongseon/excel-dbapi/actions/workflows/ci.yml/badge.svg)\n[![codecov](https://codecov.io/gh/yeongseon/excel-dbapi/branch/main/graph/badge.svg)](https://codecov.io/gh/yeongseon/excel-dbapi)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)\n\nA lightweight, Python DB-API 2.0 compliant connector for Excel files.\nUse SQL to query, insert, update, and delete rows in `.xlsx` workbooks — no database server required.\n\n## Who is this for?\n\n- **Data analysts** who want to query Excel files with SQL instead of manual filtering\n- **Citizen developers** automating small workflows with familiar SQL syntax\n- **Educators** teaching SQL concepts without setting up a database\n- **Prototypers** building quick data pipelines before moving to a real database\n\n### Who is this NOT for?\n\n- If you need JOINs, GROUP BY, subqueries, or advanced SQL → use SQLite or PostgreSQL\n- If you need concurrent writes from multiple processes → use a real database\n- If your Excel file has 100k+ rows → use pandas directly or a database\n\n---\n\n## Features\n\n- Python DB-API 2.0 compliant interface (PEP 249)\n- Query Excel files using SQL syntax\n- Supports SELECT, INSERT, UPDATE, DELETE\n- Basic DDL support (CREATE TABLE, DROP TABLE)\n- WHERE conditions with AND/OR and comparison operators\n- IN, BETWEEN, LIKE operators in WHERE clauses\n- ORDER BY and LIMIT for SELECT\n- Sheet-to-Table mapping\n- Pandas \u0026 Openpyxl engine selector\n- Formula injection defense (enabled by default)\n- Transaction simulation (commit/rollback)\n\n---\n\n## Installation\n\n```bash\npip install excel-dbapi\n```\n\nSee [CHANGELOG](CHANGELOG.md) for release history.\n\n---\n\n## Quick Start\n\n```python\nfrom excel_dbapi.connection import ExcelConnection\n\n# Open an Excel file and query it\nwith ExcelConnection(\"sample.xlsx\") as conn:\n    cursor = conn.cursor()\n    cursor.execute(\"SELECT * FROM Sheet1\")\n    print(cursor.fetchall())\n```\n\n### Insert, Update, Delete\n\n```python\nwith ExcelConnection(\"sample.xlsx\") as conn:\n    cursor = conn.cursor()\n\n    # Insert with parameter binding (recommended)\n    cursor.execute(\"INSERT INTO Sheet1 (id, name) VALUES (?, ?)\", (1, \"Alice\"))\n\n    # Update\n    cursor.execute(\"UPDATE Sheet1 SET name = 'Ann' WHERE id = 1\")\n\n    # Delete\n    cursor.execute(\"DELETE FROM Sheet1 WHERE id = 2\")\n```\n\n### Create and Drop Sheets\n\n```python\nwith ExcelConnection(\"sample.xlsx\") as conn:\n    cursor = conn.cursor()\n    cursor.execute(\"CREATE TABLE NewSheet (id, name)\")\n    cursor.execute(\"DROP TABLE NewSheet\")\n```\n\n### Engine Options\n\n| Engine | Description | Dependency |\n|--------|-------------|------------|\n| openpyxl (default) | Fast sheet access | openpyxl |\n| pandas | DataFrame-based operations | pandas, openpyxl |\n\n```python\nconn = ExcelConnection(\"sample.xlsx\", engine=\"openpyxl\")  # default\nconn = ExcelConnection(\"sample.xlsx\", engine=\"pandas\")\n```\n\n### WHERE Operators\n\n| Operator | Example | Description |\n|----------|---------|-------------|\n| `=`, `!=`, `\u003c\u003e` | `WHERE id = 1` | Equality / inequality |\n| `\u003e`, `\u003e=`, `\u003c`, `\u003c=` | `WHERE score \u003e= 80` | Comparison |\n| `IS NULL` / `IS NOT NULL` | `WHERE name IS NOT NULL` | NULL checks |\n| `IN` | `WHERE name IN ('Alice', 'Bob')` | Set membership |\n| `BETWEEN` | `WHERE score BETWEEN 70 AND 90` | Inclusive range |\n| `LIKE` | `WHERE name LIKE 'A%'` | Pattern matching |\n| `AND` / `OR` | `WHERE x = 1 AND y = 2` | Logical connectives |\n\n**LIKE patterns:** `%` matches any sequence of characters, `_` matches any single character.\n\n```python\nwith ExcelConnection(\"sample.xlsx\") as conn:\n    cursor = conn.cursor()\n\n    # IN operator\n    cursor.execute(\"SELECT * FROM Sheet1 WHERE name IN ('Alice', 'Bob')\")\n\n    # BETWEEN operator\n    cursor.execute(\"SELECT * FROM Sheet1 WHERE score BETWEEN 70 AND 90\")\n\n    # LIKE operator\n    cursor.execute(\"SELECT * FROM Sheet1 WHERE name LIKE 'A%'\")\n\n    # All operators support parameter binding\n    cursor.execute(\"SELECT * FROM Sheet1 WHERE name IN (?, ?)\", (\"Alice\", \"Bob\"))\n    cursor.execute(\"SELECT * FROM Sheet1 WHERE score BETWEEN ? AND ?\", (70, 90))\n    cursor.execute(\"SELECT * FROM Sheet1 WHERE name LIKE ?\", (\"A%\",))\n```\n\n---\n\n## Safety Defaults\n\n### Formula Injection Defense\n\nBy default, `excel-dbapi` sanitizes cell values on write (INSERT/UPDATE) to prevent\n[formula injection attacks](https://owasp.org/www-community/attacks/CSV_Injection).\nStrings starting with `=`, `+`, `-`, `@`, `\\t`, or `\\r` are automatically prefixed\nwith a single quote (`'`) so they are stored as plain text, not executed as formulas.\n\n```python\n# Default: sanitization ON (recommended)\nwith ExcelConnection(\"sample.xlsx\") as conn:\n    cursor = conn.cursor()\n    cursor.execute(\"INSERT INTO Sheet1 (id, name) VALUES (?, ?)\",\n                   (1, \"=SUM(A1:A10)\"))\n    # Stored as: '=SUM(A1:A10)  (safe, not executed as formula)\n\n# Opt out if you intentionally write formulas\nwith ExcelConnection(\"sample.xlsx\", sanitize_formulas=False) as conn:\n    cursor = conn.cursor()\n    cursor.execute(\"INSERT INTO Sheet1 (id, formula) VALUES (?, ?)\",\n                   (1, \"=SUM(A1:A10)\"))\n    # Stored as: =SUM(A1:A10)  (executed as formula in Excel)\n```\n\n---\n\n## Transaction Example\n\n```python\nwith ExcelConnection(\"sample.xlsx\", autocommit=False) as conn:\n    cursor = conn.cursor()\n    cursor.execute(\"UPDATE Sheet1 SET name = 'Ann' WHERE id = 1\")\n    conn.rollback()\n```\n\nWhen autocommit is enabled, `rollback()` is not supported.\n\n## Cursor Metadata\n\n```python\nwith ExcelConnection(\"sample.xlsx\") as conn:\n    cursor = conn.cursor()\n    cursor.execute(\"SELECT id, name FROM Sheet1\")\n    print(cursor.description)\n    print(cursor.rowcount)\n```\n\n---\n\n## Troubleshooting\n\n### \"Column 'xyz' not found\"\n\nThe column name in your SQL doesn't match any header in the sheet.\n\n```\nProgrammingError: Column 'nmae' not found in Sheet1. Available columns: ['id', 'name', 'email']\n```\n\n**Fix:** Check the spelling. Column names must match the first row (header) of the sheet exactly.\n\n### \"Table 'SheetX' not found\"\n\nThe sheet name in your SQL doesn't match any sheet in the workbook.\n\n```\nProgrammingError: Table 'Shee1' not found. Available sheets: ['Sheet1', 'Sheet2']\n```\n\n**Fix:** Check the sheet name spelling. Use the exact sheet name (case-sensitive) shown in your Excel file.\n\n### PandasEngine drops formatting\n\n`PandasEngine` reads data into a DataFrame and writes it back. This process drops\nExcel formatting, charts, images, and formulas.\n\n**Fix:** Use the default `openpyxl` engine if you need to preserve formatting.\n\n### Integer vs. string comparison (Pandas)\n\nThe Pandas engine preserves Python types. If a column contains integers,\n`WHERE id = '2'` (string) won't match — use `WHERE id = 2` (no quotes).\n\n**Fix:** Omit quotes around numeric values in WHERE clauses when using the Pandas engine.\n\n---\n\n## Limitations and Operational Guidance\n\n- `PandasEngine` rewrites workbooks and may drop formatting, charts, and formulas.\n- `OpenpyxlEngine` loads with `data_only=True`, so formulas are evaluated to values when reading.\n- Use a **single-writer model** for writes. Avoid writing to the same file from multiple processes.\n- Save is implemented with a temporary file + atomic replace (`os.replace`) for safer persistence.\n- No support for JOIN, GROUP BY, HAVING, or subqueries.\n\n## Roadmap\n\n- Remote file connection improvements\n\nSee [Project Roadmap](docs/ROADMAP.md) for details.\n\n---\n\n\n## Related Projects\n\n- [sqlalchemy-excel](https://github.com/yeongseon/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.\n---\n\n## Documentation\n\n- [Usage Guide](docs/USAGE.md)\n- [Development Guide](docs/DEVELOPMENT.md)\n- [Project Roadmap](docs/ROADMAP.md)\n- [10-Minute Quickstart](docs/QUICKSTART_10_MIN.md)\n- [Operations Notes](docs/OPERATIONS.md)\n- [Public Roadmap](docs/PUBLIC_ROADMAP.md)\n\n## Examples\n\n- `examples/basic_usage.py`\n- `examples/write_operations.py`\n- `examples/transactions.py`\n- `examples/advanced_query.py`\n- `examples/pandas_engine.py`\n\n---\n\n## License\n\nMIT License\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyeongseon%2Fexcel-dbapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyeongseon%2Fexcel-dbapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyeongseon%2Fexcel-dbapi/lists"}