====== alaSQL 完全教程 ======
alaSQL 是一个轻量级的 JavaScript SQL 数据库,专为浏览器和 Node.js 设计。它支持标准 SQL 语法,同时提供 JSON 文档存储能力,是处理客户端数据的理想选择。
===== 目录 =====
* [[#第一章:alaSQL简介与环境搭建|第一章:alaSQL简介与环境搭建]]
* [[#第二章:基础SQL操作|第二章:基础SQL操作]]
* [[#第三章:高级查询技术|第三章:高级查询技术]]
* [[#第四章:数据导入导出|第四章:数据导入导出]]
* [[#第五章:索引与性能优化|第五章:索引与性能优化]]
* [[#第六章:浏览器集成与应用|第六章:浏览器集成与应用]]
* [[#第七章:Node.js服务端开发|第七章:Node.js服务端开发]]
* [[#第八章:与其他框架集成|第八章:与其他框架集成]]
* [[#第九章:实战项目案例|第九章:实战项目案例]]
* [[#第十章:最佳实践与常见问题|第十章:最佳实践与常见问题]]
----
===== 第一章:alaSQL简介与环境搭建 =====
==== 1.1 什么是alaSQL ====
alaSQL(AlaSQL)是一个开源的 JavaScript SQL 数据库,具有以下特点:
* **纯 JavaScript 实现**:无需外部依赖,可直接在浏览器和 Node.js 中运行
* **标准 SQL 支持**:支持大部分 SQL-99 标准语法
* **JSON 友好**:原生支持 JavaScript 对象和 JSON 数据
* **轻量快速**:核心库仅约 300KB,查询性能优异
* **跨平台**:支持浏览器、Node.js、Web Workers 和 WebSQL
==== 1.2 适用场景 ====
^ 场景 ^ 说明 ^
| 离线 Web 应用 | 在无网络环境下提供数据存储和查询能力 |
| 数据可视化 | 快速处理大量数据用于图表展示 |
| 原型开发 | 快速搭建无需后端的数据演示项目 |
| 客户端缓存 | 存储用户偏好设置、临时数据等 |
| 数据转换 | CSV、Excel、JSON 等格式之间的转换 |
| 教育学习 | 学习 SQL 语法,无需安装数据库服务器 |
==== 1.3 环境搭建 ====
=== 1.3.1 浏览器环境 ===
=== 1.3.2 Node.js 环境 ===
# 安装 alaSQL
npm install alasql
// 在 Node.js 中使用
const alasql = require('alasql');
// 创建内存数据库
const db = new alasql.Database();
db.exec("CREATE TABLE products (id INT, name STRING, price NUMBER)");
db.exec("INSERT INTO products VALUES (1, 'iPhone', 5999), (2, 'iPad', 3999)");
const results = db.exec("SELECT * FROM products WHERE price > 4000");
console.log(results);
=== 1.3.3 ES6 模块导入 ===
// 使用 ES6 模块语法
import alasql from 'alasql';
// 或使用命名导入
import * as alasql from 'alasql';
// 异步查询
async function queryData() {
const res = await alasql.promise('SELECT * FROM ?', [[{a:1}, {a:2}]]);
console.log(res);
}
==== 1.4 第一个alaSQL程序 ====
// 1. 创建表
alasql("CREATE TABLE students (id INT PRIMARY KEY, name STRING, age INT, score NUMBER)");
// 2. 插入数据
alasql("INSERT INTO students VALUES \
(1, '小明', 18, 85.5), \
(2, '小红', 19, 92.0), \
(3, '小刚', 18, 78.5), \
(4, '小丽', 20, 88.0)");
// 3. 查询数据
const students = alasql("SELECT * FROM students WHERE score >= 80");
console.log("成绩80分以上的学生:", students);
// 4. 聚合查询
const stats = alasql(`
SELECT
COUNT(*) as total,
AVG(score) as avg_score,
MAX(score) as max_score,
MIN(score) as min_score
FROM students
`);
console.log("成绩统计:", stats);
// 5. 分组查询
const ageStats = alasql(`
SELECT age, COUNT(*) as count, AVG(score) as avg_score
FROM students
GROUP BY age
ORDER BY age
`);
console.log("按年龄分组统计:", ageStats);
===== 第二章:基础SQL操作 =====
==== 2.1 数据定义语言(DDL)====
=== 2.1.1 创建表 ===
// 基础建表
alasql("CREATE TABLE employees ( \
id INT PRIMARY KEY, \
name STRING, \
department STRING, \
salary NUMBER, \
hire_date DATE, \
is_active BOOLEAN DEFAULT true \
)");
// 使用 IF NOT EXISTS
alasql("CREATE TABLE IF NOT EXISTS employees (...)");
// 从查询结果创建表
alasql("CREATE TABLE high_earners AS \
SELECT * FROM employees WHERE salary > 10000");
=== 2.1.2 修改表结构 ====
// 添加列
alasql("ALTER TABLE employees ADD COLUMN email STRING");
// 删除列
alasql("ALTER TABLE employees DROP COLUMN email");
// 重命名列(alaSQL扩展语法)
alasql("ALTER TABLE employees RENAME COLUMN name TO full_name");
=== 2.1.3 删除表 ===
// 删除表
alasql("DROP TABLE employees");
// 安全删除(表不存在不报错)
alasql("DROP TABLE IF EXISTS employees");
==== 2.2 数据操作语言(DML)====
=== 2.2.1 INSERT 插入数据 ===
// 单行插入
alasql("INSERT INTO employees VALUES (1, '张三', '技术部', 15000, '2023-01-15', true)");
// 多行插入
alasql(`INSERT INTO employees VALUES
(2, '李四', '销售部', 12000, '2023-03-20', true),
(3, '王五', '技术部', 18000, '2022-11-08', true),
(4, '赵六', '人事部', 10000, '2023-06-01', false)
`);
// 指定列插入
alasql("INSERT INTO employees (id, name, department) VALUES (5, '钱七', '财务部')");
// 从其他表插入
alasql("INSERT INTO employees_backup SELECT * FROM employees WHERE is_active = true");
// 插入对象数组(JavaScript风格)
const newEmployees = [
{id: 6, name: '孙八', department: '技术部', salary: 16000},
{id: 7, name: '周九', department: '销售部', salary: 13000}
];
alasql("INSERT INTO employees VALUES ?", [newEmployees]);
=== 2.2.2 SELECT 查询数据 ====
// 基础查询
alasql("SELECT * FROM employees");
// 选择特定列
alasql("SELECT name, salary FROM employees");
// 使用别名
alasql("SELECT name AS 姓名, salary AS 工资 FROM employees");
// 去重
alasql("SELECT DISTINCT department FROM employees");
// 条件查询
alasql("SELECT * FROM employees WHERE salary > 12000");
alasql("SELECT * FROM employees WHERE department = '技术部' AND salary >= 15000");
// 范围查询
alasql("SELECT * FROM employees WHERE salary BETWEEN 10000 AND 15000");
alasql("SELECT * FROM employees WHERE department IN ('技术部', '销售部')");
// 模糊查询
alasql("SELECT * FROM employees WHERE name LIKE '张%'");
alasql("SELECT * FROM employees WHERE name LIKE '%三%'");
// 空值判断
alasql("SELECT * FROM employees WHERE email IS NULL");
alasql("SELECT * FROM employees WHERE email IS NOT NULL");
// 排序
alasql("SELECT * FROM employees ORDER BY salary DESC");
alasql("SELECT * FROM employees ORDER BY department ASC, salary DESC");
// 分页(LIMIT 和 OFFSET)
alasql("SELECT * FROM employees LIMIT 10");
alasql("SELECT * FROM employees LIMIT 10 OFFSET 20");
alasql("SELECT * FROM employees LIMIT 20, 10"); // 简写形式
=== 2.2.3 UPDATE 更新数据 ====
// 基础更新
alasql("UPDATE employees SET salary = 20000 WHERE id = 1");
// 更新多列
alasql("UPDATE employees SET salary = 22000, department = '架构部' WHERE id = 1");
// 批量更新
alasql("UPDATE employees SET salary = salary * 1.1 WHERE department = '技术部'");
// 使用表达式
alasql("UPDATE employees SET salary = salary + 1000 WHERE hire_date < '2023-01-01'");
=== 2.2.4 DELETE 删除数据 ====
// 条件删除
alasql("DELETE FROM employees WHERE id = 5");
// 批量删除
alasql("DELETE FROM employees WHERE is_active = false");
// 删除所有数据(保留表结构)
alasql("DELETE FROM employees");
// 清空表并重置自增ID(alaSQL扩展)
alasql("TRUNCATE TABLE employees");
==== 2.3 数据类型 ====
^ 类型 ^ 说明 ^ 示例 ^
| STRING / VARCHAR | 字符串 | 'Hello', "World" |
| NUMBER / FLOAT | 浮点数 | 3.14, -0.5 |
| INT / INTEGER | 整数 | 42, -10 |
| BOOLEAN | 布尔值 | true, false |
| DATE | 日期 | '2024-01-15' |
| DATETIME | 日期时间 | '2024-01-15 09:30:00' |
| OBJECT | JavaScript对象 | {a: 1, b: 2} |
| ARRAY | JavaScript数组 | [1, 2, 3] |
===== 第三章:高级查询技术 =====
==== 3.1 聚合函数 ====
// 统计函数
alasql("SELECT COUNT(*) FROM employees");
alasql("SELECT COUNT(DISTINCT department) FROM employees");
// 数值计算
alasql("SELECT SUM(salary) FROM employees");
alasql("SELECT AVG(salary) FROM employees");
alasql("SELECT MAX(salary) FROM employees");
alasql("SELECT MIN(salary) FROM employees");
// 组合使用
alasql(`
SELECT
department,
COUNT(*) as emp_count,
SUM(salary) as total_salary,
AVG(salary) as avg_salary,
MAX(salary) as highest_salary,
MIN(salary) as lowest_salary
FROM employees
GROUP BY department
`);
// HAVING 子句(过滤分组结果)
alasql(`
SELECT department, AVG(salary) as avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 12000
`);
==== 3.2 多表查询 ====
=== 3.2.1 内连接(INNER JOIN)===
// 创建部门表
alasql("CREATE TABLE departments (dept_id STRING, dept_name STRING, location STRING)");
alasql(`INSERT INTO departments VALUES
('技术部', '技术研发中心', 'A座3楼'),
('销售部', '销售中心', 'B座1楼'),
('人事部', '人力资源部', 'A座2楼')
`);
// 内连接查询
const result = alasql(`
SELECT
e.name,
e.salary,
d.dept_name,
d.location
FROM employees e
INNER JOIN departments d ON e.department = d.dept_id
`);
console.log(result);
=== 3.2.2 外连接(OUTER JOIN)===
// 左外连接(返回左表所有记录)
alasql(`
SELECT e.name, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.department = d.dept_id
`);
// 右外连接
alasql(`
SELECT e.name, d.dept_name
FROM employees e
RIGHT JOIN departments d ON e.department = d.dept_id
`);
// 全外连接
alasql(`
SELECT e.name, d.dept_name
FROM employees e
OUTER JOIN departments d ON e.department = d.dept_id
`);
=== 3.2.3 交叉连接(CROSS JOIN)===
// 笛卡尔积
alasql(`
SELECT e.name, d.dept_name
FROM employees e
CROSS JOIN departments d
`);
==== 3.3 子查询 ====
// 单行子查询
alasql(`
SELECT * FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees)
`);
// 多行子查询(IN)
alasql(`
SELECT * FROM employees
WHERE department IN (
SELECT dept_id FROM departments WHERE location LIKE 'A座%'
)
`);
// 相关子查询(EXISTS)
alasql(`
SELECT * FROM employees e
WHERE EXISTS (
SELECT 1 FROM departments d
WHERE d.dept_id = e.department AND d.location = 'A座3楼'
)
`);
// 子查询作为派生表
alasql(`
SELECT dept_name, avg_sal
FROM (
SELECT department, AVG(salary) as avg_sal
FROM employees
GROUP BY department
) t
JOIN departments d ON t.department = d.dept_id
WHERE avg_sal > 13000
`);
==== 3.4 窗口函数 ====
// ROW_NUMBER() - 行号
alasql(`
SELECT
name,
salary,
department,
ROW_NUMBER() OVER (ORDER BY salary DESC) as rank
FROM employees
`);
// RANK() - 排名(跳跃)
alasql(`
SELECT
name,
salary,
RANK() OVER (ORDER BY salary DESC) as rank
FROM employees
`);
// 分区窗口函数
alasql(`
SELECT
name,
salary,
department,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) as dept_rank
FROM employees
`);
// LAG/LEAD - 前后行
alasql(`
SELECT
name,
salary,
LAG(salary) OVER (ORDER BY salary) as prev_salary,
LEAD(salary) OVER (ORDER BY salary) as next_salary
FROM employees
`);
===== 第四章:数据导入导出 =====
==== 4.1 从JavaScript对象加载数据 ====
// 直接查询JavaScript数组
const myData = [
{id: 1, product: '苹果', price: 5.5, quantity: 100},
{id: 2, product: '香蕉', price: 3.2, quantity: 200},
{id: 3, product: '橙子', price: 4.8, quantity: 150}
];
const result = alasql("SELECT product, price * quantity as total FROM ?", [myData]);
console.log(result);
// 将数组导入为表
alasql("CREATE TABLE fruits");
alasql("SELECT * INTO fruits FROM ?", [myData]);
==== 4.2 CSV文件处理 ====
// 导出为CSV
alasql("SELECT * FROM employees", [], function(data) {
alasql.exportCsv(data, 'employees.csv');
});
// 从CSV导入(浏览器环境)
alasql("CREATE TABLE csv_data");
alasql('SELECT * FROM CSV("data.csv")', [], function(data) {
alasql("INSERT INTO csv_data SELECT * FROM ?", [data]);
});
// Node.js 从文件导入CSV
const fs = require('fs');
const csv = fs.readFileSync('data.csv', 'utf8');
alasql("CREATE TABLE products");
alasql('SELECT * FROM CSV(?)', [csv], function(data) {
alasql("INSERT INTO products SELECT * FROM ?", [data]);
});
==== 4.3 Excel文件处理 ====
// 导出为Excel
alasql("SELECT * FROM employees", [], function(data) {
alasql.exportXls(data, 'employees.xlsx');
});
// 从Excel导入
alasql('SELECT * FROM XLSX("data.xlsx")', [], function(data) {
console.log(data);
});
==== 4.4 JSON数据处理 ====
// 导出为JSON
const jsonData = alasql("SELECT * FROM employees");
console.log(JSON.stringify(jsonData, null, 2));
// 从JSON导入
const jsonStr = '[{"id":1,"name":"张三"},{"id":2,"name":"李四"}]';
const parsed = JSON.parse(jsonStr);
alasql("CREATE TABLE json_table");
alasql("INSERT INTO json_table SELECT * FROM ?", [parsed]);
===== 第五章:索引与性能优化 =====
==== 5.1 创建索引 ====
// 创建普通索引
alasql("CREATE INDEX idx_department ON employees(department)");
// 创建唯一索引
alasql("CREATE UNIQUE INDEX idx_email ON employees(email)");
// 复合索引
alasql("CREATE INDEX idx_dept_salary ON employees(department, salary)");
// 删除索引
alasql("DROP INDEX idx_department");
==== 5.2 查询优化技巧 ====
// 1. 只查询需要的列
alasql("SELECT id, name FROM employees"); // 优于 SELECT *
// 2. 使用 LIMIT 限制返回行数
alasql("SELECT * FROM employees LIMIT 100");
// 3. 合理使用索引列作为查询条件
alasql("SELECT * FROM employees WHERE department = '技术部'");
// 4. 避免在索引列上使用函数
// 不推荐:alasql("SELECT * FROM employees WHERE UPPER(name) = '张三'")
// 推荐:在应用层处理或在数据入库时统一格式
// 5. 大数据量时使用分页
alasql("SELECT * FROM employees LIMIT 50 OFFSET 0"); // 第1页
alasql("SELECT * FROM employees LIMIT 50 OFFSET 50"); // 第2页
===== 第六章:浏览器集成与应用 =====
==== 6.1 在HTML中使用alaSQL ====
alaSQL 示例
员工信息查询
==== 6.2 本地存储持久化 ====
// 使用 localStorage 持久化数据(浏览器环境)
// 保存数据库到 localStorage
function saveDatabase() {
const data = alasql("SELECT * FROM employees");
localStorage.setItem('employees_db', JSON.stringify(data));
}
// 从 localStorage 恢复数据
function loadDatabase() {
const saved = localStorage.getItem('employees_db');
if (saved) {
const data = JSON.parse(saved);
alasql("CREATE TABLE IF NOT EXISTS employees");
alasql("DELETE FROM employees"); // 清空现有数据
alasql("INSERT INTO employees SELECT * FROM ?", [data]);
}
}
// IndexedDB 持久化(alaSQL内置支持)
alasql("CREATE INDEXEDDB DATABASE IF NOT EXISTS mydb");
alasql("ATTACH INDEXEDDB DATABASE mydb");
alasql("USE mydb");
// 现在创建的表会自动持久化到 IndexedDB
alasql("CREATE TABLE IF NOT EXISTS employees (id INT PRIMARY KEY, name STRING)");
alasql("INSERT INTO employees VALUES (1, '张三')");
// 刷新页面后数据依然存在
===== 第七章:Node.js服务端开发 =====
==== 7.1 构建REST API ====
// server.js
const express = require('express');
const alasql = require('alasql');
const app = express();
app.use(express.json());
// 初始化数据库
alasql("CREATE TABLE IF NOT EXISTS users (id INT PRIMARY KEY, name STRING, email STRING)");
// GET 所有用户
app.get('/api/users', (req, res) => {
const users = alasql("SELECT * FROM users");
res.json(users);
});
// GET 单个用户
app.get('/api/users/:id', (req, res) => {
const user = alasql("SELECT * FROM users WHERE id = ?", [req.params.id]);
if (user.length === 0) {
return res.status(404).json({error: '用户不存在'});
}
res.json(user[0]);
});
// POST 创建用户
app.post('/api/users', (req, res) => {
const {id, name, email} = req.body;
try {
alasql("INSERT INTO users VALUES (?, ?, ?)", [id, name, email]);
res.status(201).json({id, name, email});
} catch (err) {
res.status(400).json({error: err.message});
}
});
// PUT 更新用户
app.put('/api/users/:id', (req, res) => {
const {name, email} = req.body;
alasql("UPDATE users SET name = ?, email = ? WHERE id = ?", [name, email, req.params.id]);
res.json({id: req.params.id, name, email});
});
// DELETE 删除用户
app.delete('/api/users/:id', (req, res) => {
alasql("DELETE FROM users WHERE id = ?", [req.params.id]);
res.status(204).send();
});
// 复杂查询端点
app.get('/api/stats', (req, res) => {
const stats = alasql(`
SELECT
COUNT(*) as total_users,
SUBSTRING(email, INSTR(email, '@') + 1) as domain,
COUNT(*) as count
FROM users
GROUP BY domain
`);
res.json(stats);
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
==== 7.2 文件数据库持久化 ====
const alasql = require('alasql');
const fs = require('fs');
const DB_FILE = './mydatabase.json';
// 加载数据库
function loadDB() {
if (fs.existsSync(DB_FILE)) {
const data = JSON.parse(fs.readFileSync(DB_FILE, 'utf8'));
for (const [tableName, rows] of Object.entries(data)) {
alasql(`CREATE TABLE IF NOT EXISTS ${tableName}`);
alasql(`DELETE FROM ${tableName}`);
if (rows.length > 0) {
alasql(`INSERT INTO ${tableName} SELECT * FROM ?`, [rows]);
}
}
}
}
// 保存数据库
function saveDB() {
const tables = alasql("SHOW TABLES");
const data = {};
tables.forEach(t => {
const tableName = t.tableid;
data[tableName] = alasql(`SELECT * FROM ${tableName}`);
});
fs.writeFileSync(DB_FILE, JSON.stringify(data, null, 2));
}
// 使用示例
loadDB();
alasql("CREATE TABLE IF NOT EXISTS products (id INT, name STRING, price NUMBER)");
alasql("INSERT INTO products VALUES (1, '笔记本电脑', 5999)");
saveDB();
===== 第八章:与其他框架集成 =====
==== 8.1 与Vue.js集成 ====
// Vue 3 + alaSQL 示例
import {ref, computed} from 'vue';
import alasql from 'alasql';
export function useDatabase() {
const data = ref([]);
// 初始化表
alasql("CREATE TABLE IF NOT EXISTS items (id INT, name STRING, value NUMBER)");
const query = (sql, params = []) => {
return alasql(sql, params);
};
const insert = (record) => {
alasql("INSERT INTO items VALUES ?", [record]);
refresh();
};
const refresh = () => {
data.value = alasql("SELECT * FROM items");
};
// 计算属性:统计数据
const stats = computed(() => {
return alasql(`
SELECT
COUNT(*) as count,
SUM(value) as total,
AVG(value) as average
FROM items
`)[0];
});
return {data, query, insert, stats, refresh};
}
==== 8.2 与React集成 ====
// React Hook for alaSQL
import {useState, useCallback, useMemo} from 'react';
import alasql from 'alasql';
export function useAlaSQL(tableName, initialData = []) {
const [version, setVersion] = useState(0);
// 初始化表
useMemo(() => {
alasql(`CREATE TABLE IF NOT EXISTS ${tableName}`);
if (initialData.length > 0) {
alasql(`INSERT INTO ${tableName} SELECT * FROM ?`, [initialData]);
}
}, [tableName]);
// 查询
const query = useCallback((sql, params = []) => {
return alasql(sql, params);
}, []);
// 获取所有数据
const getAll = useCallback(() => {
return alasql(`SELECT * FROM ${tableName}`);
}, [tableName, version]);
// 插入
const insert = useCallback((record) => {
alasql(`INSERT INTO ${tableName} VALUES ?`, [record]);
setVersion(v => v + 1);
}, [tableName]);
// 更新
const update = useCallback((setClause, whereClause) => {
alasql(`UPDATE ${tableName} SET ${setClause} WHERE ${whereClause}`);
setVersion(v => v + 1);
}, [tableName]);
// 删除
const remove = useCallback((whereClause) => {
alasql(`DELETE FROM ${tableName} WHERE ${whereClause}`);
setVersion(v => v + 1);
}, [tableName]);
return {query, getAll, insert, update, remove};
}
===== 第九章:实战项目案例 =====
==== 9.1 项目一:个人记账本 ====
// 个人记账本应用
class AccountBook {
constructor() {
alasql("CREATE TABLE IF NOT EXISTS accounts (id INT PRIMARY KEY, name STRING, type STRING)");
alasql("CREATE TABLE IF NOT EXISTS transactions (id INT PRIMARY KEY, date DATE, account_id INT, category STRING, amount NUMBER, note STRING)");
}
// 添加账户
addAccount(id, name, type) {
alasql("INSERT INTO accounts VALUES (?, ?, ?)", [id, name, type]);
}
// 记录交易
addTransaction(id, date, accountId, category, amount, note) {
alasql("INSERT INTO transactions VALUES (?, ?, ?, ?, ?, ?)", [id, date, accountId, category, amount, note]);
}
// 月度收支统计
getMonthlyReport(year, month) {
return alasql(`
SELECT
category,
SUM(CASE WHEN amount > 0 THEN amount ELSE 0 END) as income,
SUM(CASE WHEN amount < 0 THEN -amount ELSE 0 END) as expense
FROM transactions
WHERE YEAR(date) = ? AND MONTH(date) = ?
GROUP BY category
`, [year, month]);
}
// 账户余额
getAccountBalance(accountId) {
return alasql("SELECT SUM(amount) as balance FROM transactions WHERE account_id = ?", [accountId])[0].balance || 0;
}
}
// 使用示例
const book = new AccountBook();
book.addAccount(1, '现金', 'asset');
book.addAccount(2, '银行卡', 'asset');
book.addTransaction(1, '2024-01-15', 1, '工资', 10000, '1月工资');
book.addTransaction(2, '2024-01-16', 1, '餐饮', -150, '午餐');
book.addTransaction(3, '2024-01-17', 2, '交通', -50, '地铁');
console.log(book.getMonthlyReport(2024, 1));
console.log('现金余额:', book.getAccountBalance(1));
==== 9.2 项目二:数据可视化仪表板 ====
// 销售数据仪表板
class SalesDashboard {
constructor() {
alasql("CREATE TABLE IF NOT EXISTS sales (id INT, product STRING, region STRING, date DATE, amount NUMBER, quantity INT)");
}
loadData(salesData) {
alasql("DELETE FROM sales");
alasql("INSERT INTO sales SELECT * FROM ?", [salesData]);
}
// 区域销售排名
getRegionRanking() {
return alasql(`
SELECT region, SUM(amount) as total_sales, SUM(quantity) as total_qty
FROM sales
GROUP BY region
ORDER BY total_sales DESC
`);
}
// 产品销售趋势(按月)
getProductTrend(product) {
return alasql(`
SELECT
YEAR(date) as year,
MONTH(date) as month,
SUM(amount) as monthly_sales
FROM sales
WHERE product = ?
GROUP BY YEAR(date), MONTH(date)
ORDER BY year, month
`, [product]);
}
// TOP 10 产品
getTopProducts(limit = 10) {
return alasql(`
SELECT product, SUM(amount) as total_sales
FROM sales
GROUP BY product
ORDER BY total_sales DESC
LIMIT ?
`, [limit]);
}
// 同比增长率
getYoYGrowth(year) {
return alasql(`
SELECT
t1.product,
t1.this_year,
t2.last_year,
ROUND((t1.this_year - t2.last_year) / t2.last_year * 100, 2) as growth_rate
FROM (
SELECT product, SUM(amount) as this_year
FROM sales WHERE YEAR(date) = ?
GROUP BY product
) t1
LEFT JOIN (
SELECT product, SUM(amount) as last_year
FROM sales WHERE YEAR(date) = ? - 1
GROUP BY product
) t2 ON t1.product = t2.product
`, [year, year]);
}
}
===== 第十章:最佳实践与常见问题 =====
==== 10.1 最佳实践 ====
- **合理设计表结构**:根据查询需求设计索引,避免过多的列
- **批量操作**:尽量使用多行插入代替多次单行插入
- **参数化查询**:使用参数化查询防止 SQL 注入
- **及时清理**:不需要的数据及时清理,避免内存占用过高
- **错误处理**:使用 try-catch 包裹数据库操作
==== 10.2 常见问题 ====
=== Q: alaSQL 支持事务吗? ===
alaSQL 当前版本对事务的支持有限,主要用于单用户场景。如果需要复杂事务,建议使用 SQLite 或其他数据库。
=== Q: 如何处理大量数据? ===
对于超过 10 万条记录的数据集,建议:
- 使用分页查询
- 添加合适的索引
- 考虑使用 Web Workers 避免阻塞主线程
- 数据分片处理
=== Q: 如何在生产环境使用? ===
- 浏览器环境:适合离线应用、数据可视化、原型开发
- Node.js 环境:适合中小型应用、数据转换、测试环境
- 高并发场景:建议使用 PostgreSQL、MySQL 等传统数据库
=== Q: alaSQL 和 SQL.js 的区别? ===
^ 特性 ^ alaSQL ^ SQL.js ^
| 架构 | 纯 JavaScript 实现 | SQLite 编译为 WebAssembly |
| 体积 | 约 300KB | 约 1MB+ |
| SQL 兼容性 | 部分 SQL-99 | 完整 SQLite 语法 |
| JSON 支持 | 原生支持 | 需转换 |
| 浏览器支持 | 所有现代浏览器 | 支持 WASM 的浏览器 |
==== 10.3 错误处理 ====
try {
alasql("CREATE TABLE test (id INT PRIMARY KEY, name STRING)");
alasql("INSERT INTO test VALUES (1, 'Alice')");
alasql("INSERT INTO test VALUES (1, 'Bob')"); // 主键冲突,会报错
} catch (err) {
console.error('数据库错误:', err.message);
}
// 使用 promise 风格处理异步操作
alasql.promise('SELECT * FROM test')
.then(result => console.log(result))
.catch(err => console.error('查询失败:', err));
----