SQLite数据库(数据库和链表双向转换)

news2024/12/23 17:46:08

文章目录

  • SQLite数据库
    • 一、SQLite简介
      • 1、SQLite和MySQL
      • 2、基于嵌入式的数据库
    • 二、SQLite数据库安装
    • 三、SQLite的常用命令
    • 四、SQLite的编程操作
      • 1、SQLite数据库相关API
        • (1)头文件
        • (2)sqlite3_open()
        • (3)sqlite3_close()
        • (4)sqlite3_errmsg()
        • (5)sqlite3_exec()
        • (6)sqlite3_prepare_v2()
        • (7)sqlite3_step()
        • (8)sqlite3_column_*
        • (9)sqlite3_mprintf()
      • 2、编程实现
        • (1)打开数据库
        • (2)实现增删改查
          • 1.向数据库中增加数据:创建一个表,并且插入三条数据
          • 2.更改数据库中的数据:将数据库中num = 1的color改成white
          • 3.删除num = 1 的数据
        • (3)链表和SQLite数据转换
          • 1.静态链表插入SQLite
          • 2.动态创建链表插入数据库
          • 3.链表方式读取SQLite数据

SQLite数据库

一、SQLite简介

轻量化,易用的嵌入式数据库,用于设备端的数据管理,可以理解成单点的数据库。传统服务器型数据
库用于管理多端设备,更加复杂。

1、SQLite和MySQL

  • SQLite是一个无服务器的数据库,是自包含的。这也称为嵌入式数据库,这意味着数据库引擎作为
    应用程序的一部分运行。

  • MySQL需要运行服务器,MySQL将需要客户端和服务器架构通过网络进行交互。

数据库优点缺点
SQLite基于文件,易于设置和使用适合基础开发和测试,轻松携带使用标准SQL语法,进行微小修改使用方便缺乏用户管理和安全功能,不容易扩展,不适合大数据库无法定制
MySQL使用方便,提供了许多与数据库相关的功能良好的安全功能易于扩展,适用于大型数据库。提供良好的速度和性能提供良好的用户管理和多种访问控制需要一些技术专业知识来设置与传统SQL相比,语法略有不同

2、基于嵌入式的数据库

基于嵌入式的数据库主要有:SQLite,Firebird,Berkeley DB,eXtremeDB

  • Firebird 是关系型数据库,功能强大,支持存储过程,SQL兼容等
  • SQLite 关系型数据库,体积小,支持ACID事务
  • Berkeley DB 并没有数据库服务器的概念,他的程序直接链接到应用程序中
  • eXtremeDB 是内存数据库,运行效率高

二、SQLite数据库安装

安装方式一:

sudo apt-get -y install sqlite

安装方式二:

https://www.sqlite.org/download.html

在这里插入图片描述

把下载的文件sqlite-autoconf-3390000.tar.gz上传到开发板
tar xvf sqlite-autoconf-3390000.tar.gz 解压
cd sqlite-autoconf-3390000 进入文件夹
./configure --prefix=/usr/local 配置安装路径在/usr/local
make 编译//比较久10分钟
sudo make install 安装

在这里插入图片描述

如上图,安装成功过,运行sqlite3 进入SQL命令操作流程

三、SQLite的常用命令

1、创建一个数据库

方式一:

sqlite3 //进入数据库
.open test.db //打开(创建)一个名为test的数据库
.quit//退出数据库
数据库退出后在命令当前路径创建数据库test.db

方式二:

sqlite3 test.db //在命令运行当前窗口创建(打开)数据库test.db
.databases //列出当前打开的数据库
.quit //退出

2、创建一张表格

create table stu(id Integer,name char,score Integer);
//创建一个叫stu的表,内容包括id,name,和score

3、插入一条记录

给stu中的值赋值:
insert into stu values(106,'huang',99);
//id = 106,name = huang,score = 99
insert into stu values(101,"gang",100);// ''和""都行
//id = 101,name = gang,score = 100
insert into stu(name,score) values("huanggang",98); //插入部分字段内容

4、查看数据库的记录

.schema stu;//显示指定表的结构(列、数据类型等)。
select * from stu; //查询所有字段的结果
select name,score from stu; //查询数据库中部分字段的内容

5、删除一条记录

delete from stu where id = 101;//删除id = 101的这一项内容

6、更改一条记录

update stu set name = 'huangg' where id = 106;//将id = 106中呢name修改成'huangg'

7、删除一张表

drop table stu;//将名为stu的表删除

8、增加一列

alter table stu add column sex char;//在stu的表中增加一列内容sex

四、SQLite的编程操作

1、SQLite数据库相关API

带有数据库相关API函数编译时要加上 -l sqlite3

(1)头文件
#include <sqlite3.h>
(2)sqlite3_open()

sqlite3_open 函数是 SQLite API 中用于打开或创建 SQLite 数据库的 C 语言函数。

int sqlite3_open( const char *filename,sqlite3 **ppDb);
//返回值:如果成功打开数据库连接,返回 SQLITE_OK(通常为 0)。如果发生错误,返回相应的错误代码。

