本文最后更新于 2025-06-25,学习久了要注意休息哟

第七章 数据库

7.1 数据库的概念

7.1.1 数据

能够输入计算机并能被计算机程序识别和处理的信息结合

7.1.2 数据库 (database)

数据库是在数据库管理系统管理可控制下,存放在存储介质上的数据集合

7.1.3 数据库管理系统(DBMS)

DBMS 是数据库系统中 对数据管理进行同意管理可控制的软件系统

(1)数据库定义功能

(2)数据库操作功能

(3)数据库运行控制功能

(4)数据库通讯功能

(5)支持海量数据

7.1.4 文件管理特点

优点:

​ 数据可以长期保存

​ 能存储大量的数据

缺点:

​ 数据的冗余大

​ 数据一致性 完整性 难以维持

​ 数据与程序缺乏高度独立性

7.1.5 数据库介绍

大型数据库

  • Oracle公司是最早开发关系型数据库的厂商之一,其产品支持最广泛的操作系统平台。目前Oracle关系型数据库产品的市场占有率名列前茅。

  • IBM的DB2是第一个具备网上功能的多媒体关系型数据库管理系统,支持包括 Linux 在内的一系列平台。

中型数据库

  • Server是微软开发的数据库产品,主要支持Windows平台。

小型数据库

  • MySQL是一个小型关系型数据库管理系统,开发者为瑞典MySQL公司,2008年被Sun公司收购。开源代码。

7.1.6 基于嵌入式linux的数据库

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

Firebird是关系型数据库,功能强大,支持存储过程、SQL兼容等

SQLite关系型数据库,体积小,支持ACID事务

Berkeley DB中并没有数据库服务器的概念,它的程序库直接链接到应用程序中

eXtremeDB是内存数据库,运行效率高

SQLite基础

SQLite的源代码是C,其源代码完全开放。SQLite第一个Alpha版本诞生于2000年5月。他是一个轻量级的嵌入式数据库。

SQLite有以下特性:

  • 零配置——无需安装和管理配置;
  • 存储在单一磁盘文件中的一个完整的数据库;
  • 数据库文件可以在不同字节顺序的机器间自由共享;
  • 支持数据库大小至2TB;
  • 足够小,全部源代码大致3万行C代码,251KB;
  • 比目前流行的大多数数据库对数据的操作要快。

7.1.7 安装 SQLite3

官网

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

离线安装:

sudo dpkg -i sqlite3_3.22.0-1ubuntu0.4_amd64.deb  # 数据库软件
sudo dpkg -i libsqlite3-dev_3.22.0-1ubuntu0.4_amd64.deb  # 数据库的库文件

在线安装:

sudo apt-get install sqlite3                # 数据库
sudo apt-get install libsqlite3-dev         # C语言操作数据库的API

验证安装

$ sqlite3 
SQLite version 3.11.0 2016-02-15 17:29:24
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite>

退出需要按三次 ctrl + c

7.2 数据库语句和 SQL 语句

7.2.1 数据库语句

在命令前面 有 . 并不需要在命名后面加分号

1 打开数据库文件

方式1:
使用以下命令打开数据库文件,其中 文件名 可以是自定义名称,但通常以 .db 结尾。

sqlite3 文件名.db

示例:

$ sqlite3 HQYJ.db
SQLite version 3.11.0 2016-02-15 17:29:24
Enter ".help" for usage hints.
sqlite> CREATE TABLE Log_in(id INT , User CHAR(64) , Password CHAR(64))
  • 解释:
    • sqlite3 HQYJ.db:打开名为 HQYJ.db 的数据库文件。
    • create table HQYJ aaa(id int);:创建名为 HQYJ 的表,包含 id 字段。

方式2:
直接使用 sqlite3 命令进入 SQLite,然后通过 .open 命令打开数据库文件。

sqlite3

进入后执行:

