SQLite数据库入门与C语言编程实战

发布时间:2026/11/3 7:45:05
SQLite数据库入门与C语言编程实战 1. SQLite数据库入门指南SQLite作为一款轻量级的关系型数据库管理系统以其零配置、无服务器、单文件存储的特性在嵌入式系统和移动应用中广受欢迎。与MySQL、Oracle等大型数据库不同SQLite不需要单独的服务器进程数据库直接存储在磁盘文件中这使得它在资源受限的环境中表现出色。我第一次接触SQLite是在开发一个嵌入式设备的数据采集系统时。当时需要在有限的硬件资源上实现数据存储功能SQLite的轻量级特性完美解决了这个问题。从那以后无论是移动应用开发、桌面软件还是小型Web应用SQLite都成为了我的首选数据库解决方案。2. SQLite环境搭建与配置2.1 安装SQLite3在Ubuntu/Debian系统上安装SQLite非常简单只需执行以下命令sudo apt-get update sudo apt-get install sqlite3 libsqlite3-dev sqlitebrowser这三个包分别提供了sqlite3命令行交互工具libsqlite3-devC语言开发所需的头文件和静态库sqlitebrowser图形化管理工具可选安装完成后可以通过sqlite3 --version命令验证安装是否成功。2.2 基本命令行操作启动SQLite命令行界面sqlite3 test.db这会创建一个名为test.db的数据库文件如果不存在的话并进入交互模式。在交互模式下可以执行两种命令以点号(.)开头的SQLite特有命令标准的SQL语句常用管理命令.databases显示当前连接的数据库.tables列出所有表.schema 表名显示表的创建语句.mode column设置输出格式为列模式.headers on显示列名.quit退出交互模式提示SQLite的命令行工具虽然简单但功能非常完整。熟练掌握这些命令可以大大提高工作效率特别是在没有图形界面可用的环境下。3. SQL基础与实战3.1 数据表创建与管理创建学生信息表的SQL示例CREATE TABLE students ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, gender TEXT CHECK(gender IN (男, 女)), age INTEGER, score REAL, class_id INTEGER, FOREIGN KEY (class_id) REFERENCES classes(id) );关键点解析PRIMARY KEY定义主键AUTOINCREMENT确保主键自动增长NOT NULL约束该列不能为空CHECK添加数据验证规则FOREIGN KEY定义外键关系创建班级表的SQLCREATE TABLE classes ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, teacher TEXT );3.2 数据操作语言(DML)插入数据-- 插入完整记录 INSERT INTO students VALUES (NULL, 张三, 男, 18, 85.5, 1); -- 插入部分字段 INSERT INTO students (name, gender, age) VALUES (李四, 女, 17); -- 批量插入 INSERT INTO students (name, gender, age, score, class_id) VALUES (王五, 男, 18, 90.0, 1), (赵六, 女, 17, 88.5, 2);更新数据-- 更新单个记录 UPDATE students SET score 92.0 WHERE name 张三; -- 批量更新 UPDATE students SET score score 5 WHERE class_id 1; -- 使用表达式更新 UPDATE students SET age age 1 WHERE strftime(%Y-%m-%d, now) strftime(%Y-%m-%d, birthday);删除数据-- 删除特定记录 DELETE FROM students WHERE id 3; -- 清空表慎用 DELETE FROM students;注意SQLite中DELETE没有WHERE子句会删除整个表的数据但表结构保留。与TRUNCATE TABLE不同DELETE操作会记录日志可以回滚。3.3 数据查询进阶基础查询-- 查询所有字段 SELECT * FROM students; -- 查询特定字段 SELECT name, score FROM students; -- 使用别名 SELECT name AS 姓名, score AS 成绩 FROM students;条件查询-- 比较运算符 SELECT * FROM students WHERE score 60; -- 逻辑运算符 SELECT * FROM students WHERE score 60 AND gender 女; -- IN操作符 SELECT * FROM students WHERE class_id IN (1, 3); -- BETWEEN SELECT * FROM students WHERE score BETWEEN 70 AND 90; -- LIKE模糊查询 SELECT * FROM students WHERE name LIKE 张%; -- 日期查询 SELECT * FROM students WHERE birthday 2005-01-01;排序与分页-- 单列排序 SELECT * FROM students ORDER BY score DESC; -- 多列排序 SELECT * FROM students ORDER BY class_id ASC, score DESC; -- 分页查询 SELECT * FROM students LIMIT 10 OFFSET 20; -- 等价于 SELECT * FROM students LIMIT 20, 10;聚合函数-- 基本聚合 SELECT COUNT(*) AS total, AVG(score) AS avg_score, MAX(score) AS max_score, MIN(score) AS min_score FROM students; -- 分组聚合 SELECT class_id, COUNT(*) AS student_count, AVG(score) AS avg_score FROM students GROUP BY class_id HAVING COUNT(*) 5;4. 多表操作与复杂查询4.1 连接查询内连接(INNER JOIN)SELECT s.name AS student_name, c.name AS class_name FROM students s INNER JOIN classes c ON s.class_id c.id;左外连接(LEFT OUTER JOIN)SELECT s.name AS student_name, c.name AS class_name FROM students s LEFT JOIN classes c ON s.class_id c.id;交叉连接(CROSS JOIN)-- 生成学生和班级的所有可能组合 SELECT s.name AS student_name, c.name AS class_name FROM students s CROSS JOIN classes c;4.2 子查询WHERE子句中的子查询-- 查询高于平均分的学生 SELECT * FROM students WHERE score (SELECT AVG(score) FROM students);FROM子句中的子查询-- 查询每个班级的平均分 SELECT c.name AS class_name, s.avg_score FROM classes c JOIN ( SELECT class_id, AVG(score) AS avg_score FROM students GROUP BY class_id ) s ON c.id s.class_id;EXISTS子查询-- 查询有学生的班级 SELECT * FROM classes c WHERE EXISTS ( SELECT 1 FROM students s WHERE s.class_id c.id );4.3 视图与索引创建视图CREATE VIEW student_scores AS SELECT s.name AS student_name, c.name AS class_name, s.score FROM students s JOIN classes c ON s.class_id c.id;使用视图-- 查询视图 SELECT * FROM student_scores WHERE score 80; -- 视图也可以参与连接 SELECT ss.student_name, ss.score, a.activity_name FROM student_scores ss JOIN activities a ON ss.student_id a.student_id;创建索引-- 单列索引 CREATE INDEX idx_students_name ON students(name); -- 复合索引 CREATE INDEX idx_students_class_score ON students(class_id, score); -- 唯一索引 CREATE UNIQUE INDEX idx_students_id_card ON students(id_card);经验分享索引虽然能提高查询速度但会降低插入和更新性能。建议只在经常用于查询条件的列上创建索引并且避免在小表上创建不必要的索引。5. SQLite C语言编程接口5.1 基本API介绍SQLite提供了丰富的C语言API核心函数包括sqlite3_open()- 打开数据库连接sqlite3_exec()- 执行SQL语句sqlite3_prepare_v2()- 准备SQL语句sqlite3_step()- 执行预编译语句sqlite3_finalize()- 释放预编译语句sqlite3_close()- 关闭数据库连接5.2 完整示例代码#include stdio.h #include sqlite3.h int callback(void *data, int argc, char **argv, char **colName) { for(int i 0; i argc; i) { printf(%s %s\n, colName[i], argv[i] ? argv[i] : NULL); } printf(\n); return 0; } int main() { sqlite3 *db; char *err_msg NULL; // 打开数据库 int rc sqlite3_open(test.db, db); if(rc ! SQLITE_OK) { fprintf(stderr, 无法打开数据库: %s\n, sqlite3_errmsg(db)); sqlite3_close(db); return 1; } // 创建表 const char *sql CREATE TABLE IF NOT EXISTS users( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT UNIQUE NOT NULL);; rc sqlite3_exec(db, sql, 0, 0, err_msg); if(rc ! SQLITE_OK) { fprintf(stderr, SQL错误: %s\n, err_msg); sqlite3_free(err_msg); sqlite3_close(db); return 1; } // 插入数据 sql INSERT INTO users (name, email) VALUES (张三, zhangsanexample.com); INSERT INTO users (name, email) VALUES (李四, lisiexample.com);; rc sqlite3_exec(db, sql, 0, 0, err_msg); if(rc ! SQLITE_OK) { fprintf(stderr, SQL错误: %s\n, err_msg); sqlite3_free(err_msg); } // 查询数据 sql SELECT * FROM users;; rc sqlite3_exec(db, sql, callback, 0, err_msg); if(rc ! SQLITE_OK) { fprintf(stderr, SQL错误: %s\n, err_msg); sqlite3_free(err_msg); } // 使用预编译语句 sqlite3_stmt *stmt; sql SELECT * FROM users WHERE name LIKE ?;; rc sqlite3_prepare_v2(db, sql, -1, stmt, NULL); if(rc ! SQLITE_OK) { fprintf(stderr, 准备语句失败: %s\n, sqlite3_errmsg(db)); } else { sqlite3_bind_text(stmt, 1, %张%, -1, SQLITE_STATIC); while(sqlite3_step(stmt) SQLITE_ROW) { printf(id %d, name %s, email %s\n, sqlite3_column_int(stmt, 0), sqlite3_column_text(stmt, 1), sqlite3_column_text(stmt, 2)); } sqlite3_finalize(stmt); } // 关闭数据库 sqlite3_close(db); return 0; }5.3 预编译语句的使用预编译语句(Prepared Statement)是SQLite中执行SQL的高效方式特别适合需要多次执行的语句// 准备插入语句 const char *sql INSERT INTO users (name, email) VALUES (?, ?);; sqlite3_stmt *stmt; rc sqlite3_prepare_v2(db, sql, -1, stmt, NULL); if(rc ! SQLITE_OK) { // 错误处理 } // 绑定参数并执行 sqlite3_bind_text(stmt, 1, 王五, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, wangwuexample.com, -1, SQLITE_STATIC); rc sqlite3_step(stmt); if(rc ! SQLITE_DONE) { // 错误处理 } // 重置语句以便重用 sqlite3_reset(stmt); // 再次绑定和执行 sqlite3_bind_text(stmt, 1, 赵六, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, zhaoliuexample.com, -1, SQLITE_STATIC); rc sqlite3_step(stmt); // 释放语句 sqlite3_finalize(stmt);5.4 事务处理事务是数据库操作的重要特性可以确保一组操作要么全部成功要么全部失败// 开始事务 rc sqlite3_exec(db, BEGIN TRANSACTION;, 0, 0, err_msg); if(rc ! SQLITE_OK) { // 错误处理 } // 执行多个操作 rc sqlite3_exec(db, INSERT INTO users (name, email) VALUES (钱七, qianqiexample.com);, 0, 0, err_msg); if(rc SQLITE_OK) { rc sqlite3_exec(db, UPDATE users SET email new_emailexample.com WHERE name 张三;, 0, 0, err_msg); } // 根据结果提交或回滚 if(rc SQLITE_OK) { rc sqlite3_exec(db, COMMIT;, 0, 0, err_msg); } else { sqlite3_exec(db, ROLLBACK;, 0, 0, NULL); fprintf(stderr, 事务失败: %s\n, err_msg); sqlite3_free(err_msg); }6. 性能优化与最佳实践6.1 性能优化技巧使用事务将多个操作放在一个事务中可以显著提高性能。SQLite默认对每个语句都开启一个事务频繁提交会影响性能。合理使用索引在经常查询的列上创建索引但避免过度索引因为索引会降低插入和更新速度。预编译语句对于重复执行的SQL语句使用预编译语句可以减少解析开销。批量操作批量插入数据时使用单个事务和预编译语句。合理设置PRAGMAPRAGMA journal_mode WAL; -- 使用WAL日志模式提高并发性 PRAGMA synchronous NORMAL; -- 平衡安全性和性能 PRAGMA cache_size -2000; -- 设置缓存大小为2MB6.2 常见问题与解决方案数据库被锁定原因多个连接同时尝试写入解决方案使用WAL模式减少事务持有时间合理设计应用架构性能突然下降可能原因数据库需要VACUUM解决方案定期执行VACUUM命令整理数据库文件C语言接口内存泄漏预防措施确保每个sqlite3_prepare_v2()都有对应的sqlite3_finalize()每个sqlite3_open()都有对应的sqlite3_close()跨平台兼容性问题注意不同平台的文件路径表示方法不同解决方案使用跨平台路径处理库或相对路径6.3 安全注意事项SQL注入防护永远不要拼接SQL语句始终使用参数化查询预编译语句敏感数据保护考虑使用SQLite的加密扩展或在应用层加密敏感数据备份策略定期备份数据库文件使用.dump命令导出SQL脚本7. 实际项目案例7.1 学生成绩管理系统这个案例展示了如何使用SQLite和C语言构建一个完整的学生成绩管理系统包括数据库设计、核心功能和实现代码。数据库设计-- 班级表 CREATE TABLE classes ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, teacher TEXT ); -- 学生表 CREATE TABLE students ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, gender TEXT CHECK(gender IN (男, 女)), class_id INTEGER, FOREIGN KEY (class_id) REFERENCES classes(id) ); -- 课程表 CREATE TABLE courses ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, credit INTEGER ); -- 成绩表 CREATE TABLE scores ( student_id INTEGER, course_id INTEGER, score REAL CHECK(score 0 AND score 100), PRIMARY KEY (student_id, course_id), FOREIGN KEY (student_id) REFERENCES students(id), FOREIGN KEY (course_id) REFERENCES courses(id) );核心功能实现添加学生信息int add_student(sqlite3 *db, const char *name, const char *gender, int class_id) { sqlite3_stmt *stmt; const char *sql INSERT INTO students (name, gender, class_id) VALUES (?, ?, ?);; int rc sqlite3_prepare_v2(db, sql, -1, stmt, NULL); if(rc ! SQLITE_OK) return rc; sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, gender, -1, SQLITE_STATIC); sqlite3_bind_int(stmt, 3, class_id); rc sqlite3_step(stmt); sqlite3_finalize(stmt); return rc; }查询班级平均分float get_class_avg_score(sqlite3 *db, int class_id) { sqlite3_stmt *stmt; const char *sql SELECT AVG(s.score) FROM scores s JOIN students st ON s.student_id st.id WHERE st.class_id ?;; int rc sqlite3_prepare_v2(db, sql, -1, stmt, NULL); if(rc ! SQLITE_OK) return -1; sqlite3_bind_int(stmt, 1, class_id); float avg -1; if(sqlite3_step(stmt) SQLITE_ROW) { avg sqlite3_column_double(stmt, 0); } sqlite3_finalize(stmt); return avg; }数据统计报表void generate_report(sqlite3 *db) { const char *sql SELECT c.name AS class_name, COUNT(st.id) AS student_count, AVG(sc.score) AS avg_score, MAX(sc.score) AS max_score, MIN(sc.score) AS min_score FROM classes c LEFT JOIN students st ON c.id st.class_id LEFT JOIN scores sc ON st.id sc.student_id GROUP BY c.id;; sqlite3_stmt *stmt; int rc sqlite3_prepare_v2(db, sql, -1, stmt, NULL); if(rc ! SQLITE_OK) return; printf(班级\t\t学生数\t平均分\t最高分\t最低分\n); printf(------------------------------------------------\n); while(sqlite3_step(stmt) SQLITE_ROW) { const char *class_name sqlite3_column_text(stmt, 0); int student_count sqlite3_column_int(stmt, 1); double avg_score sqlite3_column_double(stmt, 2); double max_score sqlite3_column_double(stmt, 3); double min_score sqlite3_column_double(stmt, 4); printf(%-10s\t%d\t%.1f\t%.1f\t%.1f\n, class_name, student_count, avg_score, max_score, min_score); } sqlite3_finalize(stmt); }7.2 嵌入式设备数据采集系统在资源受限的嵌入式环境中SQLite是一个理想的数据存储解决方案。以下是一个数据采集系统的实现要点数据库设计优化-- 精简的数据表设计 CREATE TABLE sensor_data ( timestamp INTEGER PRIMARY KEY, sensor_id INTEGER, value REAL, status INTEGER ) WITHOUT ROWID; -- 节省存储空间高效数据插入// 批量插入传感器数据 void batch_insert_sensor_data(sqlite3 *db, SensorData *data, int count) { sqlite3_exec(db, BEGIN TRANSACTION;, 0, 0, 0); sqlite3_stmt *stmt; const char *sql INSERT INTO sensor_data VALUES (?, ?, ?, ?);; sqlite3_prepare_v2(db, sql, -1, stmt, NULL); for(int i 0; i count; i) { sqlite3_bind_int(stmt, 1, data[i].timestamp); sqlite3_bind_int(stmt, 2, data[i].sensor_id); sqlite3_bind_double(stmt, 3, data[i].value); sqlite3_bind_int(stmt, 4, data[i].status); sqlite3_step(stmt); sqlite3_reset(stmt); } sqlite3_finalize(stmt); sqlite3_exec(db, COMMIT;, 0, 0, 0); }数据压缩与归档// 定期归档旧数据 void archive_old_data(sqlite3 *db, time_t cutoff) { // 创建归档表 sqlite3_exec(db, CREATE TABLE IF NOT EXISTS sensor_data_archive AS SELECT * FROM sensor_data WHERE 0;, 0, 0, 0); // 移动旧数据到归档表 char sql[256]; snprintf(sql, sizeof(sql), INSERT INTO sensor_data_archive SELECT * FROM sensor_data WHERE timestamp %ld;, cutoff); sqlite3_exec(db, sql, 0, 0, 0); // 删除已归档数据 snprintf(sql, sizeof(sql), DELETE FROM sensor_data WHERE timestamp %ld;, cutoff); sqlite3_exec(db, sql, 0, 0, 0); // 优化数据库 sqlite3_exec(db, VACUUM;, 0, 0, 0); }8. 高级特性与扩展8.1 自定义SQL函数SQLite允许用C语言创建自定义函数然后在SQL中调用// 自定义函数计算字符串的MD5值 void md5_func(sqlite3_context *context, int argc, sqlite3_value **argv) { const char *input (const char *)sqlite3_value_text(argv[0]); if(!input) { sqlite3_result_null(context); return; } // 这里应该是实际的MD5计算代码 char md5[33] d41d8cd98f00b204e9800998ecf8427e; // 示例值 sqlite3_result_text(context, md5, -1, SQLITE_TRANSIENT); } // 注册自定义函数 sqlite3_create_function(db, md5, 1, SQLITE_UTF8, NULL, md5_func, NULL, NULL); // 在SQL中使用 // SELECT name, md5(name) FROM students;8.2 虚拟表虚拟表是SQLite的高级特性允许将外部数据源表示为SQL表// 实现一个简单的CSV文件虚拟表 #include sqlite3ext.h SQLITE_EXTENSION_INIT1 typedef struct { sqlite3_vtab base; // 自定义数据结构 } CSVVTab; typedef struct { sqlite3_vtab_cursor base; // 游标状态 } CSVVCursor; // 实现虚拟表的各种方法 static int csvvConnect(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr) { // 创建虚拟表结构 return SQLITE_OK; } // 注册模块 int sqlite3_csvvtab_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) { SQLITE_EXTENSION_INIT2(pApi) static sqlite3_module csvModule { 0, // iVersion csvvConnect, // xCreate/xConnect // 其他方法实现... }; return sqlite3_create_module(db, csv, csvModule, 0); } // 使用虚拟表 // CREATE VIRTUAL TABLE temp.csv_data USING csv(filenamedata.csv); // SELECT * FROM csv_data;8.3 扩展与插件SQLite支持通过扩展添加功能如加密、JSON支持等// 加载扩展的示例 int rc sqlite3_load_extension(db, ./sqlite3_extensions/json1, NULL, err_msg); if(rc ! SQLITE_OK) { fprintf(stderr, 无法加载扩展: %s\n, err_msg); sqlite3_free(err_msg); } // 使用JSON扩展 // SELECT json_extract(data, $.name) FROM documents;9. 跨平台开发注意事项9.1 文件路径处理在不同操作系统中文件路径表示方法不同// 跨平台路径处理 const char *get_db_path(const char *base_dir, const char *db_name) { static char path[1024]; #if defined(_WIN32) snprintf(path, sizeof(path), %s\\%s, base_dir, db_name); #else snprintf(path, sizeof(path), %s/%s, base_dir, db_name); #endif return path; }9.2 线程安全SQLite支持多线程访问但需要正确配置// 初始化线程安全模式 int rc sqlite3_config(SQLITE_CONFIG_MULTITHREAD); if(rc SQLITE_OK) { rc sqlite3_initialize(); } // 每个线程使用独立的数据库连接 void *worker_thread(void *arg) { sqlite3 *db; int rc sqlite3_open(test.db, db); if(rc ! SQLITE_OK) { // 错误处理 return NULL; } // 线程工作... sqlite3_close(db); return NULL; }9.3 平台特定优化// 针对不同平台设置PRAGMA void configure_database(sqlite3 *db) { #if defined(__linux__) !defined(ANDROID) // Linux服务器环境优化 sqlite3_exec(db, PRAGMA journal_mode WAL;, 0, 0, 0); sqlite3_exec(db, PRAGMA synchronous NORMAL;, 0, 0, 0); sqlite3_exec(db, PRAGMA cache_size -20000;, 0, 0, 0); // 20MB缓存 #elif defined(_WIN32) // Windows环境设置 sqlite3_exec(db, PRAGMA temp_store MEMORY;, 0, 0, 0); #else // 嵌入式或其他环境 sqlite3_exec(db, PRAGMA journal_mode MEMORY;, 0, 0, 0); sqlite3_exec(db, PRAGMA synchronous OFF;, 0, 0, 0); #endif }10. 调试与性能分析10.1 SQLite调试技巧启用SQLite日志// 设置SQLite日志回调 void sqlite_log(void *pArg, int code, const char *msg) { printf(SQLite日志[%d]: %s\n, code, msg); } // 在打开数据库后设置 sqlite3_config(SQLITE_CONFIG_LOG, sqlite_log, NULL);解释查询计划-- 查看SQL语句的执行计划 EXPLAIN QUERY PLAN SELECT * FROM students WHERE class_id 1;性能分析// 启用性能分析 sqlite3_exec(db, PRAGMA profile;, 0, 0, 0); // 执行查询后会输出性能信息10.2 常见错误处理错误代码解析const char *err_str sqlite3_errstr(rc); printf(错误代码 %d: %s\n, rc, err_str);资源泄漏检测// 在调试版本中检查资源泄漏 #ifdef DEBUG #define CHECK_LEAKS() do { \ printf(准备语句未释放: %d\n, sqlite3_stmt_status(db, SQLITE_STMTSTATUS_MAX, 0)); \ } while(0) #else #define CHECK_LEAKS() #endif内存使用统计// 获取内存使用情况 int current sqlite3_memory_used(); int highwater sqlite3_memory_highwater(0); printf(内存使用: 当前%d字节, 峰值%d字节\n, current, highwater);11. 工具与资源推荐11.1 图形化管理工具DB Browser for SQLite开源跨平台工具提供可视化表设计、数据浏览和SQL编辑功能SQLiteStudio功能更丰富的开源工具支持插件扩展Navicat for SQLite商业软件功能强大支持数据同步和导入导出11.2 性能分析工具sqlite3_analyzerSQLite官方提供的分析工具统计表和索引的空间使用情况sqltune用于分析SQL查询性能提供优化建议11.3 学习资源官方文档SQLite官方网站完整的C语言API参考书籍推荐《The Definitive Guide to SQLite》《SQLite权威指南》在线课程Udemy上的SQLite相关课程Coursera的数据库基础课程12. 项目实战构建完整应用12.1 需求分析我们将开发一个个人任务管理系统具有以下功能任务分类管理优先级设置截止日期提醒任务搜索与过滤数据备份与恢复12.2 数据库设计-- 分类表 CREATE TABLE categories ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, color TEXT ); -- 任务表 CREATE TABLE tasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, description TEXT, priority INTEGER DEFAULT 1 CHECK(priority BETWEEN 1 AND 5), due_date INTEGER, -- Unix时间戳 created_at INTEGER DEFAULT (strftime(%s, now)), completed INTEGER DEFAULT 0, category_id INTEGER, FOREIGN KEY (category_id) REFERENCES categories(id) ); -- 子任务表 CREATE TABLE subtasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, task_id INTEGER NOT NULL, description TEXT NOT NULL, completed INTEGER DEFAULT 0, FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE ); -- 创建索引 CREATE INDEX idx_tasks_priority ON tasks(priority); CREATE INDEX idx_tasks_due_date ON tasks(due_date); CREATE INDEX idx_tasks_category ON tasks(category_id);12.3 核心功能实现初始化数据库int init_database(const char *db_path) { sqlite3 *db; int rc sqlite3_open(db_path, db); if(rc ! SQLITE_OK) return rc; // 启用外键约束 sqlite3_exec(db, PRAGMA foreign_keys ON;, 0, 0, 0); // 创建表 const char *sql CREATE TABLE IF NOT EXISTS categories ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, color TEXT); CREATE TABLE IF NOT EXISTS tasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, description TEXT, priority INTEGER DEFAULT 1 CHECK(priority BETWEEN 1 AND 5), due_date INTEGER, created_at INTEGER DEFAULT (strftime(%s, now)), completed INTEGER DEFAULT 0, category_id INTEGER, FOREIGN KEY (category_id) REFERENCES categories(id)); CREATE TABLE IF NOT EXISTS subtasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, task_id INTEGER NOT NULL, description TEXT NOT NULL, completed INTEGER DEFAULT 0, FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE);; rc sqlite3_exec(db, sql, 0, 0, 0); sqlite3_close(db); return rc; }添加任务int add_task(sqlite3 *db, const char *title, const char *desc, int priority, time_t due_date, int category_id) { sqlite3_stmt *stmt; const char *sql INSERT INTO tasks (title, description, priority, due_date, category_id) VALUES (?, ?, ?, ?, ?);; int rc sqlite3_prepare_v2(db, sql, -1, stmt, NULL); if(rc ! SQLITE_OK) return rc; sqlite3_bind_text(stmt, 1, title, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, desc, -1, SQLITE_STATIC); sqlite3_bind_int(stmt, 3, priority); sqlite3_bind_int64(stmt, 4, due_date); if(category_id 0) { sqlite3_bind_int(stmt, 5, category_id); } else { sqlite3_bind_null(st

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询