参数说明:

  • filename:指向以 UTF-8 编码的字符串,表示要打开的数据库文件的路径。如果文件不存在,SQLite 将尝试创建它。
  • ppDb:一个指向 sqlite3 指针的指针,用于存储新创建的数据库连接句柄。即使发生错误,该参数也会被更新,除非是因为内存分配失败导致无法创建 sqlite3 对象。
(3)sqlite3_close()

sqlite3_close函数用于关闭一个打开的 SQLite 数据库连接。

int sqlite3_close(sqlite3 *db);//db:指向 sqlite3 结构的指针,表示要关闭的数据库连接。
//返回值:SQLITE_OK(通常为 0)表示成功关闭连接。错误返回SQLite 错误代码。
(4)sqlite3_errmsg()

sqlite3_errmsg函数用于获取最近一次 SQLite 操作的错误消息。

const char *sqlite3_errmsg(sqlite3 *db);//db:指向 sqlite3的指针,表示已打开的数据库连接。
//返回一个指向错误消息字符串的指针,该字符串描述了调用 SQLite 函数时发生的任何错误。

在这里插入图片描述

(5)sqlite3_exec()

sqlite3_exec是 SQLite 库中的一个便捷函数,它封装了多个任务,用于执行 SQL 语句并可通过回调函数接口收集返回数据。

int sqlite3_exec(
  sqlite3 *db,            // 数据库连接句柄
  const char *sql,        // 要执行的 SQL 语句
  int (*callback)(void*, int, char **, char **), // 回调函数
  void *,                // 给回调函数传的参数
  char **errmsg           // 错误信息
);
//返回值:SQLITE_OK(通常为 0)表示执行成功。其他值表示发生错误。

参数说明:

  • db:指向 sqlite3 结构的指针,表示已打开的数据库连接。
  • sql:指向包含要执行的 SQL 语句的零结尾字符串的指针。
  • callback:每成功执行一次 SQL 语句,就执行一次此回调函数。如果 SQL 语句不是一个查询(例如 INSERTUPDATEDELETE),则此参数可以设置为 NULL
  • **void ***:这是传递给回调函数的用户定义参数,对应于 sqlite3_exec 函数的第四个参数。
  • errmsg:如果提供了这个参数,并且函数返回了错误(非 SQLITE_OK),则错误信息将被存储在这个参数指向的位置。调用者应该在处理完错误消息后使用 sqlite3_free 释放这个指针。

其中回调函数callback要注意的是:

回调函数应该返回一个整数,一般是return 0。通常,返回 SQLITE_OK(值为 0)表示继续处理下一行。如果返回非零值,sqlite3_exec 将停止执行 SQL 语句并返回。
typedef int (*sqlite3_callback)(
  void *arg,            		// 用户定义的数据指针
  int column_size,              // 列的数量
  char *column_value[],        // 列值的数组
  char *column_name[]          // 列名的数组
);

参数说明:

  • arg:这是一个用户定义的数据指针,它被传递给 sqlite3_exec 函数,并且最终传递给回调函数。这可以用来在回调函数内部访问额外的数据或状态。
  • column_size:表示查询结果中的列数。
  • *column_value[]:这是一个指向字符指针数组的指针,每个元素包含一行中每个列的文本表示形式。可以通过column_value[i] 来访问第 i 列的名称,索引从 0 开始。
  • *column_name[]:这是一个指向列名的指针数组。每个元素对应一列的名称,可以通过column_name[i] 来访问第 i 列的名称。
(6)sqlite3_prepare_v2()

sqlite3_prepare_v2函数用于编译 SQL 语句,并生成一个准备语句(prepared statement),这个准备语句可以被进一步用于参数绑定和执行。相比于 sqlite3_exec,使用 sqlite3_prepare_v2 可以提高执行效率,因为 SQL 语句只需要编译一次,可以被重复执行多次。

int sqlite3_prepare_v2(
  sqlite3 *db,            /* Database handle */
  const char *zSql,       /* SQL statement, UTF-8 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
  const char **pzTail     /* OUT: Pointer to unused portion of zSql */
);
//返回值:成功返回 SQLITE_OK,失败返回相应的错误码。

参数说明:

  • db :指向 SQLite 数据库连接的指针。
  • zSql: 指向要编译的 SQL 语句的指针,该语句是 UTF-8 编码。
  • nByte: 是SQL 语句的最大字节长度。如果设置为负数,则 SQLite 会自己确定字符串的长度。
  • ppStmt: 是指向 sqlite3_stmt 指针的指针,用于接收编译后的 SQL 语句的句柄。
    • 它不是普通的 SQL 语句字符串,而是一个已经编译成二进制形式的实例,可以直接执行。
    • 通过调用 sqlite3_step 函数,可以执行 sqlite3_stmt 对象中的 SQL 语句。这个函数可以被调用一次或多次,用于循环执行。
    • 执行完所有操作后,使用 sqlite3_finalize 函数销毁 sqlite3_stmt 对象,释放与之关联的所有资源。
  • pzTail: 是指向剩余未编译 SQL 语句部分的指针的指针,如果 SQL 语句被成功编译,这个参数会被设置为指向 zSql 之后的第一个字符。