sqlite> .open HQYJ.db
sqlite> .table
HQYJ
  • 解释:
    • sqlite3:启动 SQLite 并进入交互模式。
    • .open HQYJ.db:打开名为 HQYJ.db 的数据库文件。
    • .table:显示数据库中所有的表。

2 SQLite3 数据库的系统命令

在 SQLite 中,系统命令以 . 开头,结尾不能加分号。这些命令可以通过 .help 来查看。

常见系统命令如下:

  • .help:显示帮助菜单,查看所有可用命令。
  • .open:打开数据库文件,格式为 .open 文件名
  • .exit.quit:退出 SQLite。
  • .tables:查看当前数据库中的所有表。
  • .schema:查看表的结构(建表语句)。
  • .headers on/off:控制查询结果中是否显示表头信息。

3 数据库表结构说明

关系型数据库中的表通常由以下几个部分组成:

  • 字段名:表示每个字段的名称(如 idname 等)。
  • 数据类型:每个字段的数据类型(如 INTEGERTEXTCHAR 等)。
  • 表中的数据:表中记录的实际内容,每条记录占据表中的一行。
  • 表名:表的名称,用于标识数据库中的特定表。

数据库结构说明

7.2.2 SQL 语句

SQL 语句具有以下特点:

  1. 通用性: 大部分关系型数据库管理系统(如 MySQL、SQLite、PostgreSQL、SQL Server 等)的 SQL 语法基本相同,通用性很强。
  2. 语法规范: SQL 语句不能以 . 开头,且每条语句必须以分号(;)结尾。
  3. 大小写不敏感: 在 SQL 语句中,关键字(如 SELECTFROM 等)对大小写不敏感,通常我们习惯将它们写成大写,以便提高可读性。

以下是常用的 SQL 语句示例,涵盖创建表、插入数据、查询、排序、更新和删除记录等操作,所有语句均符合 SQL 的通用特点。


1. 创建表

CREATE TABLE 语句用于创建表,并定义表的字段和数据类型。主键(PRIMARY KEY)用于唯一标识每一条记录。

语法:

CREATE TABLE 表名 (
    字段名1 数据类型1,
    字段名2 数据类型2,
    ...
);

整型 INT 
字符串 CHAR OR TEXT

示例:

CREATE TABLE log_in (
    id INT PRIMARY KEY,   -- 定义 id 为主键,自动唯一
    User CHAR(50),            -- 字符类型,固定长度为 50 个字符
    password CHAR(50)         -- 字符类型,固定长度为 50 个字符
);

2. 插入数据

INSERT INTO 语句用于向表中插入数据。可以插入所有字段的值,或仅插入指定字段的值。

语法:

INSERT INTO 表名 VALUES (值1, 值2, ...); 
-- 或
INSERT INTO 表名 (字段名1, 字段名2, ...) VALUES (值1, 值2, ...);

示例 1:插入所有字段

INSERT INTO log_in VALUES (1001, '张三', '密码123');

示例 2:插入指定字段

INSERT INTO log_in (id, password) VALUES (1003, '密码456');

注意:

  • 字符串值需要用单引号 ' 或双引号 " 包裹。
  • 未插入的字段将使用默认值或为空。

3. 查询数据

SELECT 语句用于从表中查询数据。可以查询所有字段,也可以查询指定字段。

语法:

SELECT 字段名1, 字段名2, ... FROM 表名;
-- 或
SELECT * FROM 表名;

示例 1:查询所有字段

SELECT * FROM log_in;

示例 2:查询指定字段

SELECT id, User FROM log_in;

4. 带条件的查询

使用 WHERE 子句可以根据条件过滤查询结果。

语法:

SELECT * FROM 表名 WHERE 条件;

示例 1:查询 id 为 1001 的记录

SELECT * FROM log_in WHERE id = 1001;

示例 2:查询 id 为 1001 且用户名为 '张三' 的记录

SELECT * FROM log_in WHERE id = 1001 AND User = '张三';

5. 排序查询结果

ORDER BY 子句用于对查询结果进行排序,默认是升序(ASC),可以使用 DESC 指定降序。

