Linux下基于SQLite3 实现商店商品管理系统

水果店账单管理系统

一.SQLite相关C接口

如果第一次直接在命令行安装sqlite3,是不包含sqlite3.h这个包的,我们需要单独下载sqlite3支持的库,即通过命令行:

sudo apt install libsqlite3-dev

如果我们不知道该安装什么包来提供sqlite3的C/C++接口,可以通过debian官网通过查询软件包关键词可以知道库是依赖libsqlite3-dev包的。

注意,链接的时候要加上-lsqlite3表示依赖第三方库

关于创建一个数据库,可以通过create table stu (id integer, name text),但是如果连续创建的话会报错,因为已经存在了,所以我们可以使用create table if not exists stu (id integer, name text)来防止重复创建报错。

可以通过句柄来获取错误消息

重要接口

以下是重要的 C&C++ / SQLite 接口程序,基本可以您在 C/C++ 程序中使用 SQLite 数据库的需求。

序号API & 描述
1*sqlite3_open(const char *filename, sqlite3 *ppDb) 该例程打开一个指向 SQLite 数据库文件的连接,返回一个用于其他 SQLite 程序的数据库连接对象。如果 filename 参数是 NULL 或 ‘:memory:’,那么 sqlite3_open() 将会在 RAM 中创建一个内存数据库,这只会在 session 的有效时间内持续。如果文件名 filename 不为 NULL,那么 sqlite3_open() 将使用这个参数值尝试打开数据库文件。如果该名称的文件不存在,sqlite3_open() 将创建一个新的命名为该名称的数据库文件并打开。
2*sqlite3_exec(sqlite3*, const char *sql, sqlite_callback, void *data, char *errmsg) 该例程提供了一个执行 SQL 命令的快捷方式,SQL 命令由 sql 参数提供,可以由多个 SQL 命令组成。在这里,第一个参数 sqlite3 是打开的数据库对象,sqlite_callback 是一个回调,data 作为其第一个参数,errmsg 将被返回用来获取程序生成的任何错误。sqlite3_exec() 程序解析并执行由 sql 参数所给的每个命令,直到字符串结束或者遇到错误为止。
3sqlite3_close(sqlite3*) 该例程关闭之前调用 sqlite3_open() 打开的数据库连接。所有与连接相关的语句都应在连接关闭之前完成。如果还有查询没有完成,sqlite3_close() 将返回 SQLITE_BUSY 禁止关闭的错误消息。

sqlite3_exec函数原型如下:

int sqlite3_exec(
  sqlite3*,                                  /* 数据库句柄 */
  const char *sql,                           /* 执行的SQLite命令 */
  int (*callback)(void*,int,char**,char**),  /* Callback function */
  void *,                                    /* 向回调函数传递的参数是 */
  char **errmsg                              /* Error msg written here */
);

sqlite3_exec()是一个通用函数,可以执行SQLite命令行,相当于间接使用命令行来操作数据库。

打开数据库

直接调用sqlite3_open()打开一个数据库。

检测返回值是否为SQLITE_OK,如果不是,表示出错了,出错信息的获取通过句柄可以获取,如下:

const char *sqlite3_errmsg(sqlite3*);

SQLite有31种返回值,如下:

#define SQLITE_OK           0   /* Successful result */
/* beginning-of-error-codes */
#define SQLITE_ERROR        1   /* Generic error */
#define SQLITE_INTERNAL     2   /* Internal logic error in SQLite */
#define SQLITE_PERM         3   /* Access permission denied */
#define SQLITE_ABORT        4   /* Callback routine requested an abort */
#define SQLITE_BUSY         5   /* The database file is locked */
#define SQLITE_LOCKED       6   /* A table in the database is locked */
#define SQLITE_NOMEM        7   /* A malloc() failed */
#define SQLITE_READONLY     8   /* Attempt to write a readonly database */
#define SQLITE_INTERRUPT    9   /* Operation terminated by sqlite3_interrupt()*/
#define SQLITE_IOERR       10   /* Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT     11   /* The database disk image is malformed */
#define SQLITE_NOTFOUND    12   /* Unknown opcode in sqlite3_file_control() */
#define SQLITE_FULL        13   /* Insertion failed because database is full */
#define SQLITE_CANTOPEN    14   /* Unable to open the database file */
#define SQLITE_PROTOCOL    15   /* Database lock protocol error */
#define SQLITE_EMPTY       16   /* Internal use only */
#define SQLITE_SCHEMA      17   /* The database schema changed */
#define SQLITE_TOOBIG      18   /* String or BLOB exceeds size limit */
#define SQLITE_CONSTRAINT  19   /* Abort due to constraint violation */
#define SQLITE_MISMATCH    20   /* Data type mismatch */
#define SQLITE_MISUSE      21   /* Library used incorrectly */
#define SQLITE_NOLFS       22   /* Uses OS features not supported on host */
#define SQLITE_AUTH        23   /* Authorization denied */
#define SQLITE_FORMAT      24   /* Not used */
#define SQLITE_RANGE       25   /* 2nd parameter to sqlite3_bind out of range */
#define SQLITE_NOTADB      26   /* File opened that is not a database file */
#define SQLITE_NOTICE      27   /* Notifications from sqlite3_log() */
#define SQLITE_WARNING     28   /* Warnings from sqlite3_log() */
#define SQLITE_ROW         100  /* sqlite3_step() has another row ready */
#define SQLITE_DONE        101  /* sqlite3_step() has finished executing */

