« 返回首页
概述
App Inventor内置的TinyDB是简单的键值存储,不支持复杂查询。SQLite扩展提供完整的SQL数据库能力。
已有文档:extensions/SQLite.md 介绍了SQLite扩展。db.md 介绍了TinyDB和TinyWebDB。本文聚焦SQLite实战用法。
TinyDB vs SQLite
| 特性 |
TinyDB |
SQLite |
| 存储方式 |
键值对 |
关系型表 |
| 查询 |
只能按Key |
SQL查询 |
| 数据量 |
小 |
大 |
| 排序/过滤 |
手动实现 |
SQL语句 |
| 多表 |
❌ |
✅ |
| 聚合统计 |
手动 |
SQL聚合函数 |
| 适合场景 |
简单配置 |
结构化数据 |
SQLite扩展
导入
- 下载SQLite扩展.aix文件
- Designer → Extension → Import Extension
核心方法
| 方法 |
说明 |
| OpenDatabase(dbName) |
打开/创建数据库 |
| ExecuteSQL(sql) |
执行SQL语句 |
| QuerySQL(sql) |
查询并返回结果 |
| CloseDatabase() |
关闭数据库 |
事件
| 事件 |
参数 |
说明 |
| OnResult(result) |
查询结果 |
查询返回 |
| OnError(error) |
错误信息 |
执行出错 |
基本操作
创建数据库和表
when Screen1.Initialize() {
SQLite1.OpenDatabase("myapp.db")
// 创建用户表
var 建表SQL = join("CREATE TABLE IF NOT EXISTS users (", "id INTEGER PRIMARY KEY AUTOINCREMENT, ", "name TEXT NOT NULL, ", "phone TEXT, ", "email TEXT, ", "created_at DATETIME DEFAULT CURRENT_TIMESTAMP)")
SQLite1.Execute(建表SQL)
}
插入数据
when 按钮_添加用户.Click() {
var SQL = join("INSERT INTO users (name, phone, email) VALUES ('", 文本输入框_姓名.Text, "', '", 文本输入框_电话.Text, "', '", 文本输入框_邮箱.Text, "')")
SQLite1.Execute(SQL)
标签_状态.Text = "✅ 用户已添加"
}
参数化查询(防SQL注入)
when 按钮_安全添加.Click() {
var SQL = "INSERT INTO users (name, phone, email) VALUES (?, ?, ?)"
SQLite1.执行参数化SQL(SQL, [文本输入框_姓名.Text, 文本输入框_电话.Text, 文本输入框_邮箱.Text])
}
查询数据
when 按钮_查询全部.Click {
SQLite1.QuerySQL("SELECT * FROM users ORDER BY created_at DESC")
}
when SQLite1.OnResult(结果) {
// 结果是列表,每项是一个字典
var 显示 = ""
var i = 1
while i <= 列表长度(结果) {
var 记录 = 列表第i项(结果)
var name = dictLookup(记录, "name", "")
var phone = dictLookup(记录, "phone", "")
var email = dictLookup(记录, "email", "")
var 显示 = 显示 + name + " | " + phone + " | " + email + "\n"
var i = i + 1
}
标签_用户列表.Text = 显示
}
条件查询
when 按钮_搜索.Click {
var SQL = "SELECT * FROM users WHERE name LIKE '%" + 输入框_搜索.Text + "%'"
SQLite1.QuerySQL(SQL)
}
更新数据
when 按钮_更新.Click {
var SQL = "UPDATE users SET phone = '" + 输入框_新电话.Text + "' WHERE name = '" + 文本输入框_姓名.Text + "'"
SQLite1.Execute(SQL)
}
删除数据
when 按钮_删除.Click() {
var SQL = join("DELETE FROM users WHERE id = ", 选中ID)
SQLite1.Execute(SQL)
}
实战案例:学生成绩管理
创建表结构
when Screen1.Initialize() {
SQLite1.OpenDatabase("school.db")
SQLite1.Execute(join("CREATE TABLE IF NOT EXISTS students (", "id INTEGER PRIMARY KEY AUTOINCREMENT, ", "name TEXT NOT NULL, ", "class TEXT, ", "student_no TEXT UNIQUE)"))
SQLite1.Execute(join("CREATE TABLE IF NOT EXISTS scores (", "id INTEGER PRIMARY KEY AUTOINCREMENT, ", "student_id INTEGER, ", "subject TEXT, ", "score REAL, ", "exam_date TEXT, ", "FOREIGN KEY(student_id) REFERENCES students(id))"))
}
录入成绩
when 按钮_录入.Click {
// 先查找学生ID
var 查询SQL = "SELECT id FROM students WHERE name = '" + 输入框_学生.Text + "'"
SQLite1.QuerySQL(查询SQL)
}
when SQLite1.OnResult(结果) {
if 列表长度(结果) > 0 {
var item = 列表第1项(结果)
var 学生ID = dictLookup(item, "id", "")
var d = 时钟1.FormatDateTime(时钟1.Now(), "yyyy-MM-dd")
var 录入SQL = "INSERT INTO scores (student_id, subject, score, exam_date) VALUES (" + 学生ID + ", '" + 下拉框_科目.Selection + "', " + 输入框_分数.Text + ", '" + d + "')"
SQLite1.Execute(录入SQL)
标签_状态.Text = "✅ 成绩已录入"
}
}
统计查询
// 查询某学生所有成绩
SELECT s.name, sc.subject, sc.score, sc.exam_date
FROM scores sc JOIN students s ON sc.student_id = s.id
WHERE s.name = '?'
ORDER BY sc.exam_date DESC
// 查询某科目平均分
SELECT subject, AVG(score) as avg_score, MAX(score) as max_score,
MIN(score) as min_score, COUNT(*) as count
FROM scores WHERE subject = '?'
GROUP BY subject
// 班级成绩排名
SELECT s.name, s.class, SUM(sc.score) as total
FROM scores sc JOIN students s ON sc.student_id = s.id
GROUP BY sc.student_id ORDER BY total DESC
用ListView展示查询结果
when SQLite1.OnResult(结果) {
var 显示列表 = []
var i = 1
while i <= 列表长度(结果) {
var 记录 = 列表第i项(结果)
var name = dictLookup(记录, "name", "")
var subject = dictLookup(记录, "subject", "")
var score = dictLookup(记录, "score", "")
var 显示文本 = name + " | " + subject + " | " + score + "分"
var 显示列表 = append(显示列表, 显示文本)
var i = i + 1
}
ListView1.Elements = 显示列表
}
与已有文档的关系
| 技术 |
已有文档 |
SQLite场景用途 |
| TinyDB |
db.md |
简单配置仍用TinyDB |
| Web API |
api_communication.md |
数据同步到云端 |
| ListView |
listview_custom.md |
展示查询结果 |
| CSV导出 |
file_operations.md |
导出SQLite数据 |
| JSON解析 |
json_parse.md |
解析API返回数据 |
常见问题
Q1: SQLite数据库文件在哪里?
数据库文件存储在应用的私有目录:/data/data/包名/databases/。需要root权限才能直接访问。
Q2: 如何导出SQLite数据?
查询全部数据 → 转CSV → 保存到/sdcard/:
when 按钮_导出.Click {
SQLite1.QuerySQL("SELECT * FROM users")
}
when SQLite1.OnResult(结果) {
var CSV = "id,name,phone,email\n"
var i = 1
while i <= 列表长度(结果) {
var r = 列表第i项(结果)
var id = dictLookup(r, "id", "")
var name = dictLookup(r, "name", "")
var phone = dictLookup(r, "phone", "")
var email = dictLookup(r, "email", "")
var CSV = CSV + id + "," + name + "," + phone + "," + email + "\n"
var i = i + 1
}
文件管理器1.SaveFile(CSV, "/sdcard/MyApp/export.csv")
}
Q3: 数据库占用空间大?
-- 清理碎片
VACUUM;
-- 删除旧数据
DELETE FROM scores WHERE exam_date < '2025-01-01';
总结
| 操作 |
SQL |
| 建表 |
CREATE TABLE |
| 插入 |
INSERT INTO |
| 查询 |
SELECT |
| 条件 |
WHERE |
| 排序 |
ORDER BY |
| 聚合 |
AVG/SUM/COUNT/MAX/MIN |
| 关联 |
JOIN |
| 分组 |
GROUP BY |