语法:

SELECT * FROM 表名 ORDER BY 字段名 [ASC|DESC];

示例:按 id 降序排列

SELECT * FROM log_in ORDER BY id DESC;

6. 更新数据

UPDATE 语句用于修改表中的记录,WHERE 子句用于指定需要修改的记录。

语法:

UPDATE 表名 SET 字段名 = 新值 WHERE 条件;

示例:修改 id 为 1001 的记录的 password

UPDATE log_in SET password = '新密码' WHERE id = 1001;

7. 删除数据

DELETE 语句用于删除表中的记录,WHERE 子句用于指定要删除的记录。

语法:

DELETE FROM 表名 WHERE 条件;

示例:删除 id 为 1001 的记录

DELETE FROM log_in WHERE id = 1001;

8. 删除表

DROP TABLE 语句用于删除整个表及其所有数据。

语法:

DROP TABLE 表名;

示例:删除 log_in

DROP TABLE log_in;

9. 给表添加列

ALTER TABLE 语句用于向现有表中添加新列。

语法:

ALTER TABLE 表名 ADD COLUMN 列名 数据类型;

示例:向 log_in 表添加 email

ALTER TABLE log_in ADD COLUMN email CHAR(100);

10. 删除表中的列

在 SQLite 中,直接删除列的操作是不被支持的,也就是说,SQLite 不像一些其他数据库系统(如 MySQL、PostgreSQL)允许使用 DROP COLUMN 来删除列。为了解决这个问题,我们需要采取一个替代方法,即通过创建一个新的表来间接删除列。

由于 SQLite 不支持 DROP COLUMN 语法,我们可以按照以下步骤删除表中的列:

  1. 创建新表:新表的结构与旧表相同,但省略掉需要删除的列。
  2. 将旧表中的数据复制到新表:只复制保留的列数据。
  3. 删除旧表
  4. 将新表重命名为旧表的名称

删除表中的列的步骤

假设有一个名为 log_in 的表,其中我们需要删除 email 列:

CREATE TABLE log_in (
    id INTEGER PRIMARY KEY,
    User CHAR(50),
    password CHAR(50),
    email CHAR(100)
);

步骤 1:创建不包含 email 列的新表

CREATE TABLE new_log_in (
    id INTEGER PRIMARY KEY,
    User CHAR(50),
    password CHAR(50)
);

步骤 2:从旧表复制数据到新表

INSERT INTO new_log_in (id, User, password)
SELECT id, User, password FROM log_in;

步骤 3:删除旧表

DROP TABLE log_in;

步骤 4:将新表重命名为旧表的名称

ALTER TABLE new_log_in RENAME TO log_in;

10. 主键定义

主键(PRIMARY KEY)用于唯一标识每条记录。创建表时可以定义主键。

语法:

CREATE TABLE 表名 (
    字段名 数据类型 PRIMARY KEY,
    ...
);

示例:为 log_in 表定义 id 为主键

CREATE TABLE log_in (
    id INTEGER PRIMARY KEY,  -- 定义 id 为主键
    User CHAR(50),
    password CHAR(50)
);

7.3 sqlite3 数据库API

使用sqlite3 提供的函数 ,编写代码时需要加头文件 #include

编译时 需要连接 sqlite3 的库 -lsqlite3

如果我们需要查看数据库说明不能使用man 了 需要去官网中的查看

这里我们介绍一些常用的API

7.3.1 相关api

打开数据库文件

文件 #include <sqlite3.h>

/* 打开数据库文件的函数 */
int sqlite3_open(const char *filename,      /* Database filename (UTF-8) */
                 sqlite3 **ppDb             /* OUT: SQLite db handle */
);

功能:打开一个数据库文件

参数:
   filename: 数据库文件的名字
   ppDb: 操作数据库的指针,句柄

返回值:
   成功: SQLITE_OK
   失败: 错误码

获取错误信息