(7)sqlite3_step()

sqlite3_step是SQLite中用于执行或继续执行由 sqlite3_stmt 表示的准备语句的函数。这个函数通常在调用 sqlite3_prepare_v2sqlite3_prepare 准备 SQL 语句后使用。

int sqlite3_step(sqlite3_stmt *stmt);

执行流程:

  1. 第一次调用:当 sqlite3_step 被首次调用时,它会开始执行 SQL 语句。
  2. 后续调用:如果 SQL 语句是一个查询,并且有多行结果,sqlite3_step 会在后续调用中返回下一行结果。

使用场景:

  1. 查询:当执行一条 SELECT 语句时,sqlite3_step 用于逐行获取查询结果。
  2. 插入、更新、删除:对于这类操作,sqlite3_step 通常只被调用一次,完成操作后返回 SQLITE_DONE

返回值:sqlite3_step 函数返回一个状态码,表示执行的状态

  • SQLITE_DONE:表示语句已经成功执行完成,没有更多的结果行。
  • SQLITE_ROW:表示 SQL 语句是一条查询,且 sqlite3_step 返回了一行结果。此时,可以使用 sqlite3_column_* 系列函数访问结果列的数据。
  • SQLITE_BUSY:表示数据库忙,通常是因为另一个操作正在使用数据库。
  • SQLITE_ERROR:表示执行过程中发生了错误。可以使用 sqlite3_errmsgsqlite3_errcode 函数获取错误详情。
  • 其他错误码:SQLite 定义了其他错误码,表示特定的错误情况。
(8)sqlite3_column_*

**sqlite3_column_***是一组 SQLite API 函数,用于从 sqlite3_stmt 对象中检索单个列的数据,该对象是通过执行 SQL 查询语句得到的。

TYPE sqlite3_column_COLUMNNAME(sqlite3_stmt *stmt, int iCol);

函数说明:

  • TYPE: 是数据类型,例如 intdoubletext 等。
  • COLUMNNAME: 是列的类型或特定属性的名称,例如 intrealblob 等。
  • stmt: 是指向 sqlite3_stmt 对象的指针,该对象包含了查询结果。
  • iCol: 是列的索引号(从 0 开始)。

常用函数

  • sqlite3_column_blob:返回列的 BLOB 数据。
  • sqlite3_column_double:返回列的 REAL 数据。
  • sqlite3_column_int:返回列的 INTEGER 数据。
  • sqlite3_column_int64:返回列的 64位 INTEGER 数据。
  • sqlite3_column_text:返回列的 TEXT 数据的指针。
  • sqlite3_column_value:返回列的 sqlite3_value 对象。

这些函数用于访问由 sqlite3_step 返回的当前行的数据。每调用一次 sqlite3_step 并返回 SQLITE_ROW 后,就可以使用 sqlite3_column_* 函数来访问当前行的列数据。

(9)sqlite3_mprintf()

sqlite3_mprintf函数用于格式化字符串,类似于标准 C 语言中的 printf 函数,但它使用 SQLite 的内存分配函数来分配生成的字符串。这个函数在 SQLite 的 API 中非常有用,特别是在需要构造 SQL 语句时。

char *sqlite3_mprintf(const char *format, ...);
//返回值:函数返回一个指向新分配的字符串的指针,该字符串是格式化后的输出。如果分配内存失败,返回 NULL。

参数说明:

  • format:这是格式字符串,它指定了如何格式化后续参数。它遵循与 printf 函数相同的格式说明符。

使用示例:

char *sql;
int id = 10;
const char *name = "example";
sql = sqlite3_mprintf("SELECT * FROM table WHERE id=%d AND name='%q'", id, name);
  • 由于 sqlite3_mprintf 分配了内存,调用者有责任在不再需要时使用 sqlite3_free 来释放它。
  • 格式化选项 %q 是特殊的,在 SQLite 中用于确保字符串被正确地引用,避免 SQL 注入攻击。不过,需要注意的是,%q 并不是所有编译器都支持的。

2、编程实现

(1)打开数据库
#include <stdio.h> 
#include <sqlite3.h> 

int main(int argc, char *argv[]) // 主函数入口,argc 是参数个数,argv 是参数数组
{
    int ret; // 用于存储 SQLite 函数的返回值
    sqlite3 *db; // 用于存储数据库连接的指针

    // 检查命令行参数的数量是否正确(应提供一个数据库文件名)
    if(argc != 2){
        printf("Usage:%s xxx.db\n",argv[1]); // 如果参数数量不正确,打印用法信息
        return -1; 
    }

    // 尝试打开数据库文件,argv[1] 是命令行提供的数据库文件名
    // sqlite3_open 函数尝试打开或创建一个数据库,并将数据库连接的指针存储在 db 指向的位置
    if((ret = sqlite3_open(argv[1],&db)) != SQLITE_OK){
        printf("error:%s,%d\n",sqlite3_errmsg(db),ret); //如果打开失败,打印错误信息和错误代码
        return -1;
    }else{
        printf("open %s success\n",argv[1]); //如果打开成功,打印成功信息
	}

    // 关闭数据库连接
    sqlite3_close(db); 

    printf("done\n"); // 打印完成信息
    return 0; 
}