插入信息

基于sqlite3_exec()使用命令行语句来插入信息,根据上面所讲,插入的命令行如下:

2-- 插入一条记录
	insert into stuinfo values(1001, 'zhangshangngsan', 18, 80);
	insert into stuinfo (id, name, score) values(1002, 'lisi', 90);
	可以按照全部元素的顺序插入,也可以指定元素插入
	插入多条的时候直接在后面加上即可
	insert into stuinfo (id, name, score) values(1002, 'lisi', 90), (1001, 'zhangshan', 18, 80);

先读取到要插入的信息,然后使用sprintf函数格式化为字符串,最后将字符串传递给sqlite3_exec()的第二个参数const char *sql来执行命令行操作数据库。

查询

查询有两种基础方法

  • 基于sqlite3_exec和回调函数,参考链接:https://sqlite.org/c3ref/exec.html
  • 直接使用sqlite3_get_table函数,参考链接:https://sqlite.org/c3ref/free_table.html

sqlite3_exec函数原型如下:

int sqlite3_exec(
  sqlite3*,                                  /* 数据库句柄 */
  const char *sql,                           /* 执行的SQLite命令 */
  int (*callback)(void*,int,char**,char**),  /* Callback function */
  void *,                                    /* 向回调函数传递的参数是 */
  char **errmsg                              /* Error msg written here */
);

sqlite3_exec()是一个通用函数,可以执行SQLite命令行,相当于间接使用命令行来操作数据库。

查询的结果通过回调函数反馈,有几行记录,就调用几次回调函数,所以每次回调函数的执行都是对一行信息的查询。

关于回调函数有如下说明:

  • 有几条记录就会调用几次回调函数
  • 回调函数的参数通过sqlite3_exec的第三个参数传递,给回调函数的第一个参数
  • 每条记录中有几列,就会传给第二个参数column
  • 第三个参数就是对应字段内容 char **value,以字符串的形式传递
  • 第四个参数char ** name就是字段名
  • 二级指针的用法和main函数的参数 char *argv[]一样
  • 回调函数返回的应该是0 表示正确,返回1代表出错

回调函数的定义可以如下:

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

还有,可以通过sqlite3_get_table来获取表信息,sqlite3_get_table 专门用于查询语句,不需要回调了:

int sqlite3_get_table(
  sqlite3 *db,          /* 句柄 */
  const char *zSql,     /* SQL to be evaluated */
  char ***pazResult,    /* 获取的表信息,传递参数时直接一个二维数组的地址 */
  int *pnRow,           /* 行数,包括数据名称 */
  int *pnColumn,        /* 列数 */
  char **pzErrmsg       /* 出错信息 */
);

直接通过行数和列数来输出信息,不过要注意的是,返回到的查询信息,开始是表的数据名称,后面才是每个行的内容。

二.程序要求

假如我家开了个水果超市,有以下水果,想实现自动化管理,扫描二维码就能知道当前的水果状态,进货几天了,
好久需要再次进货,那些水果畅销,那些水果不畅销,那些水果春夏秋冬的价格波动,好,那么现在我想将
这些信息保存在数据库中,那么我应该怎么做;
提示: 建立一张fruit表,
假如水果有: 苹果,香蕉,梨,橘子,葡萄…(可以自己查一下英文保存到数据库)
水果价格: 苹果 5元/斤 香蕉 3元/斤 梨 3.5元/斤 橘子2.5元/斤 葡萄 8元/斤…
当前存货: 苹果 80斤 香蕉 200斤 梨 50斤 橘子300斤 葡萄 100斤…
超市每天水果都有进货和卖出嘛,水果的价格随着季节和天气也会有波动,顾客也会看一下每天水果的价格的嘛,
所以要求,根据上述提示,利用数据库完成水果店各种水果的增(进货)删(卖出)改(波动)查(看价格)功能。
并将进出货的时间和顾客光顾的时间记录到数据库中保存。

