sqlite创建数据库,创建表,插入数据,查询数据的C++ demo

sqlite的API可参考:SQLite -- C/C++ | 菜鸟教程

sqlite的官网API可参考:Introduction

cpp 复制代码
#include <iostream>
#include <sqlite3.h>
#include <string>

// 回调函数,用于查询结果的输出
static int callback(void* data, int argc, char** argv, char** azColName) {
    // 第一次调用时输出表名
    static bool firstCall = true;
    static std::string tableName = reinterpret_cast<const char*>(data);

    if (firstCall) {
        std::cout << "\n表名: " << tableName << std::endl;
        std::cout << "--------------------------------" << std::endl;

        // 输出列名
        for (int i = 0; i < argc; i++) {
            std::cout << azColName[i] << "\t";
        }
        std::cout << "\n--------------------------------" << std::endl;
        firstCall = false;
    }

    // 输出数据行
    for (int i = 0; i < argc; i++) {
        std::cout << (argv[i] ? argv[i] : "") << "\t";
    }
    std::cout << std::endl;

    return 0;
}

int main() {
    sqlite3* db;
    char* errMsg = nullptr;
    int rc;

    // 1. 打开或创建数据库
    rc = sqlite3_open("demo.db", &db);
    if (rc) {
        std::cerr << "无法打开数据库: " << sqlite3_errmsg(db) << std::endl;
        return rc;
    }

    std::cout << "成功打开/创建数据库 demo.db" << std::endl;

    // 2. 创建表
    const char* createTableSQL =
        "CREATE TABLE IF NOT EXISTS Users ("
        "ID INTEGER PRIMARY KEY AUTOINCREMENT,"
        "Name TEXT NOT NULL,"
        "Age INTEGER,"
        "Email TEXT UNIQUE NOT NULL);";

    rc = sqlite3_exec(db, createTableSQL, nullptr, nullptr, &errMsg);
    printf("%s\n",createTableSQL);
    if (rc != SQLITE_OK) {
        std::cerr << "SQL错误: " << errMsg << std::endl;
        sqlite3_free(errMsg);
    } else {
        std::cout << "表 Users 创建成功或已存在" << std::endl;
    }

    // 3. 插入数据
    const char* insertDataSQL =
        "INSERT INTO Users (Name, Age, Email) VALUES "
        "('张三', 25, 'zhangsan@example.com'),"
        "('李四', 30, 'lisi@example.com'),"
        "('王五', 28, 'wangwu@example.com');";

    rc = sqlite3_exec(db, insertDataSQL, nullptr, nullptr, &errMsg);
    if (rc != SQLITE_OK) {
        std::cerr << "SQL错误: " << errMsg << std::endl;
        sqlite3_free(errMsg);
    } else {
        std::cout << "成功插入 3 条数据到 Users 表" << std::endl;
    }

    // 4. 查询数据
    std::string tableName = "Users";
    const char* selectDataSQL = "SELECT * FROM Users;";

    std::cout << "\n正在查询数据..." << std::endl;
    rc = sqlite3_exec(db, selectDataSQL, callback, const_cast<char*>(tableName.c_str()), &errMsg);

    if (rc != SQLITE_OK) {
        std::cerr << "SQL错误: " << errMsg << std::endl;
        sqlite3_free(errMsg);
    }

    // 5. 关闭数据库
    sqlite3_close(db);
    std::cout << "\n数据库连接已关闭" << std::endl;

    return 0;
}

CMake如下:

cpp 复制代码
cmake_minimum_required(VERSION 3.5)

