docs.sheetjs.com/docz/docs/03-demos/07-data/01-websql.md

248 lines
7.3 KiB
Markdown
Raw Normal View History

2023-02-24 07:46:48 +00:00
---
title: WebSQL and SQLite
2023-02-28 11:40:44 +00:00
pagination_prev: demos/desktop/index
pagination_next: demos/local/index
2023-02-24 07:46:48 +00:00
sidebar_custom_props:
type: web
sql: true
---
2023-04-27 09:12:19 +00:00
import current from '/version.js';
2023-05-01 01:27:02 +00:00
import CodeBlock from '@theme/CodeBlock';
2023-04-27 09:12:19 +00:00
2023-02-24 07:46:48 +00:00
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.
2023-03-12 06:25:57 +00:00
:::caution
WebSQL is only supported in Chromium-based browsers including Chrome.
Safari historically supported WebSQL but Safari 13 dropped support. Legacy
browsers including Internet Explorer and Firefox never added support.
:::
2023-02-24 07:46:48 +00:00
## WebSQL Details
Importing data from spreadsheets is straightforward using the `generate_sql`
2023-02-27 00:33:01 +00:00
helper function from ["Generating Tables"](/docs/demos/data/sql#generating-tables).
The Web SQL Database API is callback-based. The following snippet wraps
transactions in Promise objects:
2023-02-24 07:46:48 +00:00
```js
const db = openDatabase('sheetql', '1.0', 'SheetJS WebSQL Test', 2097152);
const stmts = generate_sql(ws, wsname);
2023-02-27 00:33:01 +00:00
2023-02-24 07:46:48 +00:00
// NOTE: tx.executeSql and db.transaction use callbacks. This wraps in Promises
2023-02-27 00:33:01 +00:00
for(var stmt of stmts) await new Promise((res, rej) => {
2023-02-24 07:46:48 +00:00
db.transaction(tx =>
2023-02-27 00:33:01 +00:00
tx.executeSql(stmt, [],
2023-02-24 07:46:48 +00:00
(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`
2023-02-27 00:33:01 +00:00
and properties like `0`, `1`, etc. However, this is not a real Array object!
2023-02-24 07:46:48 +00:00
A real Array can be created using `Array.from`:
```js
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);
2023-02-27 00:33:01 +00:00
// ... perform an export here OR wrap in a Promise
2023-02-24 07:46:48 +00:00
})
);
```
### Live Demo
2023-02-27 00:33:01 +00:00
:::note
2023-05-29 02:52:54 +00:00
This demo was last tested on 2023 May 28 in Chromium 113
2023-02-27 00:33:01 +00:00
:::
2023-02-24 07:46:48 +00:00
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:
![WebSQL view in Developer Tools](pathname:///files/websql.png)
```jsx live
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() => {
2023-02-27 00:33:01 +00:00
/* prep database */
2023-02-24 07:46:48 +00:00
const db = openDatabase('sheetql', '1.0', 'SheetJS WebSQL Test', 2097152);
2023-02-27 00:33:01 +00:00
for(var q of queries) await new Promise((res, rej) => {
2023-02-24 07:46:48 +00:00
db.transaction((tx) => {
2023-02-27 00:33:01 +00:00
tx.executeSql(q, [], (tx, data) => res(data), (tx, err) => rej(err));
2023-02-24 07:46:48 +00:00
});
});
2023-02-27 00:33:01 +00:00
/* pull data and generate rows */
2023-02-24 07:46:48 +00:00
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.
2023-05-29 02:52:54 +00:00
The Chinook database is a MIT-licensed sample database. The original source code
repository `http://chinookdatabase.codeplex.com` is no longer available, so the
[raw SQL queries are mirrored here](pathname:///sqlite/chinook.sql).
2023-02-24 07:46:48 +00:00
2023-02-27 00:33:01 +00:00
:::note
2023-05-29 02:52:54 +00:00
This demo was last tested on 2023 May 28
2023-02-27 00:33:01 +00:00
:::
2023-02-24 07:46:48 +00:00
### NodeJS
2023-05-29 02:52:54 +00:00
The `better-sqlite3` module provides an API for working with SQLite databases.
`Statement#all` runs a prepared statement and returns an array of objects:
2023-02-24 07:46:48 +00:00
2023-05-29 02:52:54 +00:00
```js
import Database from "better-sqlite3";
import * as XLSX from "xlsx";
/* open database */
var db = Database("chinook.db");
/* get data from the `Invoice` table */
var aoo = db.prepare("SELECT * FROM 'Invoice' LIMIT 100000").all();
/* create worksheet from the row objects */
var ws = XLSX.utils.json_to_sheet(aoo, {dense: true});
```
0) Build `chinook.db` from [the SQL statements](pathname:///sqlite/chinook.sql):
```bash
curl -LO https://docs.sheetjs.com/sqlite/chinook.sql
sqlite3 chinook.db ".read chinook.sql"
```
2023-02-27 00:33:01 +00:00
2023-02-24 07:46:48 +00:00
1) Install the dependencies:
2023-05-01 01:27:02 +00:00
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz better-sqlite3@8.1.0`}
</CodeBlock>
2023-02-24 07:46:48 +00:00
2023-05-29 02:52:54 +00:00
2) Download [`SheetJSQLiteNode.mjs`](pathname:///sqlite/SheetJSQLiteNode.mjs):
2023-02-24 07:46:48 +00:00
2023-05-29 02:52:54 +00:00
```bash
curl -LO https://docs.sheetjs.com/sqlite/SheetJSQLiteNode.mjs
2023-02-24 07:46:48 +00:00
```
2023-05-29 02:52:54 +00:00
3) Run `node SheetJSQLiteNode.mjs` and open `SheetJSQLiteNode.xlsx`
2023-02-24 07:46:48 +00:00
### Bun
2023-05-29 02:52:54 +00:00
Bun ships with a built-in high-performance module `bun:sqlite`:
2023-02-24 07:46:48 +00:00
2023-05-29 02:52:54 +00:00
```js
import { Database } from "bun:sqlite";
import * as XLSX from "xlsx";
/* open database */
var db = Database.open("chinook.db");
/* get data from the `Invoice` table */
var aoo = db.prepare("SELECT * FROM 'Invoice' LIMIT 100000").all();
/* create worksheet from the row objects */
var ws = XLSX.utils.json_to_sheet(aoo, {dense: true});
```
0) Build `chinook.db` from [the SQL statements](pathname:///sqlite/chinook.sql):
```bash
curl -LO https://docs.sheetjs.com/sqlite/chinook.sql
sqlite3 chinook.db ".read chinook.sql"
```
2023-02-27 00:33:01 +00:00
2023-02-24 07:46:48 +00:00
1) Install the dependencies:
2023-05-01 01:27:02 +00:00
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</CodeBlock>
2023-02-24 07:46:48 +00:00
2023-05-29 02:52:54 +00:00
2) Download [`SheetJSQLiteBun.mjs`](pathname:///sqlite/SheetJSQLiteBun.mjs):
2023-02-24 07:46:48 +00:00
2023-05-29 02:52:54 +00:00
```bash
curl -LO https://docs.sheetjs.com/sqlite/SheetJSQLiteBun.mjs
2023-02-24 07:46:48 +00:00
```
2023-05-29 02:52:54 +00:00
3) Run `bun run SheetJSQLiteBun.mjs` and open `SheetJSQLiteBun.xlsx`
2023-02-24 07:46:48 +00:00
### Deno
2023-05-29 02:52:54 +00:00
Deno `sqlite` library returns raw arrays of arrays:
2023-02-24 07:46:48 +00:00
2023-05-29 02:52:54 +00:00
<CodeBlock language="ts">{`\
2023-02-24 07:46:48 +00:00
import { DB } from "https://deno.land/x/sqlite/mod.ts";
2023-05-01 01:27:02 +00:00
// @deno-types="https://cdn.sheetjs.com/xlsx-${current}/package/types/index.d.ts"
2023-05-29 02:52:54 +00:00
import * as XLSX from "https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs";
2023-05-01 01:27:02 +00:00
\n\
2023-05-29 02:52:54 +00:00
/* open database */
var db = new DB("chinook.db");
2023-05-01 01:27:02 +00:00
\n\
2023-05-29 02:52:54 +00:00
/* get data from the \`Invoice\` table */
var aoa = db.prepareQuery("SELECT * FROM 'Invoice' LIMIT 100000").all();
2023-05-01 01:27:02 +00:00
\n\
2023-05-29 02:52:54 +00:00
/* create worksheet from the row objects */
var data = [query.columns().map(x => x.name)].concat(aoa);
var ws = XLSX.utils.aoa_to_sheet(data, {dense: true});`}
2023-05-01 01:27:02 +00:00
</CodeBlock>
2023-02-24 07:46:48 +00:00
2023-05-29 02:52:54 +00:00
0) Build `chinook.db` from [the SQL statements](pathname:///sqlite/chinook.sql):
```bash
curl -LO https://docs.sheetjs.com/sqlite/chinook.sql
sqlite3 chinook.db ".read chinook.sql"
```
1) Download [`SheetJSQLiteDeno.ts`](pathname:///sqlite/SheetJSQLiteDeno.ts):
```bash
curl -LO https://docs.sheetjs.com/sqlite/SheetJSQLiteDeno.ts
```
2) Run `deno run --allow-read --allow-write SheetJSQLiteDeno.ts` and open `SheetJSQLiteDeno.xlsx`