三.程序说明

题目要求:
所以要求,根据上述提示,利用数据库完成水果店各种水果的增(进货)删(卖出)改(波动)查(看价格)功能。
并将进出货的时间和顾客光顾的时间记录到数据库中保存。

程序执行:
直接make即可 显示界面,按照指示输入指令即可实现上述所有功能
make clean用于清除二进制可执行文件

程序说明:
main函数中循环执行菜单栏目
根据用户在菜单栏目中的输入跳转到相应的功能区执行,每项功能都封装在一个函数中
功能区描述如下:
	int menu(void);               //菜单
	|
	----void select_fruit(void);      //产看所有货物信息
		void add_fruit(void);         //增加新货物信息
		void delete_fruit(void);      //删除货物信息
		void upadte_fruit(void);      //更新信息
		|
		----void purchase_control(void);  //进货
			void sell_control(void);      //售卖
			void price_change(void);      //价格变动
			
更新信息中可以进行:进货、售卖、价格变动等操作,也可退回上一菜单

进货时间在进货、增加货物信息的时候更新
顾客光顾时间在售卖的时候更新

四.实现代码

#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

static int callback(void*,int,char**,char**);

int menu(void);               //菜单
void select_fruit(void);      //产看所有货物信息
void add_fruit(void);         //增加新货物信息
void delete_fruit(void);      //删除货物信息
void upadte_fruit(void);      //更新信息

void purchase_control(void);  //进货
void sell_control(void);      //售卖
void price_change(void);      //价格变动

static char sql[128] = {0};
static sqlite3 *ppdb; //句柄
static int ret;
#define BUFLEN 255
char tmpBuf[BUFLEN];  //时间字符串


int main(int argc, const char *argv[])
{
    int n;

    //open the SQLite3
    if (sqlite3_open("./fruit.db", &ppdb) != SQLITE_OK) {
        printf("open filed:%s\n", sqlite3_errmsg(ppdb));
        exit(1);
    } 

    time_t t = time( 0 );
 	strftime(tmpBuf, BUFLEN, "%Y-%m-%d %H:%M", localtime(&t));
     printf("%s\n\n\n", tmpBuf);

    //创建数据库,在系统初始化的时候使用一次
    // memset(sql, 0, sizeof(sql));
    // sprintf(sql, "create table fruit (name, price, stockpile, purchase_time, sell_time);");
    // ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
    // if (ret != SQLITE_OK) {
    //     printf("create filed:%s\n", sqlite3_errmsg(ppdb));
    //     exit(1);
    // }

    while (1) {
        n = menu();

        switch (n)
        {
        case 1:
            select_fruit();
            break;
        case 2:
            add_fruit();
            break;
        case 3:
            upadte_fruit(); //包括 进货、售出、价格修改
            break;
        case 4:
            delete_fruit();
            break;
        case 5:
            sqlite3_close(ppdb);
            exit(0);
            
        default:
            printf("wrong number!!!\n");
            break;
        }
    }

    return 0;
}

int menu(void)
{
    int n;

    printf("---- Welcome to GQ's Fruit commodity management system! ----\n");
    printf("- (please input the number as follows)                     -\n");
    printf("- 1.select all commodity                                   -\n");
    printf("- 2.add commodity                                          -\n");
    printf("- 3.upadte commodity                                       -\n");
    printf("- 4.delete commodity                                       -\n");
    printf("- 5.exit system                                            -\n");
    printf("------------------------------------------------------------\n");
    printf("input number here:");
    scanf("%d", &n);

    return n;
}

//查看所有货物信息
void select_fruit(void)
{
    memset(sql, 0, sizeof(sql));
    sprintf(sql, "select * from fruit;");
    ret = sqlite3_exec(ppdb, sql, callback, NULL, NULL);  //useing callback function
    if (ret != SQLITE_OK) {
        printf("select filed:%s\n", sqlite3_errmsg(ppdb));
        exit(1);
    }
    printf("select ok!\n\n\n");
}

