数据库SQLite的使用
SQLite是一个C语言库,实现了一个小型、快速、独立、高可靠性、功能齐全的SQL数据库引擎。SQLite文件格式稳定、跨平台且向后兼容。SQLite源代码属于公共领域(public-domain),任何人都可以免费将其用于任何目的。源码地址:https://github.com/sqlite/sqlite,最新发布版本为3.47.0。
SQLite是关系型数据库,与许多其它数据库管理系统不同,SQLite不是一个客户端/服务器结构的数据库引擎,而是被集成在用户程序中。SQLite将整个数据库,包括定义、表、索引以及数据本身,作为一个单独的、可跨平台使用的文件存储在主机中。
SQLite提供了一个叫做sqlite3的独立程序用来查询和管理SQLite数据库文件,可从 https://www.sqlite.org/download.html 下载sqlite-tools-win-x64-3470000.zip获取到。
所有的SQLite语句可以以任何关键字开始,如SELECT、INSERT、UPDATE、DELETE、ALTER、DROP等,所有的语句通常使用分号;结束。
Windows10上生成SQLite静态库:
(1).从 https://www.sqlite.org/download.html 下载sqlite-dll-win-x64-3470000.zip和sqlite-amalgamation-3470000.zip
(2).解压缩到同一目录下:此目录下有sqlite3.dll、sqlite3.def、sqlite3.h、sqlite3.c、sqlite3ext.h、shell.c
(3).打开"Developer Command Prompt for VS 2022",并将其定位到存放sqlite的目录下,执行如下命令:执行完后会生成sqlite3.lib和sqlite3.exp
lib /DEF:sqlite3.def /OUT:sqlite3.lib /MACHINE:x64
SQLite开源的可视化工具DB Browser for SQLite(DB4S)的使用:
1.SQLite数据库浏览器(DB4S)是一款高质量、可视化、开源工具,用于创建、设计和编辑与SQLite兼容的数据库文件。源码地址:https://github.com/sqlitebrowser/sqlitebrowser,license为GPL或类似的开源许可证,最新发布版本为v3.13.1。它是跨平台的,可在Windows、Linux、MacOS等操作系统上使用。DB4S操作:
(1).创建和压缩数据库文件
(2).创建、定义、修改和删除表
(3).创建、定义和删除索引
(4).浏览、编辑、添加和删除记录(records)
(5).搜索记录
(6).以文本形式导入和导出记录
(7).从CSV文件导入和导出表
(8).从SQL转储文件(dump files)导入和导出数据库
(9).SQL查询并检查结果
2.Windows10上安装DB4S:
(1).从https://github.com/sqlitebrowser/sqlitebrowser/releases/tag/v3.13.1 下载DB.Browser.for.SQLite-v3.13.1-win64.zip,并解压缩
(2).双击打开DB Browser for SQLite.exe即可:界面如下:
注:
(1).SQLite是不区分大小写的,但也有一些命令是大小写敏感的。
(2).SQLite没有一个单独的用于存储日期和/或时间的存储类,但SQLite能够把日期和时间存储为TEXT、REAL或INTEGER值。
(3).在对当前数据库进行操作(c++)前,需要先关闭DB4S。
(4).DB4S没有刷新功能,而PostgreSQL的图形界面(pgAdmin 4)有。
以下为测试代码段:
(1).创建数据库:
int create_database(const std::string& dbname)
{
sqlite3* db{ nullptr };
auto ret = sqlite3_open(dbname.c_str(), &db); // 如果数据库不存在,则会创建它
if (ret != SQLITE_OK)
std::cerr << "Error: fail to sqlite3_open: " << ret << ", " << sqlite3_errmsg(db) << std::endl;
sqlite3_close(db);
return ret;
}
(2).删除数据库:直接调用C++17中的std::filesystem::remove函数删除类似*.db的文件
int delete_database(const std::string& dbname)
{
namespace fs = std::filesystem;
fs::path file{ dbname };
if (fs::exists(file)) {
try {
fs::remove(file);
}
catch (const fs::filesystem_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
return -1;
}
} else {
std::cerr << "Warning: database file does not exist: " << dbname << std::endl;
return -1;
}
return 0;
}
(3).创建表:
int create_table(const std::string& dbname, const std::string& command)
{
sqlite3* db{ nullptr };
auto ret = sqlite3_open(dbname.c_str(), &db);
if (ret != SQLITE_OK)
std::cerr << "Error: fail to sqlite3_open: " << ret << ", " << sqlite3_errmsg(db) << std::endl;
char* errmsg{ nullptr };
ret = sqlite3_exec(db, command.c_str(), nullptr, nullptr, &errmsg);
if (ret != SQLITE_OK) {
std::cerr << "Error: fail to create table: " << ret << ", " << errmsg << std::endl;
sqlite3_free(errmsg);
}
sqlite3_close(db);
return ret;
}
(4).删除表:
int drop_table(const std::string& dbname, const std::string& tablename)
{
sqlite3* db{ nullptr };
auto ret = sqlite3_open(dbname.c_str(), &db);
if (ret != SQLITE_OK)
std::cerr << "Error: fail to sqlite3_open: " << ret << ", " << sqlite3_errmsg(db) << std::endl;
char* errmsg{ nullptr };
const std::string str{ "DROP TABLE " };
ret = sqlite3_exec(db, (str+tablename).c_str(), nullptr, nullptr, &errmsg);
if (ret != SQLITE_OK) {
std::cerr << "Error: fail to drop table: " << ret << ", " << errmsg << std::endl;
sqlite3_free(errmsg);
}
sqlite3_close(db);
return ret;
}
(5).向表中插入数据:
int insert_into_teacher(const std::string& dbname, int id, const std::string& name, const std::string& addr, const std::string& sex)
{
sqlite3* db{ nullptr };
auto ret = sqlite3_open(dbname.c_str(), &db);
if (ret != SQLITE_OK)
std::cerr << "Error: fail to sqlite3_open: " << ret << ", " << sqlite3_errmsg(db) << std::endl;
char* errmsg{ nullptr };
std::string str{ "INSERT INTO teacher (id, name, addr, sex) VALUES (" };
str = str + std::to_string(id) + ", '" + name + "', '" + addr + "', '" + sex + "');";
ret = sqlite3_exec(db, str.c_str(), nullptr, nullptr, &errmsg);
if (ret != SQLITE_OK) {
std::cerr << "Error: fail to insert into teacher: " << ret << ", " << errmsg << std::endl;
sqlite3_free(errmsg);
}
sqlite3_close(db);
return ret;
}
std::string get_current_time()
{
auto timenow = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::tm* now_tm = std::localtime(&timenow);
std::ostringstream oss;
oss << std::put_time(now_tm, "%Y-%m-%d %H:%M:%S");
return oss.str();
}
int insert_into_student(const std::string& dbname, int id, const std::string& name, const std::string& addr, int age,
float score, const std::string& date, const std::string& sex)
{
sqlite3* db{ nullptr };
auto ret = sqlite3_open(dbname.c_str(), &db);
if (ret != SQLITE_OK)
std::cerr << "Error: fail to sqlite3_open: " << ret << ", " << sqlite3_errmsg(db) << std::endl;
char* errmsg{ nullptr };
std::string str{ "INSERT INTO student (id, name, addr, age, score, date, sex) VALUES (" };
str = str + std::to_string(id) + ", '" + name + "', '" + addr + "'," + std::to_string(age) + "," +
std::to_string(score) + ", '" + date + "', '" + sex + "'); ";
ret = sqlite3_exec(db, str.c_str(), nullptr, nullptr, &errmsg);
if (ret != SQLITE_OK) {
std::cerr << "Error: fail to insert into student: " << ret << ", " << errmsg << std::endl;
sqlite3_free(errmsg);
}
sqlite3_close(db);
return ret;
}
(6).向已有表中添加、删除列:
int alter_table(const std::string& dbname)
{
sqlite3* db{ nullptr };
auto ret = sqlite3_open(dbname.c_str(), &db);
if (ret != SQLITE_OK)
std::cerr << "Error: fail to sqlite3_open: " << ret << ", " << sqlite3_errmsg(db) << std::endl;
char* errmsg{ nullptr };
const std::string str{ "ALTER TABLE teacher " };
const std::string str1{ "ADD COLUMN hobbies CHAR(64) DEFAULT swim;" };
ret = sqlite3_exec(db, (str+str1).c_str(), nullptr, nullptr, &errmsg);
if (ret != SQLITE_OK) {
std::cerr << "Error: fail to add cloumn: " << ret << ", " << errmsg << std::endl;
sqlite3_free(errmsg);
}
const std::string str2{ "DROP COLUMN addr;" };
ret = sqlite3_exec(db, (str + str2).c_str(), nullptr, nullptr, &errmsg);
if (ret != SQLITE_OK) {
std::cerr << "Error: fail to drop column: " << ret << ", " << errmsg << std::endl;
sqlite3_free(errmsg);
}
sqlite3_close(db);
return ret;
}
(7).删除表中数据:
int delete_table_data(const std::string& dbname)
{
sqlite3* db{ nullptr };
auto ret = sqlite3_open(dbname.c_str(), &db);
if (ret != SQLITE_OK)
std::cerr << "Error: fail to sqlite3_open: " << ret << ", " << sqlite3_errmsg(db) << std::endl;
char* errmsg{ nullptr };
const std::string str{ "DELETE FROM teacher WHERE id > 10000 OR sex='女';" };
ret = sqlite3_exec(db, str.c_str(), nullptr, nullptr, &errmsg);
if (ret != SQLITE_OK) {
std::cerr << "Error: fail to delete data from teachar: " << ret << ", " << errmsg << std::endl;
sqlite3_free(errmsg);
}
sqlite3_close(db);
return ret;
}
(8).调整表中已有数据:
int update_table_data(const std::string& dbname)
{
sqlite3* db{ nullptr };
auto ret = sqlite3_open(dbname.c_str(), &db);
if (ret != SQLITE_OK)
std::cerr << "Error: fail to sqlite3_open: " << ret << ", " << sqlite3_errmsg(db) << std::endl;
char* errmsg{ nullptr };
const std::string str1 = std::string("UPDATE teacher SET sex = 'man' WHERE sex = ") + "\'" + gbk_to_utf8("男") + "\';";
ret = sqlite3_exec(db, str1.c_str(), nullptr, nullptr, &errmsg);
if (ret != SQLITE_OK) {
std::cerr << "Error: fail to update data from teachar: " << ret << ", " << errmsg << std::endl;
sqlite3_free(errmsg);
}
const std::string str2 = std::string("UPDATE teacher SET sex = ") + "\'" + gbk_to_utf8("女") + "\'" + " WHERE sex = 'woman';";
ret = sqlite3_exec(db, str2.c_str(), nullptr, nullptr, &errmsg);
if (ret != SQLITE_OK) {
std::cerr << "Error: fail to update data from teachar: " << ret << ", " << errmsg << std::endl;
sqlite3_free(errmsg);
}
sqlite3_close(db);
return ret;
}
(9).查询表中数据:
int select_table_data(const std::string& dbname)
{
sqlite3* db{ nullptr };
auto ret = sqlite3_open(dbname.c_str(), &db);
if (ret != SQLITE_OK)
std::cerr << "Error: fail to sqlite3_open: " << ret << ", " << sqlite3_errmsg(db) << std::endl;
const std::string query{ "SELECT * FROM student WHERE age >= 20 AND DATETIME(date) > DATETIME('2024-11-07 17:54:30');" };
char* errmsg{ nullptr };
sqlite3_stmt* stmt{ nullptr };
ret = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, 0);
if (ret != SQLITE_OK) {
std::cerr << "Error: fail to sqlite3_prepare_v2: " << ret << ", " << sqlite3_errmsg(db) << std::endl;
return ret;
}
std::cout << "id\tname\taddr\tage\tscore\tdate\t\t\t\tsex" << std::endl;
while (sqlite3_step(stmt) == SQLITE_ROW) {
auto id = sqlite3_column_int(stmt, 0);
auto name = utf8_to_gbk(std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1))));
auto addr = utf8_to_gbk(std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2))));
auto age = sqlite3_column_int(stmt, 3);
auto score = sqlite3_column_double(stmt, 4);
auto date = std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 5)));
auto sex = utf8_to_gbk(std::string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 6))));
std::cout << id << "\t" << name << "\t" << addr << "\t" << age << "\t" << score << "\t"
<< date << "\t\t" << sex << std::endl;
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return ret;
}
全局变量设置如下:
const std::string table_teacher{ "CREATE TABLE teacher ("
"id INTEGER PRIMARY KEY NOT NULL CHECK(id>1000),"
"name TEXT NOT NULL,"
"addr TEXT DEFAULT 'BeiJing',"
"sex TEXT NOT NULL);" };
const std::string table_student{ "CREATE TABLE student ("
"id INTEGER PRIMARY KEY NOT NULL,"
"name CHAR(32) NOT NULL,"
"addr CHAR(64) DEFAULT 'TianJin',"
"age INTEGER,"
"score REAL,"
"date CHAR(24),"
"sex CHAR(8) NOT NULL);" };
SQLite中没有实现类似libpqxx中的set_client_encoding函数,如果表中数据有中文则会显示乱码,这里实现utf8和gbk之间的转换:
inline std::string gbk_to_utf8(const std::string& str)
{
#ifdef _MSC_VER
// gbk to wchar
auto len = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, nullptr, 0);
std::wstring wstr(len, 0);
::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, &wstr[0], len);
// wchar to utf8
len = ::WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
std::string u8str(len, 0);
::WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &u8str[0], len, nullptr, nullptr);
u8str.pop_back(); // remove '\0'
return u8str;
#else
return std::string{"Unimplemented"};
#endif
}
inline std::string utf8_to_gbk(const std::string& u8str)
{
#ifdef _MSC_VER
// utf8 to wchar
auto len = ::MultiByteToWideChar(CP_UTF8, 0, u8str.c_str(), -1, nullptr, 0);
std::wstring wstr(len, 0);
::MultiByteToWideChar(CP_UTF8, 0, u8str.c_str(), -1, &wstr[0], len);
// wchar to gbk
len = ::WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
std::string str(len, 0);
::WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, &str[0], len, nullptr, nullptr);
str.pop_back(); // remove '\0'
return str;
#else
return std::string{"Unimplemented"};
#endif
}
主函数如下:
int test_sqlite()
{
const std::string dbname{ "info.db" };
//create_database(dbname);
delete_database(dbname);
create_table(dbname, table_teacher);
create_table(dbname, table_student);
//drop_table(dbname, "teacher");
//drop_table(dbname, "student");
insert_into_teacher(dbname, 1111, gbk_to_utf8("Tom"), gbk_to_utf8("HeBei"), gbk_to_utf8("man"));
insert_into_teacher(dbname, 5555, gbk_to_utf8("Tom"), gbk_to_utf8("北京"), gbk_to_utf8("男"));
insert_into_teacher(dbname, 2222, gbk_to_utf8("小张"), gbk_to_utf8("天津"), gbk_to_utf8("woman"));
insert_into_teacher(dbname, 16625, gbk_to_utf8("小王"), gbk_to_utf8("Tianjin"), gbk_to_utf8("女"));
insert_into_student(dbname, 8, gbk_to_utf8("小王"), gbk_to_utf8("HeBei"), 32, 88.8f, get_current_time(), gbk_to_utf8("男"));
insert_into_student(dbname, 28, gbk_to_utf8("小何"), gbk_to_utf8("深圳"), 8, 22.22f, get_current_time(), gbk_to_utf8("女"));
std::this_thread::sleep_for(std::chrono::minutes(1));
insert_into_student(dbname, 29, gbk_to_utf8("Lucy"), gbk_to_utf8("北京"), 18, 22.22f, get_current_time(), gbk_to_utf8("woman"));
insert_into_student(dbname, 33, gbk_to_utf8("Tom"), gbk_to_utf8("深圳"), 28, 22.22f, get_current_time(), gbk_to_utf8("woman"));
insert_into_student(dbname, 18, gbk_to_utf8("小李"), gbk_to_utf8("上海"), 28, 66.6f, get_current_time(), gbk_to_utf8("女"));
std::this_thread::sleep_for(std::chrono::seconds(5));
insert_into_student(dbname, 48, gbk_to_utf8("Tom"), gbk_to_utf8("深圳"), 38, 22.22f, get_current_time(), gbk_to_utf8("woman"));
alter_table(dbname);
delete_table_data(dbname);
update_table_data(dbname);
select_table_data(dbname);
return 0;
}
执行结果如下:
DB4S显示内容如下:
GitHub:https://github.com/fengbingchun/Messy_Test