运行结果:成功打开数据库test3.db

在这里插入图片描述

(2)实现增删改查
1.向数据库中增加数据:创建一个表,并且插入三条数据
#include <stdio.h> 
#include <sqlite3.h> 

// 回调函数原型,由 sqlite3_exec 调用以处理查询结果
int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{
    int i;
    printf("column_size = %d\n", column_size); // 打印结果集中的列数
    printf("arg = %s\n", (char *)arg); // 打印传递给回调函数的参数,这里通常是 NULL
    for(i = 0; i < column_size; i++) {
        // 打印每一列的名称和值,如果值为 NULL,则打印 "NULL"
        printf("%s = %s\n", column_name[i], column_value[i] ? column_value[i] : "NULL");
    }
    printf("==================\n");
    return 0; // 回调函数返回 0 以继续执行
}

int main(int argc, char *argv[]) 
{
    int ret; // 用于存储 SQLite 函数的返回状态
    char *errorMes = NULL; // 用于存储错误消息
  
    /* 定义 SQL 语句字符串*/
    //创建一个名为Colors的表
    char *Sql_cretable = "create table Colors(num Integer, color char);";
    
     //Colors表中插入数据
    char *Sql_insert = "insert into Colors values(1,'black'),"
                       "(2,'pink'),"
                       "(3,'purple');";
    //查询Colors表中的所有数据
    char *Sql_select = "select * from Colors;";
    
    sqlite3 *db; // SQLite 数据库连接的指针

    // 检查命令行参数数量是否正确
    if(argc != 2){
        printf("Usage:%s xxx.db\n", argv[1]);
        return -1; // 参数数量不正确时,打印用法并退出
    }

    // 尝试打开数据库,如果失败打印错误消息并退出
    if((ret = sqlite3_open(argv[1], &db)) != SQLITE_OK){
        printf("error:%s\n", sqlite3_errmsg(db));
        return -1;
    }
    printf("open %s success\n", argv[1]); // 打开成功,打印消息

    // 执行创建表的 SQL 语句,如果失败打印错误
    if((ret = sqlite3_exec(db, Sql_cretable, NULL, NULL, &errorMes)) != SQLITE_OK){
        printf("error:%s\n", errorMes);
    }
    printf("create Colors success\n"); // 创建表成功,打印消息

    // 执行插入数据的 SQL 语句,如果失败打印错误
    if((ret = sqlite3_exec(db, Sql_insert, NULL, NULL, &errorMes)) != SQLITE_OK){
        printf("error:%s\n", errorMes);
    }
    printf("insert success\n"); // 插入数据成功,打印消息

    // 执行查询数据的 SQL 语句,并使用回调函数处理结果
    if((ret = sqlite3_exec(db, Sql_select, callback, NULL, &errorMes)) != SQLITE_OK){
        printf("error:%s\n", errorMes);
    }
    printf("select success\n"); // 查询成功,打印消息
   
    sqlite3_close(db);// 关闭数据库连接
    printf("done\n"); 
    return 0;
}

运行结果:
在这里插入图片描述

2.更改数据库中的数据:将数据库中num = 1的color改成white
#include <stdio.h> 
#include <sqlite3.h> 

//回调函数,由 sqlite3_exec 调用以处理查询结果
int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{
    int i;
    printf("column_size = %d\n", column_size); // 打印结果集中的列数
    printf("arg = %s\n", (char *)arg); // 打印传递给回调函数的参数,这里通常是 NULL
    for(i = 0; i < column_size; i++) {
        // 打印每一列的名称和值,如果值为 NULL,则打印 "NULL"
        printf("%s = %s\n", column_name[i], column_value[i] ? column_value[i] : "NULL");
    }
    printf("==================\n");
    return 0; // 回调函数返回 0 以继续执行
}

int main(int argc, char *argv[]) 
{
    int ret; // 用于存储 SQLite 函数的返回状态
    char *errorMes = NULL; // 用于存储错误消息
   
    /*定义 SQL 语句字符串*/
	//更新表中num = 1的数据
    char *Sql_update = "update Colors set color = 'white' where num = 1;";
	// 查询 Colors 表中的所有数据
    char *Sql_select = "select * from Colors;"; 

    sqlite3 *db; // SQLite 数据库连接的指针

    // 检查命令行参数数量是否正确
    if(argc != 2){
        printf("Usage:%s xxx.db\n", argv[1]);
        return -1; // 参数数量不正确时,打印用法并退出
    }

    // 尝试打开数据库,如果失败打印错误消息并退出
    if((ret = sqlite3_open(argv[1], &db)) != SQLITE_OK){
        printf("error:%s\n", sqlite3_errmsg(db));
        return -1;
    }
    printf("open %s success\n", argv[1]); // 打开成功,打印消息

    // 执行更新数据的 SQL 语句,并使用回调函数处理结果
    if((ret = sqlite3_exec(db, Sql_update, callback, NULL, &errorMes)) != SQLITE_OK){
        printf("error:%s\n", errorMes);
    }
    printf("update success\n"); // 更新成功,打印消息

    // 关闭数据库连接
    sqlite3_close(db);
    printf("done\n");
    return 0; 
}