static int callback(void *data, int column_number, char *column_data[], char *column_name[])
{
    int i;

    for (i = 0; i < column_number; i++) {
        if (i == column_number-1)
            printf("%13s=%7s ", column_name[i], column_data[i]);
        else
            printf("%13s=%9s , ", column_name[i], column_data[i]);
    }
    puts("");
    return 0;
}

//完成添加新货物信息
void add_fruit(void)
{
    char name[10];
    float price;
    int stockpile;

    printf("please input the fruit message:\n");
    printf(" name   price   stockpile \n>");

    scanf("%s", name);
    scanf("%f", &price);
    scanf("%d", &stockpile);
    getchar(); //吃掉回车

    time_t t = time( 0 );
 	strftime(tmpBuf, BUFLEN, "%Y-%m-%d %H:%M", localtime(&t));

    memset(sql, 0, sizeof(sql));
    sprintf(sql, "insert into fruit values('%s', %f, %d, '%s', NULL);", name, price, stockpile, tmpBuf);//注意冒号
    ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
    if (ret != SQLITE_OK) {
        printf("add filed:%s\n", sqlite3_errmsg(ppdb));
        exit(1);
    }
    printf("add success!\n\n\n");
}

//完成删除货物信息
void delete_fruit(void)
{
    char name[10];

    printf("input delete fruit:");
    scanf("%s", name);
    getchar();

    memset(sql, 0, sizeof(sql));
    sprintf(sql, "delete from fruit where name='%s';", name);//注意冒号
    ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
    if (ret != SQLITE_OK) {
        printf("delete filed:%s\n", sqlite3_errmsg(ppdb));
        exit(1);
    }
    printf("delete %s success\n\n\n", name);
}


//完成进货、卖出、价格波动
void upadte_fruit(void)
{
    int n;

    printf("---- Welcome to GQ's Fruit commodity management system! ----\n");
    printf("- (please input the number as follows)                     -\n");
    printf("- 1.purchase control                                       -\n");
    printf("- 2.sell control                                           -\n");
    printf("- 3.price change                                           -\n");
    printf("- 4.last step                                              -\n");
    printf("- 5.exit system                                            -\n");
    printf("------------------------------------------------------------\n");
    printf("input number here:");
    scanf("%d", &n);

    switch (n)
    {
    case 1:
        purchase_control();
        break;
    case 2:
        sell_control();
        break;
    case 3:
        price_change();
        break;
    case 4:
        return ;
        break;
    case 5:
        sqlite3_close(ppdb);
        break;
    default:
        break;
    }
}

void purchase_control(void)
{
    char name[10];
    int stockpile;

    printf("input fruit name:");
    scanf("%s", name);
    getchar();

    printf("input purchase quantity:");
    scanf("%d", &stockpile);
    getchar();

    sprintf(sql, "update fruit set stockpile=%d where name='%s';", stockpile, name);
    ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
    if (ret != SQLITE_OK) {
        printf("purchase_control filed:%s\n", sqlite3_errmsg(ppdb));
        exit(1);
    }
    printf("purchase_control %s success\n\n\n", name);

}

void sell_control(void)
{
    char name[10];
    int stockpile;

    printf("input fruit name:");
    scanf("%s", name);
    getchar();

    printf("input new stockpile:");
    scanf("%d", &stockpile);
    getchar();

    time_t t = time( 0 );
 	strftime(tmpBuf, BUFLEN, "%Y-%m-%d %H:%M", localtime(&t));

    sprintf(sql, "update fruit set stockpile=%d ,sell_time='%s' where name='%s';", stockpile, tmpBuf, name);
    ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
    if (ret != SQLITE_OK) {
        printf("sell_control filed:%s\n", sqlite3_errmsg(ppdb));
        exit(1);
    }
    printf("sell_control %s success\n\n\n", name);
}

void price_change(void)
{
    char name[10];
    float price;

    printf("input fruit name:");
    scanf("%s", name);
    getchar();

    printf("input new price:");
    scanf("%f", &price);
    getchar();

    sprintf(sql, "update fruit set price=%f where name='%s';", price, name);
    ret = sqlite3_exec(ppdb, sql, NULL, NULL, NULL);
    if (ret != SQLITE_OK) {
        printf("price_change filed:%s\n", sqlite3_errmsg(ppdb));
        exit(1);
    }
    printf("price_change %s success\n\n\n", name);
}
posted @ 2021-01-21 16:19  Aspirant-GQ  阅读(192)  评论(0编辑  收藏  举报