概述
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])
}
查询数据
当 按钮_查询全部.被点击
调用 SQLite1.查询SQL("SELECT * FROM users ORDER BY created_at DESC")
当 SQLite1.查询结果(结果)
' 结果是列表,每项是一个字典
设 显示 = ""
设 i = 1
当 i ≤ 列表长度(结果)
设 记录 = 列表第i项(结果)
设 显示 = 显示 &
从字典 记录 获取 "name" & " | " &
从字典 记录 获取 "phone" & " | " &
从字典 记录 获取 "email" & "\n"
设 i = i + 1
标签_用户列表.文本 = 显示
条件查询
当 按钮_搜索.被点击
设 SQL = "SELECT * FROM users WHERE name LIKE '%" & 输入框_搜索.文本 & "%'"
调用 SQLite1.查询SQL(SQL)
更新数据
当 按钮_更新.被点击
设 SQL = "UPDATE users SET phone = '" & 输入框_新电话.文本 &
"' WHERE name = '" & 文本输入框_姓名.文本 & "'"
调用 SQLite1.执行SQL(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))"))
}
录入成绩
当 按钮_录入.被点击
' 先查找学生ID
设 查询SQL = "SELECT id FROM students WHERE name = '" & 输入框_学生.文本 & "'"
调用 SQLite1.查询SQL(查询SQL)
当 SQLite1.查询结果(结果)
如果 列表长度(结果) > 0
设 学生ID = 从字典 列表第1项(结果) 获取 "id"
设 录入SQL = "INSERT INTO scores (student_id, subject, score, exam_date) VALUES (" &
学生ID & ", '" & 下拉框_科目.选中项 & "', " &
输入框_分数.文本 & ", '" &
计时器1.格式化日期时间(计时器1.当前时间(), "yyyy-MM-dd") & "')"
调用 SQLite1.执行SQL(录入SQL)
标签_状态.文本 = "✅ 成绩已录入"
统计查询
' 查询某学生所有成绩
设 SQL = "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"
' 查询某科目平均分
设 SQL = "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"
' 班级成绩排名
设 SQL = "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展示查询结果
当 SQLite1.查询结果(结果)
设 显示列表 = 创建空列表
设 i = 1
当 i ≤ 列表长度(结果)
设 记录 = 列表第i项(结果)
设 显示文本 = 从字典 记录 获取 "name" & " | " &
从字典 记录 获取 "subject" & " | " &
从字典 记录 获取 "score" & "分"
设 显示列表 = 添加列表项(显示列表, 显示文本)
设 i = i + 1
设 ListView1.元素 = 显示列表
与已有文档的关系
| 技术 | 已有文档 | 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/:
当 按钮_导出.被点击
调用 SQLite1.查询SQL("SELECT * FROM users")
当 SQLite1.查询结果(结果)
设 CSV = "id,name,phone,email\n"
设 i = 1
当 i ≤ 列表长度(结果)
设 r = 列表第i项(结果)
设 CSV = CSV & 从字典r获取"id" & "," &
从字典r获取"name" & "," &
从字典r获取"phone" & "," &
从字典r获取"email" & "\n"
设 i = i + 1
调用 文件管理器1.保存文件(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 |
版权声明:MIT App Inventor 官方文档采用 CC BY-SA 4.0 授权,本文档由 ai2claw 🐝 整理。
扫码添加客服咨询