运行结果:
在这里插入图片描述

3.删除num = 1 的数据
#include <stdio.h> 
#include <sqlite3.h> 

// 回调函数原型,由 sqlite3_exec 调用以处理查询结果
int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{
    int i;
    printf("column_size = %d\n", column_size); // 打印结果集中的列数
    printf("arg = %s\n", (char *)arg); // 打印传递给回调函数的参数,这里通常是 NULL
    for(i = 0; i < column_size; i++) {
        // 打印每一列的名称和值,如果值为 NULL,则打印 "NULL"
        printf("%s = %s\n", column_name[i], column_value[i] ? column_value[i] : "NULL");
    }
    printf("==================\n");
    return 0; // 回调函数返回 0 以继续执行
}

int main(int argc, char *argv[]) 
{
    int ret; // 用于存储 SQLite 函数的返回状态
    char *errorMes = NULL; // 用于存储错误消息
    /* 定义 SQL 语句字符串*/
    
	// 删除 Colors 表中num = 1的数据
    char *Sql_delete = "delete from Colors where num = 1;";
    // 查询 Colors 表中的所有数据
    char *Sql_select = "select * from Colors;";

    sqlite3 *db; // SQLite 数据库连接的指针

    // 检查命令行参数数量是否正确
    if(argc != 2){
        printf("Usage:%s xxx.db\n", argv[1]);
        return -1; // 参数数量不正确时,打印用法并退出
    }

    // 尝试打开数据库,如果失败打印错误消息并退出
    if((ret = sqlite3_open(argv[1], &db)) != SQLITE_OK){
        printf("error:%s\n", sqlite3_errmsg(db));
        return -1;
    }
    printf("open %s success\n", argv[1]); // 打开成功,打印消息

    // 执行删除数据的 SQL 语句,如果失败打印错误
    if((ret = sqlite3_exec(db, Sql_delete, NULL, NULL, &errorMes)) != SQLITE_OK){
        printf("error:%s\n", errorMes);
    }
    printf("delete success\n"); // 删除成功,打印消息

    // 再次执行查询数据的 SQL 语句,验证删除操作的结果
    if((ret = sqlite3_exec(db, Sql_select, NULL, NULL, &errorMes)) != SQLITE_OK){
        printf("error:%s\n", errorMes);
    }
    printf("select success\n"); // 查询成功,打印消息

    // 关闭数据库连接
    sqlite3_close(db);
    printf("done\n"); 
    return 0; 
}

运行结果:

在这里插入图片描述

(3)链表和SQLite数据转换
1.静态链表插入SQLite
#include <stdio.h>    // 包含标准输入输出库
#include <sqlite3.h> // 包含 SQLite 库的头文件

struct Stu {
    int id;        // 学生ID
    int class;     // 班级
    char name[12]; // 学生姓名
    int scores;    // 分数
    struct Stu *next; // 指向下一个链表节点的指针
};

// 回调函数原型,由 sqlite3_exec 调用以处理查询结果
int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{
	int i;
	printf("column_size = %d\n",column_size);
	printf("arg = %s\n",(char *)arg);
	for(i=0; i<column_size;i++){
		printf("%s = %s\n",column_name[i],column_value[i]);
	}
	printf("==================\n");
	return 0;
}

int main(int argc, char *argv[]) {
    int ret;              // 函数返回状态
    char *errorMes = NULL; // 错误信息
    // 定义 SQL 语句
    char *Sql_cretable = "create table Stu(id Integer,class Integer,name\ 									char,scores Integer);";
    char *Sql_select = "select * from Stu;";
    char *sql = NULL;     // 动态 SQL 语句字符串    
    sqlite3 *db;          // SQLite 数据库连接指针
   
    // 定义链表节点
    struct Stu stu1 = {1, 1801, "dafang", 99, NULL};
    struct Stu stu2 = {2, 1801, "xiaohong", 68, NULL};
    struct Stu stu3 = {3, 1801, "zhangsan", 88, NULL};
    
    // 初始化链表头指针并构建链表
    struct Stu *head = &stu1;
    head->next = &stu2;
    stu2.next = &stu3;

    // 检查命令行参数数量
    if (argc != 2) {
        printf("Usage:%s xxx.db\n", argv[1]);
        return -1;
    }

    // 打开 SQLite 数据库
    if ((ret = sqlite3_open(argv[1], &db)) != SQLITE_OK) {
        printf("error:%s,%d\n", sqlite3_errmsg(db), ret);
        return -1;
    } else {
        printf("open %s success\n", argv[1]);
    }

    // 创建表
    if ((ret = sqlite3_exec(db, Sql_cretable, NULL, NULL, &errorMes)) !=\ 					SQLITE_OK) {
        printf("error:%s\n", errorMes);
    }
    printf("create Stu table success\n");

    // 遍历链表并插入数据
    while (head != NULL) {
        // 构建 SQL 插入语句
        sql = sqlite3_mprintf("insert into Stu(id,class,name,scores)\ 											values(%d,%d,%Q,%d)",\
                              head->id, head->class, head->name, head->scores);
        // 执行 SQL 插入语句
        if ((ret = sqlite3_exec(db, sql, NULL, NULL, &errorMes)) != SQLITE_OK) {
            printf("error:%s\n", errorMes);
        }
        // 释放动态分配的 SQL 语句内存
        sqlite3_free(sql);
        // 移动到链表的下一个节点
        head = head->next;
    }
    printf("insert success\n");

    // 执行查询并打印结果
    if ((ret = sqlite3_exec(db, Sql_select, callback, NULL, &errorMes)) != SQLITE_OK) {
        printf("error:%s\n", errorMes);
    }
    printf("select success\n");
 
    sqlite3_close(db); // 关闭数据库连接
    printf("done\n");
    
    return 0;
}

