Query Excel Files with SQL in Your Browser

Load an .xlsx file and run SQL queries across all sheets using DuckDB-WASM. Each sheet becomes a separate table, with no install or upload required.

ZERO UPLOAD · ALL LOCAL
  1. Drop a file onto the drop zone — or click it to browse. Supported: Parquet, Arrow, Feather, CSV, TSV, JSON, NDJSON, Avro, DBF, Excel (.xlsx), SQLite (.db/.sqlite).
  2. The query engine pre-loads in the background (~2 MB, one-time per session). Your file is indexed immediately after.
  3. Browse the schema accordion to see tables and column types.
  4. Type a SQL query in the editor and click Run Query.
  5. Results appear in the grid below. Click Export, then choose CSV, JSON, Excel, or Parquet to download the full result set.

These examples show the query only. Load a matching data file first, then use Load into tool to try it.

Worked examples for this use case

List all available sheet names as tables

Example
SHOW TABLES;

Returns all sheet names loaded from the workbook. Each name is a queryable table.

Join two sheets on a common column

Example
SELECT o.order_id,
       o.quantity,
       p.product_name,
       p.unit_price
FROM Orders o
JOIN Products p ON o.product_id = p.id;

Multiple sheets from the same workbook are available simultaneously as separate tables.

Find the top customers by total spend

Example
SELECT customer_name,
       SUM(amount) AS total_spend
FROM Orders
GROUP BY customer_name
ORDER BY total_spend DESC
LIMIT 10;

DuckDB sums across all rows in the sheet — no pivot table required.

Check for duplicate IDs in a sheet

Example
SELECT id, COUNT(*) AS n
FROM Products
GROUP BY id
HAVING COUNT(*) > 1;

Returns only rows where the id value appears more than once — a fast data quality check.

Zero upload guarantee

Your database file never leaves this device. DuckDB runs locally via WebAssembly — no server, no account, no logs.

Drop a file here — Parquet, CSV, JSON, Excel, Arrow, and more

or click to select · .parquet · .csv · .json · .xlsx · .arrow · .feather · .tsv · .ndjson · .avro · .dbf · .db · .sqlite

Loading DuckDB engine…

SCHEMA

Running query…

RESULTS

Query Excel Files with SQL in Your Browser

An .xlsx workbook often arrives as the final stop before a messy export. The SQL Workbench converts every sheet in that workbook into a separate DuckDB table, named after the sheet tab, so you can query Sheet1 and Summary in the same session and JOIN them without copy-paste formulas.1

Excel as a data source: where it fits and where it struggles

Excel workbooks carry data in a format that every business user understands, which is exactly why they appear in so many pipelines: stakeholders paste updates into a shared sheet, analysts download reports from SaaS platforms as .xlsx, and finance teams maintain ledgers that never migrate to a database. Yet Excel has limits that SQL does not. Formula cells can hide calculation errors, merged cells break tabular structure, and workbooks with hundreds of thousands of rows become slow to navigate. Because the workbench loads the raw cell values into DuckDB tables, you bypass all of those issues. Each sheet becomes a plain table. Formula results appear as their computed values.2 You run SQL against the data, not against the spreadsheet machinery.

How the workbench loads Excel files

Excel files pass through a JavaScript parser that reads the modern XML-based .xlsx format.1 Each sheet in the workbook becomes a DuckDB table named after the sheet tab.3 Column headers come from the first row, and a workbook with sheets named Orders, Products, and Returns produces three tables: Orders, Products, and Returns.

Excel types after parsing

The parser infers column types from the cell values: numeric cells become DOUBLE, date cells become VARCHAR (Excel date serial numbers are converted to ISO strings), and text cells become VARCHAR.3 After parsing, the workbench hands every table to DuckDB, so you query them with the same SQL as any other file format. Parquet export is available for Excel-derived tables because they are loaded into DuckDB rather than sql.js, which means your exported file preserves column types exactly.

Because every column resolves to a single DuckDB type, a column that mixes numbers and text lands as VARCHAR to avoid dropping values, which is why a price column with a stray note becomes text instead of DOUBLE. Cast such columns in the query rather than trusting the preview type, and review the SHOW TABLES output before writing JOINs so a type mismatch does not filter your rows out silently.

Multi-sheet queries and practical patterns

