数据库编程:从SQLite基础到C语言集成

一、数据库概述

1.1 数据库的定义与作用

数据库(Database)是一种按照数据结构来组织、存储和管理数据的软件系统。它能够高效地处理大批量数据,提供数据持久化、快速检索、并发控制、安全性保障等功能,是应用程序与数据之间的桥梁。

1.2 数据库的分类

根据数据组织方式,数据库主要分为两类:

  • 关系型数据库:基于关系模型,使用表格(二维表)存储数据,表与表之间通过外键等约束建立关联。常见的有:

    • Oracle:大型企业级数据库,功能强大但资源占用高。

    • MySQL:开源广泛使用,适用于Web应用。

    • SQL Server:微软产品,与.NET生态集成良好。

    • SQLite:轻量级嵌入式数据库,无需独立服务进程,直接集成到应用程序中。

  • 非关系型数据库:以键值对、文档、列族或图结构存储数据,适用于高并发、海量数据的场景。如Redis(键值存储)、MongoDB(文档型)等。

本次学习主要围绕SQLite展开,因为它轻巧、无需配置、支持标准SQL,非常适合嵌入式设备和桌面应用开发。


二、SQLite数据库基础

2.1 SQLite的特点

  • 零配置:不需要安装和配置服务器,数据库就是一个单一的文件。

  • 跨平台:支持Windows、Linux、macOS等多种操作系统。

  • 轻量级:代码库小(约250KB),内存占用低。

  • 支持SQL:实现了大部分SQL-92标准,支持事务(ACID)。

  • C语言接口:提供原生C API,便于嵌入式开发。

2.2 SQLite的安装(Ubuntu环境)

在Linux系统中,通过apt-get工具集安装SQLite及相关开发包:

复制代码
sudo apt-get install sqlite3          # SQLite命令行工具
sudo apt-get install libsqlite3-dev   # SQLite开发库(供C语言调用)
sudo apt-get install sqlitebrowser    # 图形化管理工具(可选)

安装完成后,终端输入sqlite3即可进入交互式命令行环境。

2.3 SQLite常用命令

在sqlite3提示符下,以点号开头的命令用于管理数据库,常见的有:

命令 功能
.databases 列出当前打开的数据库文件
.tables 显示所有表名
.header on/off 开启/关闭查询结果头部显示
.mode MODE 设置输出格式,如csv、column、list等
.schema [表名] 显示创建表的SQL语句
.quit 退出sqlite3

例如,设置列对齐显示:

复制代码
sqlite> .header on
sqlite> .mode column

三、SQL语句详解

SQL(Structured Query Language)是操作关系型数据库的标准语言。以下通过一个学生信息表student来演示常用操作。

3.1 数据定义语言(DDL)

创建表
复制代码
CREATE TABLE student (
    学号 INTEGER PRIMARY KEY,
    姓名 TEXT,
    性别 TEXT,
    年龄 INTEGER,
    成绩 INTEGER
);
  • PRIMARY KEY约束指定学号为主键,唯一标识一条记录。

  • SQLite支持的数据类型:INTEGERREALTEXT(实际上SQLite采用动态类型,但建议明确声明)。

删除表
复制代码
DROP TABLE student;

3.2 数据操作语言(DML)

插入数据
  • 全字段插入:INSERT INTO student VALUES (1002, '李四', '女', 13, 80);

  • 部分字段插入:INSERT INTO student (学号, 姓名, 性别) VALUES (1009, '熊大', '男');

删除数据
复制代码
DELETE FROM student WHERE 姓名 = '赵五';
更新数据
复制代码
UPDATE student SET 年龄 = 16, 成绩 = 85 WHERE 姓名 = '熊大';

3.3 数据查询语言(DQL)

基本查询
复制代码
SELECT * FROM student;                           -- 查询所有列
SELECT 学号, 成绩 FROM student;                   -- 查询指定列
SELECT 姓名 FROM student WHERE 成绩 < 60 AND 性别 = '男';  -- 带条件查询
SELECT 姓名 FROM student WHERE 姓名 LIKE '%田%';   -- 模糊查询
排序
复制代码
SELECT 学号, 姓名 FROM student WHERE 成绩 > 60 ORDER BY 成绩 DESC;  -- 降序
SELECT 学号, 姓名 FROM student WHERE 成绩 > 60 ORDER BY 成绩 ASC;   -- 升序

3.4 多表联合查询

实际应用中数据往往分散在多个表中,需要通过连接(JOIN)获取完整信息。假设有以下三表:

  • 学生信息表:学生信息(学号, 姓名, ...)

  • 课程表:学生课程(编号, 名称)

  • 成绩表:学生成绩(学号, 课程编号, 成绩)

交叉连接(CROSS JOIN)

返回两表的笛卡尔积,较少使用。

复制代码
SELECT 学生信息.姓名 AS 姓名, 学生课程.名称 AS 课程
FROM 学生信息 CROSS JOIN 学生课程;
内连接(INNER JOIN)

返回两表中满足连接条件的记录。