运行结果:

在这里插入图片描述

2.动态创建链表插入数据库
#include <stdio.h> 
#include <stdlib.h> 
#include <sqlite3.h> 

// 定义学生结构体
struct Stu {
    int id;         // 学生ID
    int class;      // 班级编号
    char name[12];  // 学生姓名,假设最大长度为12
    int scores;     // 分数
    struct Stu *next; // 指向下一个学生结构的指针,用于构建链表
};

// 回调函数,用于 sqlite3_exec 函数查询操作
int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{
	int i;
	printf("column_size = %d\n",column_size);
	printf("arg = %s\n",(char *)arg);
	for(i=0; i<column_size;i++){
		printf("%s = %s\n",column_name[i],column_value[i]);
	}
	printf("==================\n");
	return 0;
}


/*提示用户输入学生信息,然后将这些信息插入到数据库中。使用 sqlite3_mprintf 来安全地格式化 SQL 插入命令,并使用 sqlite3_exec 来执行这些命令。*/
// 创建数据并插入到数据库的函数
int createData(sqlite3 *db)
{
    int ret; // 用于存储 sqlite3_exec 函数的返回值
    char *sql; // 用于存储构建的 SQL 语句
    char *errorMes = NULL; // 用于存储可能发生的错误信息
    struct Stu *new; // 指向新分配的 Stu 结构的指针;
    
    // 提示用户输入数据
	printf("Please input data:id Integer,class Integer,name char,scores Integer\n");
	printf("input 0 0 0 0 quit!\n");
    
	while(1){
		new = (struct Stu *)malloc(sizeof(struct Stu));		
		scanf("%d%d%s%d",&new->id,&new->class,new->name,&new->scores);
        new->next = NULL;
		printf("id=%d,class=%d,name=%s,scores=%d\n",\
				new->id,new->class,new->name,new->scores);
		if((new->id == 0) && (new->class == 0) && (new->scores == 0)){
			return 0;
		}
		sql = sqlite3_mprintf("insert into Stu(id,class,name,scores) \
								values(%d,%d,%Q,%d)",\
								new->id,new->class,new->name,new->scores);
		if((ret = sqlite3_exec(db,sql,NULL,NULL,&errorMes)) != SQLITE_OK){
			printf("error: %s\n",errorMes);
		}
		sqlite3_free(sql);
	}
	return 0;
}

int main(int argc, char *argv[]) {
    // 检查命令行参数数量
    if (argc != 2) {
        printf("Usage: %s database_name.db\n", argv[0]);
        return -1;
    }
    
    // 打开 SQLite 数据库
    sqlite3 *db;
    if (sqlite3_open(argv[1], &db) != SQLITE_OK) {
        // 打印错误信息并退出
        printf("Cannot open database: %s\n", sqlite3_errmsg(db));
        return -1;
    }
    printf("Opened database successfully\n");
    
    // 创建学生表的 SQL 语句
    char *Sql_cretable = "CREATE TABLE IF NOT EXISTS Stu (id INTEGER, class INTEGER, name TEXT, scores INTEGER);";
    
    // 执行创建表的 SQL 语句
    char *errorMes;
    if (sqlite3_exec(db, Sql_cretable, NULL, NULL, &errorMes) != SQLITE_OK) {
        printf("Error creating table: %s\n", errorMes);
    }
    printf("Table created successfully\n");
    
    // 调用函数创建数据并插入数据库
    int ret = createData(db);
    
    // 执行查询并打印结果
    char *Sql_select = "SELECT * FROM Stu;";
    if (sqlite3_exec(db, Sql_select, callback, NULL, &errorMes) != SQLITE_OK) {
        printf("Error querying the database: %s\n", errorMes);
    }
    printf("Query executed successfully\n");

    // 关闭数据库连接
    sqlite3_close(db);
    printf("Database closed\n");
    return 0;
}

运行结果:

在这里插入图片描述

3.链表方式读取SQLite数据
#include <stdio.h>    
#include <stdlib.h>  
#include <sqlite3.h> 

struct Stu {        // 定义学生结构体
    int id;          // 学生ID
    int class;       // 班级
    char name[12];   // 学生姓名
    int scores;      // 分数
    struct Stu *next; // 指向下一个学生节点的指针
};