Having multiple sheets as separate tables unlocks queries that spreadsheets handle awkwardly. JOIN the Orders sheet to the Products sheet on a product ID column to compute revenue per product. Use GROUP BY on the Orders sheet alone to find the top customers by spend. Apply window functions like ROW_NUMBER() OVER (PARTITION BY region ORDER BY sale_date DESC) to rank rows within each region across an entire sheet.4 For data quality checks, COUNT(DISTINCT id) versus COUNT(*) identifies duplicate rows in a sheet header that should have unique identifiers. When a workbook contains summary sheets that aggregate from detail sheets, you can verify the summary against the raw data with a single query.

Data quality checks across multiple sheets

Data quality checks across sheets are where the workbench outperforms in-spreadsheet formulas. A single SQL query cross-validates two sheets simultaneously: SELECT o.order_id FROM Orders o LEFT JOIN Products p ON o.product_id = p.id WHERE p.id IS NULL returns all order rows whose product_id has no matching record in Products. A VLOOKUP would handle this only awkwardly, because a spreadsheet formula cannot scan two entire sheets at once and flag every mismatched row in a single pass.

Detecting duplicates and referential integrity failures

For duplicate detection within a sheet, SELECT id, COUNT(*) AS n FROM Orders GROUP BY id HAVING n > 1 returns only IDs that appear more than once. Combine both checks into a single quality session: run the duplicate query on each sheet first, then run the LEFT JOIN referential integrity check across sheets. Export the problem rows to CSV to share findings with the file owner without resending the entire workbook.

Excel date and number formatting in SQL queries

In Excel, date cells are stored internally as numeric serial numbers (days since January 1, 1900) and displayed with a format mask.5 When the workbench loads an Excel file, the JavaScript parser converts date cells to ISO date strings (YYYY-MM-DD) before handing them to DuckDB. The resulting column type is VARCHAR, not DATE.

Working with Excel dates and percentages

To use date arithmetic or date_trunc, cast the column first: sale_date::DATE converts the VARCHAR ISO string to a DuckDB DATE type, which is exactly where Excel dates need a real DATE cast before any date math. Number cells formatted as currencies in Excel (formatted as $1,234.56) arrive as DOUBLE in DuckDB; the currency symbol and comma formatting are presentation concerns the parser strips. Percentage cells arrive as DOUBLE in their decimal form: 25% becomes 0.25. Multiply by 100 when you need the display percentage: SELECT margin_pct * 100 AS margin_pct_display FROM orders.

When to use this

Use this when you receive an .xlsx export from a SaaS platform, a finance system, or a colleague and want to run SQL aggregations, cross-sheet JOINs, or data quality checks without opening the file in Excel. Drop the workbook into the workbench and run SHOW TABLES first to confirm every sheet loaded as its own table before you write a cross-sheet JOIN.

Examples

List all available sheet names as tables

Before
SHOW TABLES;

Returns all sheet names loaded from the workbook. Each name is a queryable table.

Join two sheets on a common column

Before
SELECT o.order_id,
       o.quantity,
       p.product_name,
       p.unit_price
FROM Orders o
JOIN Products p ON o.product_id = p.id;

Multiple sheets from the same workbook are available simultaneously as separate tables.

Find the top customers by total spend

Before
SELECT customer_name,
       SUM(amount) AS total_spend
FROM Orders
GROUP BY customer_name
ORDER BY total_spend DESC
LIMIT 10;

DuckDB sums across all rows in the sheet — no pivot table required.

Check for duplicate IDs in a sheet

Before
SELECT id, COUNT(*) AS n
FROM Products
GROUP BY id
HAVING COUNT(*) > 1;

Returns only rows where the id value appears more than once — a fast data quality check.

Sources
  1. 1.

    Microsoft Learn, "Structure of a SpreadsheetML document," learn.microsoft.com, January 2025. https://learn.microsoft.com/en-us/office/open-xml/spreadsheet/structure-of-a-spreadsheetml-document

  2. 2.

    DuckDB Foundation, "Excel Import," duckdb.org, accessed June 2026. https://duckdb.org/docs/current/guides/file_formats/excel_import

  3. 3.

    OfficeDev, "Working with formulas," github.com, January 2025. https://github.com/OfficeDev/open-xml-docs/blob/main/docs/spreadsheet/working-with-formulas.md

  4. 4.

    Microsoft Support, "Change the date system, format, or two-digit year interpretation," support.microsoft.com, accessed June 2026. https://support.microsoft.com/en-US/Excel/change-the-date-system-format-or-two-digit-year-interpretation

  5. 5.

    PostgreSQL Global Development Group, "Window Functions," postgresql.org, accessed June 2026. https://www.postgresql.org/docs/18/functions-window.html

FAQ