复制代码
SELECT 学生信息.姓名 AS 姓名, 学生成绩.成绩 AS 成绩
FROM 学生信息 INNER JOIN 学生成绩 ON 学生信息.学号 = 学生成绩.学号;
左外连接(LEFT OUTER JOIN)

返回左表全部记录,右表无匹配时填充NULL。

复制代码
SELECT 学生信息.姓名 AS 姓名, 学生成绩.成绩 AS 成绩
FROM 学生信息 LEFT OUTER JOIN 学生成绩 ON 学生信息.学号 = 学生成绩.学号;
三表联合查询
复制代码
SELECT 学生信息.姓名 AS 姓名, 学生课程.名称 AS 课程, 学生成绩.成绩 AS 成绩
FROM 学生信息
LEFT OUTER JOIN 学生成绩 ON 学生信息.学号 = 学生成绩.学号
LEFT OUTER JOIN 学生课程 ON 学生成绩.课程编号 = 学生课程.编号
WHERE 成绩 > 60
ORDER BY 成绩 DESC;

四、C语言数据库编程(SQLite API)

SQLite提供了一套C语言接口,允许程序直接操作数据库。核心API如下:

4.1 打开数据库:sqlite3_open

复制代码
int sqlite3_open(const char *filename, sqlite3 **ppDb);
  • 功能:打开(或创建)一个SQLite数据库文件,返回数据库句柄sqlite3 *

  • 返回值:成功返回SQLITE_OK,否则返回错误码。

4.2 错误处理:sqlite3_errmsg

复制代码
const char *sqlite3_errmsg(sqlite3 *db);
  • 功能:根据数据库句柄获取最后一次操作的错误描述。

4.3 执行SQL语句:sqlite3_exec

复制代码
int sqlite3_exec(
    sqlite3 *db,                                  /* 数据库句柄 */
    const char *sql,                              /* 要执行的SQL语句 */
    int (*callback)(void*, int, char**, char**),  /* 回调函数(处理查询结果) */
    void *arg,                                     /* 传递给回调函数的参数 */
    char **errmsg                                  /* 错误信息指针 */
);
  • 该函数可以执行任何SQL语句(DDL、DML、DQL)。

  • 对于SELECT语句,每检索到一行就会调用一次回调函数。回调函数原型:

    复制代码
    int callback(void *arg, int nColumns, char **colValues, char **colNames);
    • arg:用户传入的参数。

    • nColumns:当前行的列数。

    • colValues:字符串数组,存放各列的值。

    • colNames:字符串数组,存放各列的字段名。

    • 返回值:0表示继续处理后续行,非0则终止查询。

4.4 释放错误信息:sqlite3_free

复制代码
void sqlite3_free(void *ptr);
  • 用于释放sqlite3_exec中由errmsg分配的内存。

4.5 关闭数据库:sqlite3_close

复制代码
int sqlite3_close(sqlite3 *db);
  • 关闭数据库连接,释放资源。

4.6 示例:查询学生信息

复制代码
#include <stdio.h>
#include <sqlite3.h>

int callback(void *arg, int nCol, char **val, char **colName) {
    for (int i = 0; i < nCol; i++)
        printf("%s = %s\n", colName[i], val[i] ? val[i] : "NULL");
    printf("\n");
    return 0;
}

int main() {
    sqlite3 *db;
    char *errmsg = NULL;
    int rc = sqlite3_open("test.db", &db);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        return 1;
    }

    const char *sql = "SELECT * FROM student;";
    rc = sqlite3_exec(db, sql, callback, NULL, &errmsg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "SQL error: %s\n", errmsg);
        sqlite3_free(errmsg);
    }

    sqlite3_close(db);
    return 0;
}

编译时需要链接SQLite库:

复制代码
gcc example.c -lsqlite3 -o example

五、实践作业分析

本次学习的作业之一是构建一个单词查询系统,要求:

  1. 将单词文件中的所有单词和含义插入到数据库中。

  2. 从终端输入单词,通过数据库查找对应的含义并打印;若无匹配则提示输入有误。

相关推荐
刘一说19 小时前
使用 CLion 搭建 Redis 6.x 源码调试环境:从零开始的完整指南
数据库·redis·缓存
daad77719 小时前
peerconnection
linux
人道领域19 小时前
苍穹外卖:菜品分页查询与删除功能(保姆级详解)
java·开发语言·数据库·后端·spring
木子欢儿19 小时前
从零到精通 Neovim:Ubuntu 下的终极开发利器指南
linux·运维·服务器·ubuntu
Navicat中国20 小时前
利用 PostgreSQL 的强大力量:Supabase 简介
数据库·postgresql·navicat·supabase
天外来鹿20 小时前
Map/Set/WeakMap/WeakSet学习笔记
前端·javascript·笔记·学习
蚊子爱喝水20 小时前
swoole6.2新特性
linux·swoole
峥嵘life20 小时前
Android16 【GTS】 GtsDevicePolicyTestCases 测试存在Failed项
android·linux·学习
yqzyy20 小时前
Redis 设置密码无效问题解决
数据库·redis·缓存
leixj02520 小时前
SVN学习笔记
笔记·学习·svn