// 回调函数,用于sqlite3_exec查询数据库内容
int callback(void *arg, int column_size, char *column_value[], char *column_name[]) {
    // ... 此处实现回调函数,用于打印查询结果 ...
}

// 定义从数据库创建链表的函数
struct Stu *createListFromDB(sqlite3 *db) {
    sqlite3_stmt *stmt; // 存储编译后的SQL语句
    struct Stu *head = NULL; // 链表头初始化为NULL
    struct Stu *node = NULL; // 链表的节点指针
    struct Stu *current = NULL; // 遍历链表的当前节点
    char *Sql_select = "select * from Stu;"; // 查询SQL语句

    // 准备SQL查询语句
    sqlite3_prepare_v2(db, Sql_select, -1, &stmt, NULL);
    while (sqlite3_step(stmt) == SQLITE_ROW) { // 遍历查询结果
        node = (struct Stu *)malloc(sizeof(struct Stu)); // 为新节点分配内存
        if (node == NULL) { // 检查内存分配是否成功
            fprintf(stderr, "malloc failed\n");
            break;
        }

        // 从数据库查询结果中获取数据并赋值给节点成员
        node->id = sqlite3_column_int(stmt, 0);
        node->class = sqlite3_column_int(stmt, 1);
        snprintf(node->name, sizeof(node->name), "%s", \
                 (char *)sqlite3_column_text(stmt, 2));
        node->scores = sqlite3_column_int(stmt, 3);

        // 将新节点添加到链表
        if (head == NULL) {
            head = node; // 如果链表为空,则新节点是头节点
        } else {
            current->next = node; // 否则,将新节点链接到链表末尾
        }
        current = node; // 更新当前节点为新节点
    }
    sqlite3_finalize(stmt); // 最终化SQL语句
    return head; // 返回链表的头指针
}

// 释放链表内存的函数
void freeList(struct Stu *head) {
    struct Stu *tmp;
    while (head != NULL) {
        tmp = head; // 暂存当前节点
        head = head->next; // 移动到下一个节点
        free(tmp); // 释放当前节点的内存
    }
}

int main(int argc, char *argv[]) {
    int ret; // 用于存储函数返回值
    sqlite3 *db; // 用于存储数据库连接的指针

    // 检查命令行参数数量
    if (argc != 2) {
        printf("Usage:%s xxx.db\n", argv[1]);
        return -1;
    }

    // 打开SQLite数据库
    if ((ret = sqlite3_open(argv[1], &db)) != SQLITE_OK) {
        printf("error:%s,%d\n", sqlite3_errmsg(db), ret);
        return -1;
    } else {
        printf("open %s success\n", argv[1]);
    }

    // 使用createListFromDB函数从数据库创建链表
    struct Stu *stuList = createListFromDB(db);
    if (stuList != NULL) {
        // 遍历链表并打印学生信息
        struct Stu *ptr = stuList;
        while (ptr) {
            printf("ID: %d, Class: %d, Name: %s, Score: %d\n",\
                   ptr->id, ptr->class, ptr->name, ptr->scores);
            ptr = ptr->next;
        }
        // 释放链表占用的内存
        freeList(stuList);
    }

    // 关闭数据库连接
    sqlite3_close(db);
    printf("done\n");
    return 0;
}

运行结果:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1850489.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VBA技术资料MF164:列出文件夹中的所有文件和创建日期

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

【Arduino】实验使用ESP32单片机根据光线变化控制LED小灯开关(图文)

今天小飞鱼继续来实验ESP32的开发&#xff0c;这里使用关敏电阻来配合ESP32做一个我们平常接触比较多的根据光线变化开关灯的实验。当白天时有太阳光&#xff0c;则把小灯关闭&#xff1b;当光线不好或者黑天时&#xff0c;自动打开小灯。 int value;void setup() {pinMode(34…

STM32驱动-ads1112

汇总一系列AD/DA的驱动程序 ads1112.c #include "ads1112.h" #include "common.h"void AD5726_Init(void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE );//PORTA、D时钟使能 G…

C++入门 vector部分模拟实现

目录 vector大致框架 vector常见接口模拟实现 begin迭代器 & end迭代器 capacity( ) & size( ) reserve operator[ ] push_back( ) & pop_back( ) sort vector大致框架 vector的内部的成员变量大概有三部分构成&#xff1a; namespace bit {template<c…

python字符串如何删除后几位

1、首先在jupyter notebook中新建一个空白的python文件&#xff1a; 2、然后定义一个字符串&#xff0c;用字符串截取的方式打印出排除最后三个字符的结果&#xff0c;这里的“s[:-3]”的意思就是从字符串取第0个字符至倒数第三个字符的前一个字符&#xff0c;这样就截取了最后…

DDP(Differential Dynamic Programming)算法举例

DDP(Differential Dynamic Programming)算法 基本原理 DDP(Differential Dynamic Programming)是一种用于求解非线性最优控制问题的递归算法。它基于动态规划的思想,通过线性化系统的动力学方程和二次近似代价函数,递归地优化控制策略。DDP的核心在于利用局部二次近似来…

昇腾Ascend上使用分布式训练