/* 获取错误信息的函数 */
const char *sqlite3_errmsg(sqlite3 *db);

功能:获取错误信息描述

参数:返回的错误码 句柄

返回值:
    错误码对于的信息

关闭文件

/* 关闭数据库的函数 */
int sqlite3_close(sqlite3 *db);

/* 功能:关闭一个数据库 */

执行sql语句

/* 执行 SQL 语句的函数 */
int sqlite3_exec(sqlite3 *db, 
                 const char *sql, 
                 int (*callback)(void*,int,char**,char**), 
                 void *arg, 
                 char **errmsg);

/* 功能:执行一条 SQL 语句 */

    参数:
        db       : 数据库的句柄指针
        sql      : 将要执行的 SQL 语句
        callback : 回调函数指针,只有在查询语句时,才会给回调函数传参
        arg      : 传递给回调函数的参数 , 只有在查询语句时,才会给回调函数传参
        errmsg   : 错误信息的地址
                    如果使用了errmsg 参数 需要使用sqlite3_free 函数进行释放

返回值:
   成功:SQLITE_OK
   出错:错误码 errcode

回调函数的使用

int callback(void *data, int argc, char **argv, char **azColName)

typedef int (*sqlite3_callback)(
    void*,    /* 在 sqlite3_exec() 的第 4 个参数中提供的数据 */
    int,      /* 行中的列数 */
    char**,   /* 表示行中字段的字符串数组 */
    char**    /* 表示列名的字符串数组 */
);
// 示例程序
int callback(void *data, int argc, char **argv, char **azColName)
{
    for (int i = 0; i < argc; i++)
    {
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
    printf("\n");
    return 0;
}

释放

sqlite3_free(void * )

7.3.2 api 的相关操作

1. 初始化操作

sqlite3 *sqlite3_init_log_in(void)
{
    // 打开数据库
    int sqlite_Errnum = 0;
    sqlite3 *sqlite3_log_in;
    char *errmsg;

    sqlite_Errnum = sqlite3_open("log_in.db", &sqlite3_log_in);
    if (SQLITE_OK != sqlite_Errnum)
    {
        printf("sqlite3_open : errnum:[%d] errstr:[%s]\n", sqlite_Errnum, sqlite3_errmsg(sqlite3_log_in));
        exit(-1);
    }

    printf("打开成功\n");

    // 建立表

    char sql_cmd[128];

    sprintf(sql_cmd, "CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY AUTOINCREMENT , User CHAR(64), password CHAR(64))", Tab_name);
    // INTEGER PRIMARY KEY AUTOINCREMENT 从 1 开始自增
    // IF NOT EXISTS 当有表格时 不会报错
    sqlite_Errnum = sqlite3_exec(sqlite3_log_in, sql_cmd, NULL, NULL, &errmsg);
    if (SQLITE_OK != sqlite_Errnum)
    {
        printf("sqlite3_exec : errnum:[%d] errstr:[%s]\n", sqlite_Errnum, errmsg);
        sqlite3_close(sqlite3_log_in);
        sqlite3_free(errmsg);
        exit(-1);
    }

    // 释放报错信息
    sqlite3_free(errmsg);

    return sqlite3_log_in;

}

2. 插入操作

// 插入
void Insert_INTO_log_in(sqlite3 *sql)
{
    // 用户名
    char user[64];
    // 密码
    char password[64];
    // 数据库错误码
    int sql_err_num;
    // 数据库错误信息
    char * sql_err_str;
    // 数据库命令
    char sql_cmd[1024];

    // 用户输入 插入的信息
    printf("请输入用户名:");
    scanf("%63s" , user);
    printf("请输入用户密码:");
    scanf("%63s" , password);

    // 命令组装
    snprintf( sql_cmd , sizeof(sql_cmd) , "INSERT INTO %s (User, password) VALUES ('%s' , '%s')" ,\
    Tab_name , user ,  password );

    // 执行命令
    sql_err_num = sqlite3_exec( sql , sql_cmd , NULL , NULL , &sql_err_str );
    if (SQLITE_OK != sql_err_num)
    {
        printf("插入错误 : errnum:[%d] errstr:[%s]\n", sql_err_num, sql_err_str );
        sqlite3_free(sql_err_str);
        return ;
    }

    printf("插入成功\n");

    return ;
}

3. 删除操作

4. 查找操作

5. 修改操作

#include <head.h>

#define Tab_name "log_in"

// 初始化
sqlite3 *sqlite3_init_log_in(void);

// 插入
void Insert_INTO_log_in(sqlite3 *sql);

// 删除
void Delete_FROM_log_in(sqlite3 *sql);

// 查找
void Select_FROM_log_in(sqlite3 *sql);

// 修改
void Updata_SET_log_in(sqlite3 *sql);

// 回调函数
int callback(void *data, int argc, char **argv, char **azColName);

int main(int argc, char const *argv[])
{
    // 创建表
    sqlite3 *sql_log_in = sqlite3_init_log_in();
    while (1)
    {
        printf("1、增加学生信息 2、删除学生信息 3、查找学生信息 4、修改学生信息 5、退出\n");

        int sw_num;

        scanf("%d", &sw_num);

        switch (sw_num)
        {
        case 1: // 增加
            Insert_INTO_log_in(sql_log_in);
            break;
        case 2: // 删除
            Delete_FROM_log_in(sql_log_in);
            break;
        case 3: // 查找
            Select_FROM_log_in(sql_log_in);
            break;
        case 4: // 修改
            Updata_SET_log_in(sql_log_in);
            break;
        case 5:
            sqlite3_close(sql_log_in);
            return 0;
        default:
            printf("输入错误\n");
            break;
        }
    }

    sqlite3_close(sql_log_in);

    return 0;
}

sqlite3 *sqlite3_init_log_in(void)
{
    // 打开数据库
    int sqlite_Errnum = 0;
    sqlite3 *sqlite3_log_in;
    char *errmsg;

    sqlite_Errnum = sqlite3_open("log_in.db", &sqlite3_log_in);
    if (SQLITE_OK != sqlite_Errnum)
    {
        printf("sqlite3_open : errnum:[%d] errstr:[%s]\n", sqlite_Errnum, sqlite3_errmsg(sqlite3_log_in));
        exit(-1);
    }

    printf("打开成功\n");

    // 建立表

    char sql_cmd[128];

    sprintf(sql_cmd, "CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY AUTOINCREMENT , User CHAR(64), password CHAR(64))", Tab_name);
    // INTEGER PRIMARY KEY AUTOINCREMENT 从 1 开始自增
    // IF NOT EXISTS 当有表格时 不会报错
    sqlite_Errnum = sqlite3_exec(sqlite3_log_in, sql_cmd, NULL, NULL, &errmsg);
    if (SQLITE_OK != sqlite_Errnum)
    {
        printf("sqlite3_exec : errnum:[%d] errstr:[%s]\n", sqlite_Errnum, errmsg);
        sqlite3_close(sqlite3_log_in);
        sqlite3_free(errmsg);
        exit(-1);
    }

    // 释放报错信息
    sqlite3_free(errmsg);

    return sqlite3_log_in;
}

// 插入
void Insert_INTO_log_in(sqlite3 *sql)
{
    // 用户名
    char user[64];
    // 密码
    char password[64];
    // 数据库错误码
    int sql_err_num;
    // 数据库错误信息
    char *sql_err_str;
    // 数据库命令
    char sql_cmd[1024];

    // 用户输入 插入的信息
    printf("请输入用户名:");
    scanf("%63s", user);
    printf("请输入用户密码:");
    scanf("%63s", password);

    // 命令组装
    snprintf(sql_cmd, sizeof(sql_cmd), "INSERT INTO %s (User, password) VALUES ('%s' , '%s')",
             Tab_name, user, password);

    // 执行命令
    sql_err_num = sqlite3_exec(sql, sql_cmd, NULL, NULL, &sql_err_str);
    if (SQLITE_OK != sql_err_num)
    {
        printf("插入错误 : errnum:[%d] errstr:[%s]\n", sql_err_num, sql_err_str);
        sqlite3_free(sql_err_str);
        return;
    }

    printf("插入成功\n");

    return;
}

// 删除
void Delete_FROM_log_in(sqlite3 *sql)
{
    // 用户id
    int id;
    // 数据库错误码
    int sql_err_num;
    // 数据库错误信息
    char *sql_err_str;
    // 数据库命令
    char sql_cmd[1024];

    // 输入用户id
    printf("请输入要删除的ID:");
    scanf("%d", &id);

    // 组装命令 DELETE FROM log_in WHERE id = 1001;
    snprintf(sql_cmd, sizeof(sql_cmd), "DELETE FROM %s WHERE id = %d",
             Tab_name, id);

    // 执行命令
    sql_err_num = sqlite3_exec(sql, sql_cmd, NULL, NULL, &sql_err_str);
    if (SQLITE_OK != sql_err_num)
    {
        printf("插入错误 : errnum:[%d] errstr:[%s]\n", sql_err_num, sql_err_str);
        sqlite3_free(sql_err_str);
        return;
    }

    printf("删除成功\n");

    return;
}

// 查找
void Select_FROM_log_in(sqlite3 *sql)
{

    // 用户id
    int id;
    // 数据库错误码
    int sql_err_num;
    // 数据库错误信息
    char *sql_err_str;
    // 数据库命令
    char sql_cmd[1024];
    // 是否有数据
    int is = 0;

    // 输入用户id
    printf("请输入要删除的ID:");
    scanf("%d", &id);


    // 组装命令 SELECT * FROM 表名 WHERE 条件;
    snprintf(sql_cmd, sizeof(sql_cmd), "SELECT * FROM %s WHERE id = %d",
             Tab_name , id);

    // 执行命令
    sql_err_num = sqlite3_exec(sql, sql_cmd, callback , (void *)&is , &sql_err_str);
    if (SQLITE_OK != sql_err_num)
    {
        printf("插入错误 : errnum:[%d] errstr:[%s]\n", sql_err_num, sql_err_str);
        sqlite3_free(sql_err_str);
        return;
    }
    if (is == 1)
    {
        printf("找到了\n");
        return;
    }
    printf("没找到\n");
}

// 修改
void Updata_SET_log_in(sqlite3 *sql)
{
    // 用户名
    char user[64];
    // 密码
    char password[64];
    // 用户id
    int id;
    // 数据库错误码
    int sql_err_num;
    // 数据库错误信息
    char *sql_err_str;
    // 数据库命令
    char sql_cmd[1024];
    // 是否有数据
    int is = 0;

    // 输入用户id
    printf("请输入要删除的ID:");
    scanf("%d", &id);

    // 用户输入 修改的信息
    printf("请输入用户名:");
    scanf("%63s", user);

    printf("请输入用户密码:");
    scanf("%63s", password);

    // 组装命令 UPDATE 表名 SET 字段名 = 新值 WHERE 条件;
    snprintf(sql_cmd, sizeof(sql_cmd), "UPDATE %s SET User = '%s' , password = '%s'  WHERE id = %d",
             Tab_name, user  , password , id);

    // 执行命令 
    sql_err_num = sqlite3_exec(sql, sql_cmd, callback, (void *)&is, &sql_err_str);
    if (SQLITE_OK != sql_err_num)
    {
        printf("插入错误 : errnum:[%d] errstr:[%s]\n", sql_err_num, sql_err_str);
        sqlite3_free(sql_err_str);
        return;
    }
}

// 回调函数
int callback(void *data, int argc, char **argv, char **azColName)
{
    for (int i = 0; i < argc; i++)
    {
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
        *((int *)data) = 1;
    }
    printf("\n");
    return 0;
}