7.3 KiB
title | pagination_prev | pagination_next | sidebar_custom_props | ||||
---|---|---|---|---|---|---|---|
WebSQL and SQLite | demos/grid | demos/worker |
|
WebSQL is a popular SQL-based in-browser database available on Chrome. In practice, it is powered by SQLite, and most simple SQLite-compatible queries work as-is in WebSQL.
The public demo https://sheetjs.com/sql generates a database from workbook.
WebSQL Details
Importing data from spreadsheets is straightforward using the generate_sql
helper function from "Generating Tables":
const db = openDatabase('sheetql', '1.0', 'SheetJS WebSQL Test', 2097152);
const stmts = generate_sql(ws, wsname);
// NOTE: tx.executeSql and db.transaction use callbacks. This wraps in Promises
for(var i = 0; i < stmts.length; ++i) await new Promise((res, rej) => {
db.transaction(tx =>
tx.executeSql(stmts[i], [],
(tx, data) => res(data), // if the query is successful, return the data
(tx, err) => rej(err) // if the query fails, reject with the error
));
});
The result of a SQL SELECT statement is a SQLResultSet
. The rows
property
is a SQLResultSetRowList
. It is an "array-like" structure that has length
and properties like 0
, 1
, etc. However, this is not a real Array object.
A real Array can be created using Array.from
:
const db = openDatabase('sheetql', '1.0', 'SheetJS WebSQL Test', 2097152);
db.readTransaction(tx =>
tx.executeSQL("SELECT * FROM DatabaseTable", [], (tx, data) => {
// data.rows is "array-like", so `Array.from` can make it a real array
const aoo = Array.from(data.rows);
const ws = XLSX.utils.json_to_sheet(aoo);
// ... it is recommended to perform an export here OR wrap in a Promise
})
);
Live Demo
The following demo generates a database with 5 fixed SQL statements. Queries can be changed in the Live Editor. The WebSQL database can be inspected in the "WebSQL" section of the "Application" Tab of Developer Tools:
function SheetQL() {
const [out, setOut] = React.useState("");
const queries = [
'DROP TABLE IF EXISTS Presidents',
'CREATE TABLE Presidents (Name TEXT, Idx REAL)',
'INSERT INTO Presidents (Name, Idx) VALUES ("Barack Obama", 44)',
'INSERT INTO Presidents (Name, Idx) VALUES ("Donald Trump", 45)',
'INSERT INTO Presidents (Name, Idx) VALUES ("Joseph Biden", 46)'
];
const xport = React.useCallback(async() => {
// prep database
const db = openDatabase('sheetql', '1.0', 'SheetJS WebSQL Test', 2097152);
for(var i = 0; i < queries.length; ++i) await new Promise((res, rej) => {
db.transaction((tx) => {
tx.executeSql(queries[i], [], (tx, data) => res(data), (tx, err) => rej(err));
});
});
// pull data and generate rows
db.readTransaction(tx => {
tx.executeSql("SELECT * FROM Presidents", [], (tx, data) => {
const aoo = Array.from(data.rows);
setOut("QUERY RESULT:\n" + aoo.map(r => JSON.stringify(r)).join("\n") + "\n")
const ws = XLSX.utils.json_to_sheet(aoo);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "Presidents");
XLSX.writeFile(wb, "SheetQL.xlsx");
});
});
});
return ( <pre>{out}<button onClick={xport}><b>Fetch!</b></button></pre> );
}
Server-Side SQLite
Most platforms offer a simple way to query SQLite database files.
The following example shows how to query for each table in an SQLite database, query for the data for each table, add each non-empty table to a workbook, and export as XLSX.
The Northwind database is available in SQLite form.
NodeJS
The better-sqlite3
module provides a very simple API for working with
SQLite databases. Statement#all
runs a prepared statement and returns an array
of JS objects.
- Install the dependencies:
npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz better-sqlite3
- Save the following to
node.mjs
:
/* Load SQLite3 connector library */
import Database from "better-sqlite3";
/* Load SheetJS library */
import * as XLSX from 'xlsx';
import * as fs from 'fs';
XLSX.set_fs(fs);
/* Initialize database */
var db = Database("northwind.db");
/* Create new workbook */
var wb = XLSX.utils.book_new();
/* Get list of table names */
var sql = db.prepare("SELECT name FROM sqlite_master WHERE type='table'");
var result = sql.all();
/* Loop across each name */
result.forEach(function(row) {
/* Get first 100K rows */
var aoo = db.prepare("SELECT * FROM '" + row.name + "' LIMIT 100000").all();
if(aoo.length > 0) {
/* Create Worksheet from the row objects */
var ws = XLSX.utils.json_to_sheet(aoo, {dense: true});
/* Add to Workbook */
XLSX.utils.book_append_sheet(wb, ws, row.name);
}
});
/* Write File */
XLSX.writeFile(wb, "node.xlsx");
- Run
node node.mjs
and opennode.xlsx
Bun
Bun ships with a built-in high-performance module bun:sqlite
.
- Install the dependencies:
npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
- Save the following to
bun.mjs
:
/* Load SQLite3 connector library */
import { Database } from "bun:sqlite";
/* Load SheetJS library */
import * as XLSX from 'xlsx';
import * as fs from 'fs';
XLSX.set_fs(fs);
/* Initialize database */
var db = Database.open("northwind.db");
/* Create new workbook */
var wb = XLSX.utils.book_new();
/* Get list of table names */
var sql = db.prepare("SELECT name FROM sqlite_master WHERE type='table'");
var result = sql.all();
/* Loop across each name */
result.forEach(function(row) {
/* Get first 100K rows */
var aoo = db.prepare("SELECT * FROM '" + row.name + "' LIMIT 100000").all();
if(aoo.length > 0) {
/* Create Worksheet from the row objects */
var ws = XLSX.utils.json_to_sheet(aoo, {dense: true});
/* Add to Workbook */
XLSX.utils.book_append_sheet(wb, ws, row.name);
}
});
/* Write File */
XLSX.writeFile(wb, "bun.xlsx");
- Run
bun bun.mjs
and openbun.xlsx
Deno
Deno sqlite
library returns raw arrays of arrays.
- Save the following to
deno.ts
:
/* Load SQLite3 connector library */
import { DB } from "https://deno.land/x/sqlite/mod.ts";
/* Load SheetJS library */
// @deno-types="https://cdn.sheetjs.com/xlsx-latest/package/types/index.d.ts"
import * as XLSX from 'https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs';
/* Initialize database */
var db = new DB("northwind.db");
/* Create new workbook */
var wb = XLSX.utils.book_new();
/* Get list of table names */
var sql = db.prepareQuery("SELECT name FROM sqlite_master WHERE type='table'");
var result = sql.all();
/* Loop across each name */
result.forEach(function(row) {
/* Get first 100K rows */
var query = db.prepareQuery("SELECT * FROM '" + row[0] + "' LIMIT 100000")
var aoa = query.all();
if(aoa.length > 0) {
/* Create array of arrays */
var data = [query.columns().map(x => x.name)].concat(aoa);
/* Create Worksheet from the aoa */
var ws = XLSX.utils.aoa_to_sheet(data, {dense: true});
/* Add to Workbook */
XLSX.utils.book_append_sheet(wb, ws, row[0]);
}
});
/* Write File */
XLSX.writeFile(wb, "deno.xlsx");
- Run
deno run --allow-read --allow-write deno.ts
and opendeno.xlsx