一、环境搭建 1、使用hccn_tool配置昇腾训练卡的芯片网络&#xff0c;包括ip地址和掩码 命令原型 hccn_tool [-i %d] -ip -s [address %s] [netmask %s] 使用样例(配置两张卡)&#xff1a; hccn_tool -i 0 -ip -s address 192.168.2.10 netmask 255.255.255.0 hccn_tool …

丰臣秀吉-读书笔记六

登山的目标必然是山顶。但人生的乐趣和生息的快乐却不在山顶&#xff0c;相反可以说是在山中的逆境之处。当我们遇上峡谷、绝壁、溪流、断崖、雪崩之类的险路时&#xff0c;心里虽想着已经不行了等&#xff0c;却不甘就此罢手而不与面前的艰难险阻战斗。而当我们完美克服并跨越…

【SpringSecurity】认证与鉴权框架SpringSecurity——认证

目录 SpringSecurity介绍特性CSRF攻击攻击模式攻击原理预防手段 XSS攻击攻击模式危害预防手段 SpringSecurity预防CSRF攻击SpringSecurity预防XSS攻击SpringSecurity与OAuth2的关系SpringSecurity的核心功能 代码实战依赖定义一个接口Redis工具类响应类直接运行工具类认证业务密…

简易智能家居系统

文章目录 摘要一、系统设计要求及总体设计方案1.1 设计要求1.2 总体设计方案 二、终端结点的设计及实现2.1单片机最小系统2.2 LED灯的控制与工作状态的显示2.2.1 硬件设计2.2.2 软件设计 2.3 温度的测量与显示2.4 火灾的监测与报警2.5 串口的显示与控制 三、网络传输与控制3.1 …

three.js 第十一节 - uv坐标

// ts-nocheck // 引入three.js import * as THREE from three // 导入轨道控制器 import { OrbitControls } from three/examples/jsm/controls/OrbitControls // 导入lil.gui import { GUI } from three/examples/jsm/libs/lil-gui.module.min.js // 导入tween import * as T…

计算机网络(概述)

该笔记为湖科大计算机网络相关笔记、教材参考计算机网络第六版 湖科大计算机网络 计算机网络概述 因特网概述 Internet和internet的区别 internet&#xff1a;只要是计算机与计算机连接&#xff0c;形成了网络&#xff0c;就可以叫internet Internet&#xff1a;泛指全世界的…

现在这个行情,又又又要开始准备面试了~~

亲爱的程序员朋友们: 这些资料曾经帮助过许多有志之士顺利拿下抖音、快手、阿里等大厂的Offer&#xff0c;现在也希望它们能为你的面试旅程助力&#xff01; 关注【程序员世杰】回复【1024】惊喜等你来拿&#xff01; 截图 关注【程序员世杰】回复【1024】惊喜等你来拿&#xf…

【数据分享】《中国法律年鉴》1987-2022

而今天要免费分享的数据就是1987-2022年间出版的《中国法律年鉴》并以多格式提供免费下载。&#xff08;无需分享朋友圈即可获取&#xff09; 数据介绍 自1987年起&#xff0c;《中国法律年鉴》作为一部全面记录中国法律发展进程的重要文献&#xff0c;见证了中国法治建设的每…

C语言| 数组的折半查找

数组的折半查找 折半查找&#xff1a;在已经排好序的一组数据中快速查找数据。 先排序&#xff0c;再使用折半查找。 【折半查找的运行过程】 1 存储数组下标 low最小的下标&#xff0c;mid中间的下标&#xff0c; high最大的下标 2 key存放查找的值&#xff0c;每一次对比后…

2024年,业绩大爆发的企业,都做对了一件事

作为新质生产力之一的AI技术&#xff0c;已经完成了从实验室到场景应用的“惊险一跃”&#xff0c;这背后离不开云计算、大数据技术的日趋成熟。与此同时&#xff0c;大模型、柔性计算等创新的云基础设施解决方案&#xff0c;为企业降本增效、快速高质量地发展&#xff0c;提供…

电影数据集关联分析及FP-Growth实现

&#xff08;1&#xff09;数据预处理 我们先对数据集进行观察&#xff0c;其属性为’movieId’ ‘title’ ‘genres’&#xff0c;其中’movieId’为电影的序号&#xff0c;但并不完整&#xff0c;‘title’为电影名称及年份&#xff0c;‘genres’为电影的分类标签。…

【从0实现React18】 (一) 项目初始化

Multi-repo 和 Mono-repo 由于需要同时管理多个包&#xff0c;如React、React-dom等&#xff0c;所以选择**Mono-repo** 选择使用pnpm-workspace搭建Mono-repo环境的原因 依赖安装快更规范 Pnpm初始化 npm install -g pnpm pnpm init配置pnpm-workspace.yml文件 pnpm-work…

【C++提高编程-11】----C++ STL常用集合算法

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

vscode插件path-intellisense失效原因

很可能是因为设置中的自动补全部分除了问题。 问题 作者自身是因为使用了copilot之后&#xff0c;感觉vscod自带的自动补全(设置里面叫"建议"&#xff0c;或者inttelisense)就没必要了&#xff0c;然后一通改设置把建议关掉之后发现插件path-intellisense也不能用了…