[{"data":1,"prerenderedAt":755},["ShallowReactive",2],{"doc-\u002Fdocs\u002Ftutorial\u002Feduwin-sqlite":3},{"id":4,"title":5,"body":6,"description":748,"extension":749,"meta":750,"navigation":61,"path":751,"seo":752,"stem":753,"__hash__":754},"content\u002Fdocs\u002Ftutorial\u002Feduwin-sqlite.md","eduwin + SQLite 数据库编程",{"type":7,"value":8,"toc":737},"minimark",[9,13,26,29,33,237,240,252,265,267,271,274,279,294,317,321,341,348,363,367,498,506,512,567,570,574,583,585,588,599,614,640,650,653,697,699,703,713,716,733],[10,11,5],"h1",{"id":12},"eduwin-sqlite-数据库编程",[14,15,16,17,21,22,25],"p",{},"SQLite 是一个自包含、零配置、嵌入式的 C 语言数据库引擎。eduwin 已将 SQLite 编译进 ",[18,19,20],"code",{},"eduwin.lib","，学生程序只需 ",[18,23,24],{},"#include \"sqlite3.h\""," 即可直接使用，无需额外配置。",[27,28],"hr",{},[30,31,32],"h2",{"id":32},"快速开始",[34,35,40],"pre",{"className":36,"code":37,"language":38,"meta":39,"style":39},"language-c shiki shiki-themes github-light github-dark","#include \"eduwin.h\"\n#include \"sqlite3.h\"\n\nint main(void)\n{\n    init_app();\n\n    sqlite3 *db = NULL;\n    int rc = sqlite3_open(\"test.db\", &db);\n    if (rc != SQLITE_OK)\n    {\n        alert(L\"错误\", L\"无法打开数据库\");\n        return 1;\n    }\n\n    char *err = NULL;\n    sqlite3_exec(db, \"CREATE TABLE IF NOT EXISTS users (\"\n                     \"id INTEGER PRIMARY KEY AUTOINCREMENT, \"\n                     \"name TEXT NOT NULL, \"\n                     \"email TEXT)\", NULL, NULL, &err);\n    if (err)\n    {\n        alert(L\"错误\", L\"建表失败\");\n        sqlite3_free(err);\n    }\n\n    HWND win = create_window(L\"SQLite 测试\", 500, 300);\n    show_window(win);\n    run_app();\n\n    sqlite3_close(db);\n    return 0;\n}\n","c","",[18,41,42,50,56,63,69,75,81,86,92,98,104,110,116,122,128,133,139,145,151,157,163,169,174,180,186,191,196,202,208,214,219,225,231],{"__ignoreMap":39},[43,44,47],"span",{"class":45,"line":46},"line",1,[43,48,49],{},"#include \"eduwin.h\"\n",[43,51,53],{"class":45,"line":52},2,[43,54,55],{},"#include \"sqlite3.h\"\n",[43,57,59],{"class":45,"line":58},3,[43,60,62],{"emptyLinePlaceholder":61},true,"\n",[43,64,66],{"class":45,"line":65},4,[43,67,68],{},"int main(void)\n",[43,70,72],{"class":45,"line":71},5,[43,73,74],{},"{\n",[43,76,78],{"class":45,"line":77},6,[43,79,80],{},"    init_app();\n",[43,82,84],{"class":45,"line":83},7,[43,85,62],{"emptyLinePlaceholder":61},[43,87,89],{"class":45,"line":88},8,[43,90,91],{},"    sqlite3 *db = NULL;\n",[43,93,95],{"class":45,"line":94},9,[43,96,97],{},"    int rc = sqlite3_open(\"test.db\", &db);\n",[43,99,101],{"class":45,"line":100},10,[43,102,103],{},"    if (rc != SQLITE_OK)\n",[43,105,107],{"class":45,"line":106},11,[43,108,109],{},"    {\n",[43,111,113],{"class":45,"line":112},12,[43,114,115],{},"        alert(L\"错误\", L\"无法打开数据库\");\n",[43,117,119],{"class":45,"line":118},13,[43,120,121],{},"        return 1;\n",[43,123,125],{"class":45,"line":124},14,[43,126,127],{},"    }\n",[43,129,131],{"class":45,"line":130},15,[43,132,62],{"emptyLinePlaceholder":61},[43,134,136],{"class":45,"line":135},16,[43,137,138],{},"    char *err = NULL;\n",[43,140,142],{"class":45,"line":141},17,[43,143,144],{},"    sqlite3_exec(db, \"CREATE TABLE IF NOT EXISTS users (\"\n",[43,146,148],{"class":45,"line":147},18,[43,149,150],{},"                     \"id INTEGER PRIMARY KEY AUTOINCREMENT, \"\n",[43,152,154],{"class":45,"line":153},19,[43,155,156],{},"                     \"name TEXT NOT NULL, \"\n",[43,158,160],{"class":45,"line":159},20,[43,161,162],{},"                     \"email TEXT)\", NULL, NULL, &err);\n",[43,164,166],{"class":45,"line":165},21,[43,167,168],{},"    if (err)\n",[43,170,172],{"class":45,"line":171},22,[43,173,109],{},[43,175,177],{"class":45,"line":176},23,[43,178,179],{},"        alert(L\"错误\", L\"建表失败\");\n",[43,181,183],{"class":45,"line":182},24,[43,184,185],{},"        sqlite3_free(err);\n",[43,187,189],{"class":45,"line":188},25,[43,190,127],{},[43,192,194],{"class":45,"line":193},26,[43,195,62],{"emptyLinePlaceholder":61},[43,197,199],{"class":45,"line":198},27,[43,200,201],{},"    HWND win = create_window(L\"SQLite 测试\", 500, 300);\n",[43,203,205],{"class":45,"line":204},28,[43,206,207],{},"    show_window(win);\n",[43,209,211],{"class":45,"line":210},29,[43,212,213],{},"    run_app();\n",[43,215,217],{"class":45,"line":216},30,[43,218,62],{"emptyLinePlaceholder":61},[43,220,222],{"class":45,"line":221},31,[43,223,224],{},"    sqlite3_close(db);\n",[43,226,228],{"class":45,"line":227},32,[43,229,230],{},"    return 0;\n",[43,232,234],{"class":45,"line":233},33,[43,235,236],{},"}\n",[14,238,239],{},"编译命令：",[34,241,245],{"className":242,"code":243,"language":244,"meta":39,"style":39},"language-bash shiki shiki-themes github-light github-dark","build.bat\n","bash",[18,246,247],{"__ignoreMap":39},[43,248,249],{"class":45,"line":46},[43,250,243],{"class":251},"sScJk",[14,253,254,255,258,259,261,262,264],{},"只要在 ",[18,256,257],{},".c"," 文件中 ",[18,260,24],{},"，link 时自动从 ",[18,263,20],{}," 获取 SQLite 实现。",[27,266],{},[30,268,270],{"id":269},"核心-api","核心 API",[14,272,273],{},"SQLite 最常用的三个函数：",[275,276,278],"h3",{"id":277},"打开关闭","打开\u002F关闭",[34,280,282],{"className":36,"code":281,"language":38,"meta":39,"style":39},"int sqlite3_open(const char *filename, sqlite3 **ppDb);\nint sqlite3_close(sqlite3 *db);\n",[18,283,284,289],{"__ignoreMap":39},[43,285,286],{"class":45,"line":46},[43,287,288],{},"int sqlite3_open(const char *filename, sqlite3 **ppDb);\n",[43,290,291],{"class":45,"line":52},[43,292,293],{},"int sqlite3_close(sqlite3 *db);\n",[295,296,297,304,310],"ul",{},[298,299,300,303],"li",{},[18,301,302],{},"sqlite3_open"," 打开或创建数据库文件（UTF-8 路径）",[298,305,306,309],{},[18,307,308],{},"sqlite3_close"," 关闭数据库，释放资源",[298,311,312,313,316],{},"返回 ",[18,314,315],{},"SQLITE_OK","（0）表示成功",[275,318,320],{"id":319},"执行-sql","执行 SQL",[34,322,324],{"className":36,"code":323,"language":38,"meta":39,"style":39},"int sqlite3_exec(sqlite3 *db, const char *sql,\n                 int (*callback)(void *, int, char **, char **),\n                 void *data, char **errmsg);\n",[18,325,326,331,336],{"__ignoreMap":39},[43,327,328],{"class":45,"line":46},[43,329,330],{},"int sqlite3_exec(sqlite3 *db, const char *sql,\n",[43,332,333],{"class":45,"line":52},[43,334,335],{},"                 int (*callback)(void *, int, char **, char **),\n",[43,337,338],{"class":45,"line":58},[43,339,340],{},"                 void *data, char **errmsg);\n",[14,342,343,344,347],{},"最简单的执行方式——不需要回调时传 ",[18,345,346],{},"NULL","：",[34,349,351],{"className":36,"code":350,"language":38,"meta":39,"style":39},"sqlite3_exec(db, \"INSERT INTO users VALUES(NULL, '张三', 'zhangsan@test.com')\",\n             NULL, NULL, &err);\n",[18,352,353,358],{"__ignoreMap":39},[43,354,355],{"class":45,"line":46},[43,356,357],{},"sqlite3_exec(db, \"INSERT INTO users VALUES(NULL, '张三', 'zhangsan@test.com')\",\n",[43,359,360],{"class":45,"line":52},[43,361,362],{},"             NULL, NULL, &err);\n",[275,364,366],{"id":365},"带参数查询推荐","带参数查询（推荐）",[34,368,370],{"className":36,"code":369,"language":38,"meta":39,"style":39},"\u002F* 根据学号查询用户，返回姓名，未找到返回 NULL *\u002F\nconst char *find_user_name(sqlite3 *db, int user_id)\n{\n    sqlite3_stmt *stmt = NULL;\n\n    \u002F* 1. 准备 SQL（？是占位符） *\u002F\n    int rc = sqlite3_prepare_v2(db,\n                \"SELECT name FROM users WHERE id = ?\",\n                -1, &stmt, NULL);\n    if (rc != SQLITE_OK)\n        return NULL;\n\n    \u002F* 2. 绑定参数（第 1 个 ? 绑定 user_id） *\u002F\n    sqlite3_bind_int(stmt, 1, user_id);\n\n    \u002F* 3. 执行查询 *\u002F\n    const char *result = NULL;\n    if (sqlite3_step(stmt) == SQLITE_ROW)\n    {\n        \u002F* 4. 读取结果集第 0 列 *\u002F\n        result = strdup((const char *)sqlite3_column_text(stmt, 0));\n    }\n\n    \u002F* 5. 释放语句 *\u002F\n    sqlite3_finalize(stmt);\n    return result;\n}\n",[18,371,372,377,382,386,391,395,400,405,410,415,419,424,428,433,438,442,447,452,457,461,466,471,475,479,484,489,494],{"__ignoreMap":39},[43,373,374],{"class":45,"line":46},[43,375,376],{},"\u002F* 根据学号查询用户，返回姓名，未找到返回 NULL *\u002F\n",[43,378,379],{"class":45,"line":52},[43,380,381],{},"const char *find_user_name(sqlite3 *db, int user_id)\n",[43,383,384],{"class":45,"line":58},[43,385,74],{},[43,387,388],{"class":45,"line":65},[43,389,390],{},"    sqlite3_stmt *stmt = NULL;\n",[43,392,393],{"class":45,"line":71},[43,394,62],{"emptyLinePlaceholder":61},[43,396,397],{"class":45,"line":77},[43,398,399],{},"    \u002F* 1. 准备 SQL（？是占位符） *\u002F\n",[43,401,402],{"class":45,"line":83},[43,403,404],{},"    int rc = sqlite3_prepare_v2(db,\n",[43,406,407],{"class":45,"line":88},[43,408,409],{},"                \"SELECT name FROM users WHERE id = ?\",\n",[43,411,412],{"class":45,"line":94},[43,413,414],{},"                -1, &stmt, NULL);\n",[43,416,417],{"class":45,"line":100},[43,418,103],{},[43,420,421],{"class":45,"line":106},[43,422,423],{},"        return NULL;\n",[43,425,426],{"class":45,"line":112},[43,427,62],{"emptyLinePlaceholder":61},[43,429,430],{"class":45,"line":118},[43,431,432],{},"    \u002F* 2. 绑定参数（第 1 个 ? 绑定 user_id） *\u002F\n",[43,434,435],{"class":45,"line":124},[43,436,437],{},"    sqlite3_bind_int(stmt, 1, user_id);\n",[43,439,440],{"class":45,"line":130},[43,441,62],{"emptyLinePlaceholder":61},[43,443,444],{"class":45,"line":135},[43,445,446],{},"    \u002F* 3. 执行查询 *\u002F\n",[43,448,449],{"class":45,"line":141},[43,450,451],{},"    const char *result = NULL;\n",[43,453,454],{"class":45,"line":147},[43,455,456],{},"    if (sqlite3_step(stmt) == SQLITE_ROW)\n",[43,458,459],{"class":45,"line":153},[43,460,109],{},[43,462,463],{"class":45,"line":159},[43,464,465],{},"        \u002F* 4. 读取结果集第 0 列 *\u002F\n",[43,467,468],{"class":45,"line":165},[43,469,470],{},"        result = strdup((const char *)sqlite3_column_text(stmt, 0));\n",[43,472,473],{"class":45,"line":171},[43,474,127],{},[43,476,477],{"class":45,"line":176},[43,478,62],{"emptyLinePlaceholder":61},[43,480,481],{"class":45,"line":182},[43,482,483],{},"    \u002F* 5. 释放语句 *\u002F\n",[43,485,486],{"class":45,"line":188},[43,487,488],{},"    sqlite3_finalize(stmt);\n",[43,490,491],{"class":45,"line":193},[43,492,493],{},"    return result;\n",[43,495,496],{"class":45,"line":198},[43,497,236],{},[14,499,500,501,505],{},"流程：",[502,503,504],"strong",{},"准备 → 绑定 → 单步执行 → 读列 → 销毁","。",[14,507,508,511],{},[18,509,510],{},"?"," 是占位符，从 1 开始编号。多参数时：",[34,513,515],{"className":36,"code":514,"language":38,"meta":39,"style":39},"\u002F* UPDATE 示例：带三个占位符 *\u002F\nsqlite3_stmt *stmt;\nsqlite3_prepare_v2(db,\n    \"UPDATE users SET name = ?, email = ? WHERE id = ?\",\n    -1, &stmt, NULL);\nsqlite3_bind_text(stmt, 1, name_utf8, -1, SQLITE_TRANSIENT);\nsqlite3_bind_text(stmt, 2, email_utf8, -1, SQLITE_TRANSIENT);\nsqlite3_bind_int(stmt,  3, user_id);\nsqlite3_step(stmt);\nsqlite3_finalize(stmt);\n",[18,516,517,522,527,532,537,542,547,552,557,562],{"__ignoreMap":39},[43,518,519],{"class":45,"line":46},[43,520,521],{},"\u002F* UPDATE 示例：带三个占位符 *\u002F\n",[43,523,524],{"class":45,"line":52},[43,525,526],{},"sqlite3_stmt *stmt;\n",[43,528,529],{"class":45,"line":58},[43,530,531],{},"sqlite3_prepare_v2(db,\n",[43,533,534],{"class":45,"line":65},[43,535,536],{},"    \"UPDATE users SET name = ?, email = ? WHERE id = ?\",\n",[43,538,539],{"class":45,"line":71},[43,540,541],{},"    -1, &stmt, NULL);\n",[43,543,544],{"class":45,"line":77},[43,545,546],{},"sqlite3_bind_text(stmt, 1, name_utf8, -1, SQLITE_TRANSIENT);\n",[43,548,549],{"class":45,"line":83},[43,550,551],{},"sqlite3_bind_text(stmt, 2, email_utf8, -1, SQLITE_TRANSIENT);\n",[43,553,554],{"class":45,"line":88},[43,555,556],{},"sqlite3_bind_int(stmt,  3, user_id);\n",[43,558,559],{"class":45,"line":94},[43,560,561],{},"sqlite3_step(stmt);\n",[43,563,564],{"class":45,"line":100},[43,565,566],{},"sqlite3_finalize(stmt);\n",[14,568,569],{},"始终使用参数绑定而非字符串拼接，可防止 SQL 注入。",[275,571,573],{"id":572},"获取最后插入的-id","获取最后插入的 ID",[34,575,577],{"className":36,"code":576,"language":38,"meta":39,"style":39},"int last_id = (int)sqlite3_last_insert_rowid(db);\n",[18,578,579],{"__ignoreMap":39},[43,580,581],{"class":45,"line":46},[43,582,576],{},[27,584],{},[30,586,587],{"id":587},"字符串编码",[14,589,590,591,594,595,598],{},"SQLite 的 API 使用 ",[502,592,593],{},"UTF-8"," 编码，而 eduwin 使用 ",[502,596,597],{},"UTF-16（宽字符）","。eduwin 提供两个内置工具函数完成互转：",[34,600,602],{"className":36,"code":601,"language":38,"meta":39,"style":39},"char *wtou8(const WCHAR *ws);\nWCHAR *u8tow(const char *us);\n",[18,603,604,609],{"__ignoreMap":39},[43,605,606],{"class":45,"line":46},[43,607,608],{},"char *wtou8(const WCHAR *ws);\n",[43,610,611],{"class":45,"line":52},[43,612,613],{},"WCHAR *u8tow(const char *us);\n",[295,615,616,630],{},[298,617,618,621,622,625,626,629],{},[18,619,620],{},"wtou8","：宽字符串 → UTF-8 字符串（",[18,623,624],{},"malloc"," 分配内存，用完需 ",[18,627,628],{},"free","）",[298,631,632,635,636,625,638,629],{},[18,633,634],{},"u8tow","：UTF-8 字符串 → 宽字符串（",[18,637,624],{},[18,639,628],{},[14,641,642,643,645,646,649],{},"这两个函数已编译在 ",[18,644,20],{}," 中，",[18,647,648],{},"#include \"eduwin.h\""," 即可使用。",[14,651,652],{},"用法：",[34,654,656],{"className":36,"code":655,"language":38,"meta":39,"style":39},"char *sql = wtou8(L\"INSERT INTO users VALUES(NULL, '测试用户', 'test@test.com')\");\nsqlite3_exec(db, sql, NULL, NULL, &err);\nfree(sql);\n\nconst char *name8 = (const char *)sqlite3_column_text(stmt, 1);\nWCHAR *name16 = u8tow(name8);\nset_text(label, name16);\nfree(name16);\n",[18,657,658,663,668,673,677,682,687,692],{"__ignoreMap":39},[43,659,660],{"class":45,"line":46},[43,661,662],{},"char *sql = wtou8(L\"INSERT INTO users VALUES(NULL, '测试用户', 'test@test.com')\");\n",[43,664,665],{"class":45,"line":52},[43,666,667],{},"sqlite3_exec(db, sql, NULL, NULL, &err);\n",[43,669,670],{"class":45,"line":58},[43,671,672],{},"free(sql);\n",[43,674,675],{"class":45,"line":65},[43,676,62],{"emptyLinePlaceholder":61},[43,678,679],{"class":45,"line":71},[43,680,681],{},"const char *name8 = (const char *)sqlite3_column_text(stmt, 1);\n",[43,683,684],{"class":45,"line":77},[43,685,686],{},"WCHAR *name16 = u8tow(name8);\n",[43,688,689],{"class":45,"line":83},[43,690,691],{},"set_text(label, name16);\n",[43,693,694],{"class":45,"line":88},[43,695,696],{},"free(name16);\n",[27,698],{},[30,700,702],{"id":701},"完整示例用户管理","完整示例：用户管理",[14,704,705,708,709,712],{},[18,706,707],{},"demo\\sqlite_demo.c"," 是一个完整的用户信息管理程序，演示了增删改查全部操作，可直接编译运行（",[18,710,711],{},"demo\\build_sqlite_demo.bat","）：",[14,714,715],{},"功能包括：",[295,717,718,721,724,727,730],{},[298,719,720],{},"列表显示所有用户（ListView）",[298,722,723],{},"添加用户（姓名、邮箱、电话）",[298,725,726],{},"双击列表项回填到输入框，修改后保存",[298,728,729],{},"选中用户后删除",[298,731,732],{},"实时搜索过滤",[734,735,736],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":39,"searchDepth":52,"depth":52,"links":738},[739,740,746,747],{"id":32,"depth":52,"text":32},{"id":269,"depth":52,"text":270,"children":741},[742,743,744,745],{"id":277,"depth":58,"text":278},{"id":319,"depth":58,"text":320},{"id":365,"depth":58,"text":366},{"id":572,"depth":58,"text":573},{"id":587,"depth":52,"text":587},{"id":701,"depth":52,"text":702},"SQLite 是一个自包含、零配置、嵌入式的 C 语言数据库引擎。eduwin 已将 SQLite 编译进 eduwin.lib，学生程序只需 #include \"sqlite3.h\" 即可直接使用，无需额外配置。","md",{},"\u002Fdocs\u002Ftutorial\u002Feduwin-sqlite",{"title":5,"description":748},"docs\u002Ftutorial\u002Feduwin-sqlite","2Crz_HJ9w9O9YzgATSB1f3B9FwdGw9RcrliXjf8sVk4",1782488679846]