project(testDB LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(testDB main.cpp)
target_link_libraries(testDB sqlite3)

运行结果如下:

sqlite3_exec函数介绍

sqlite3_exec() 是 SQLite C 接口中的一个便捷函数,用于执行一个或多个 SQL 语句,并可选择性地处理查询结果。它是 sqlite3_prepare_v2()sqlite3_step()sqlite3_finalize() 的封装,适合执行不需要复杂处理的 SQL 命令。


函数原型

|--------------------------------------------------|
| int sqlite3_exec( |
| sqlite3 *db, /* 数据库连接对象 */ |
| const char *sql, /* 要执行的 SQL 语句 */ |
| int (*callback)( /* 回调函数,处理查询结果 */ |
| void*, /* 回调函数的第一个参数(由sqlite3_exec的第四个参数传入) */ |
| int, /* 结果行的列数 */ |
| char**, /* 当前行的数据数组 */ |
| char** /* 列名数组 */ |
| ), |
| void *data, /* 传递给回调函数的第一个参数 */ |
| char **errmsg /* 错误信息(需手动释放) */ |
| ); |


参数详解

1. db
  • 类型 : sqlite3*
  • 作用 : 已打开的数据库连接对象(通过 sqlite3_open() 获得)。
  • 注意 : 如果为 `` 或无效连接,函数返回 SQLITE_MISUSE
2. sql
  • 类型 : const char*

  • 作用 : 要执行的 SQL 语句,可以是单个语句或多个语句(用分号 ; 分隔)。

  • 示例 :

    sql

    |------------------------------------------------------------------|
    | "CREATE TABLE test (id INTEGER); INSERT INTO test VALUES (1);" |

  • 注意 :

    • 如果 SQL 有语法错误,sqlite3_exec() 会返回错误码,并通过 errmsg 返回错误信息。
    • 不支持参数绑定(如 ?:name),需直接拼接 SQL 字符串(需注意 SQL 注入风险)。
3. callback
  • 类型 : 函数指针 int (*callback)(void*, int, char**, char**)

  • 作用 : 处理查询结果的回调函数。对 SELECT 查询的每一行结果调用一次;对 INSERT/UPDATE/DELETE 等操作不调用(除非返回影响行数)。

  • 回调函数参数 :

    • void* data: 由 sqlite3_exec 的第四个参数 data 传入(通常用于传递上下文)。
    • int argc: 当前行的列数。
    • char** argv: 当前行的数据数组(argv[i] 是第 i 列的值,字符串形式)。
    • char** azColName: 列名数组(azColName[i] 是第 i 列的名称)。
  • 返回值 :

    • 返回 0 表示继续处理后续行。
    • 返回非零值会中断查询,sqlite3_exec() 会立即返回 SQLITE_ABORT
  • 示例 :

    |-----------------------------------------------------------------------------|
    | static int callback(void *data, int argc, char **argv, char **colNames) { |
    | for (int i = 0; i < argc; i++) { |
    | printf("%s = %s\n", colNames[i], argv[i] ? argv[i] : ""); |
    | } |
    | return 0; |
    | } |

4. data
  • 类型 : void*

  • 作用 : 传递给回调函数的第一个参数(callbackvoid* data)。

  • 用途: 通常用于传递上下文信息(如输出文件名、表名等)。

  • 示例 :

    |----------------------------------------------------------------------------------|
    | const char* tableName = "Users"; |
    | sqlite3_exec(db, "SELECT * FROM Users;", callback, (void*)tableName, &errMsg); |

5. errmsg
  • 类型 : char**

  • 作用: 指向错误信息字符串的指针。如果执行失败,SQLite 会分配错误信息(需手动释放)。

  • 注意 :

    • 成功时 *errmsg 为 ``。
    • 失败时需调用 sqlite3_free(*errmsg) 释放内存。
    • 如果传入的 errmsg 为 ``,错误信息不会被返回。
  • 示例 :

    |------------------------------------------------------------------------|
    | char *errMsg = nullptr; |
    | int rc = sqlite3_exec(db, "INVALID SQL", nullptr, nullptr, &errMsg); |
    | if (rc != SQLITE_OK) { |
    | std::cerr << "Error: " << errMsg << std::endl; |
    | sqlite3_free(errMsg); // 必须释放! |
    | } |


返回值

  • SQLITE_OK (0): 执行成功。
  • 其他错误码 (如 SQLITE_ERROR, SQLITE_MISUSE): 表示执行失败,可通过 errmsg 获取详情。

典型用法

1. 执行非查询语句(如 CREATE/INSERT)

|--------------------------------------------------------------|
| char *errMsg = nullptr; |
| int rc = sqlite3_exec(db, |
| "CREATE TABLE IF NOT EXISTS test (id INTEGER, name TEXT);" |
| "INSERT INTO test VALUES (1, 'Alice');", |
| nullptr, nullptr, &errMsg); |
| |
| if (rc != SQLITE_OK) { |
| fprintf(stderr, "SQL error: %s\n", errMsg); |
| sqlite3_free(errMsg); |
| } |

2. 执行查询并处理结果

|-------------------------------------------------------------------------------|
| static int printRow(void *unused, int argc, char **argv, char **colNames) { |
| for (int i = 0; i < argc; i++) { |
| printf("%s: %s\n", colNames[i], argv[i] ? argv[i] : ""); |
| } |
| printf("---\n"); |
| return 0; |
| } |
| |
| sqlite3_exec(db, "SELECT * FROM test;", printRow, nullptr, &errMsg); |


注意事项

  1. SQL 注入风险 :
    sqlite3_exec 直接执行 SQL 字符串,避免拼接用户输入。如需参数化查询,应使用 sqlite3_prepare_v2() + sqlite3_bind_*()

  2. 错误处理 :

    始终检查返回值,并释放 errmsg(如果非)。

  3. 性能 :

    不适合大量数据操作(每次调用会重新解析 SQL)。高频操作建议使用预处理语句(Prepared Statements)。

  4. 多语句执行 :

    可通过分号 ; 分隔多个 SQL 语句,但某条语句失败时,后续语句不会执行。


其他函数

如果需要更精细的控制(如参数绑定、事务处理),建议使用:

  1. sqlite3_prepare_v2()
  2. sqlite3_bind_*()
  3. sqlite3_step()
  4. sqlite3_finalize()

例如:

|---------------------------------------------------------------------------------|
| sqlite3_stmt *stmt; |
| sqlite3_prepare_v2(db, "INSERT INTO test VALUES (?, ?)", -1, &stmt, nullptr); |
| sqlite3_bind_int(stmt, 1, 2); |
| sqlite3_bind_text(stmt, 2, "Bob", -1, SQLITE_STATIC); |
| sqlite3_step(stmt); |
| sqlite3_finalize(stmt); |

sqlite的demo可参考:SQLite3 - Linux C上数据库开发(基本操作,这篇够了)_linux 上c语言使用sqlite3-CSDN博客

Sqlite3小结(小型数据库中增删改查的操作)_如何获得sqlite3库表的记录的大小-CSDN博客

参加上面的连接查看数据代码也可以写成下面代码:

cpp 复制代码
//获取行数
    int nrow,ncolumn;
    char selectCmd[]="select * from Users;";
    char **result;
    if(sqlite3_get_table(db,selectCmd,&result,&nrow,&ncolumn,&errMsg)!=0)
    {

        std::cerr << "SQL错误: " << errMsg << std::endl;
        sqlite3_free(errMsg);
    }
    printf("nrow is %d, ncolumn is %d\n",nrow,ncolumn);//测试输出
    int i,j=0;
    for(i=1;i<=nrow;i++)//result内结果包含表头信息,因此result[0]是表头信息,实际数据范围为result[1]~result[nrow]
    {

        for(j=0;j<ncolumn;j++)

        {

            printf("%s:%s\n",result[j],result[i*ncolumn+j]);

        }

        printf("------------------\n");

    }

运行结果如下:

相关推荐
TDengine (老段)11 分钟前
TDengine IDMP 应用场景:工业锅炉监控
大数据·数据库·物联网·信息可视化·时序数据库·tdengine
dreams_dream2 小时前
Django的Settings 配置文件详解
数据库·django·sqlite
遇见你的雩风3 小时前
【MySQL】CRUD基础详解
数据库·mysql
.Shu.6 小时前
Mysql InnoDB 底层架构设计、功能、原理、源码系列合集【四、事务引擎核心 - MVCC与锁机制】
数据库·mysql
多工坊6 小时前
【DataGrip】连接达梦数据库后,能查询数据但是看不到表的几种情况分析,达梦数据库驱动包下载DmJdbcDriver18.jar
java·数据库·jar
何中应7 小时前
如何用Redis作为消息队列
数据库·redis·缓存
liulilittle7 小时前
.NET反射与IL反编译核心技术
开发语言·数据库·c#·.net·反射·反编译·il
老纪的技术唠嗑局7 小时前
向量数据库在 UGC 社区个性化推荐的落地指南
数据库
张鱼小丸子8 小时前
MySQL企业级部署与高可用实战
运维·数据库·mysql·云原生·高可用·mha·组从复制