9、QT—SQLite使用小记

前言
开发平台:Win10 64位
开发环境:Qt Creator 13.0.0
构建环境:Qt 5.15.2 +MSVC2019 64位
sqlite版本:sqlite3


文章目录

  • 一、Sqlite是什么
  • 二、sqlite使用步骤
    • 2.1 下载
    • 2.2 安装
    • 2.3 使用
  • 三、Qt集成sqlite3
    • 3.1 关键问题
    • 3.2 封装sqlite
  • 四、参考文献
    • 4.1 https://blog.csdn.net/Javachichi/article/details/138106632
    • 4.2 https://zhuanlan.zhihu.com/p/24993071
    • 4.3 https://blog.csdn.net/weixin_50670076/article/details/136350060
    • 4.4 https://www.cnblogs.com/sfy5848/p/4825771.html
    • 4.5 https://blog.csdn.net/only_a_Heroic_car/article/details/119605906
    • 4.6 https://blog.csdn.net/p154613730/article/details/85144718
    • 4.7 https://blog.csdn.net/lms1008611/article/details/81271712


一、Sqlite是什么

SQLite 是一个用 C 语言编写的开源、轻量级、快速、独立且高可靠性的 SQL 数据库引擎,它提供了功能齐全的数据库解决方案。SQLite 几乎可以在所有的手机和计算机上运行,它被嵌入到无数人每天都在使用的众多应用程序中。
此外,SQLite 还具有稳定的文件格式、跨平台能力和向后兼容性等特点。SQLite 的开发者承诺,至少在 2050 年之前保持该文件格式不变。

二、sqlite使用步骤

2.1 下载

官方下载地址: link
在这里插入图片描述
windows平台下载这个预编译的就可以。从后面解释可以看到,压缩包里面是一些命令行工具,用来管理sqlite数据库的。

2.2 安装

下载完后解压得到三个文件,都是用来执行命令行工具的可执行应用。
在这里插入图片描述

  1. sqldiff.exe: 命令行实用程序,用于显示 SQLite 数据库之间的内容差异
  2. sqlite3.exe:命令行实用程序,执行 SQLite 数据库操作和 SQL 语句。
  3. sqlite3_analyzer.exe:命令行实用程序,测量和显示多少和如何有效的空间被用于单个的表和索引与SQLite数据库文件

配置环境变量: 为了在命令提示符或 PowerShell 中从任何地方运行 SQLite,需要将 SQLite 的路径添加到电脑的 PATH 环境变量中。

  • 打开控制面板并选择 “系统”。
  • 点击 “高级系统设置”。
  • 在 “系统属性” 对话框中,点击 “环境变量” 按钮。
  • 在 “系统变量” 部分,滚动找到并选中 “Path”,然后点击 “编辑”。
  • 在 “编辑环境变量” 对话框中,点击 “新建”,然后输入您的 SQLite 目录的路径,比如 C:\sqlite-tools-win-x64-3450300。
  • 点击 “确定” 保存更改。

测试安装: win+r打开一个新的命令提示符或 PowerShell 窗口,并输入 sqlite3。如果您看到了 SQLite 的欢迎消息和一个命令提示符,那么说明您已经成功安装了 SQLite。其实这一步和双击sqlite3.exe实现的功能是一样的,都是调用命令行,只不过可以省去双击sqlite3.exe这一步。
在这里插入图片描述


2.3 使用

根据提示输入.help,获取命令功能提示

C:\Users\qwer>sqlite3
SQLite version 3.45.3 2024-04-15 13:34:05 (UTF-16 console I/O)
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .help
.archive ...             Manage SQL archives
.auth ON|OFF             Show authorizer callbacks
.backup ?DB? FILE        Backup DB (default "main") to FILE
.bail on|off             Stop after hitting an error.  Default OFF
.cd DIRECTORY            Change the working directory to DIRECTORY
.changes on|off          Show number of rows changed by SQL
.check GLOB              Fail if output since .testcase does not match
.clone NEWDB             Clone data into NEWDB from the existing database
.connection [close] [#]  Open or close an auxiliary database connection
.crnl on|off             Translate \n to \r\n.  Default ON
.databases               List names and files of attached databases
.dbconfig ?op? ?val?     List or change sqlite3_db_config() options
.dbinfo ?DB?             Show status information about the database
.dump ?OBJECTS?          Render database content as SQL
.echo on|off             Turn command echo on or off
.eqp on|off|full|...     Enable or disable automatic EXPLAIN QUERY PLAN
.excel                   Display the output of next command in spreadsheet
.exit ?CODE?             Exit this program with return-code CODE
.expert                  EXPERIMENTAL. Suggest indexes for queries
.explain ?on|off|auto?   Change the EXPLAIN formatting mode.  Default: auto
.filectrl CMD ...        Run various sqlite3_file_control() operations
.fullschema ?--indent?   Show schema and the content of sqlite_stat tables
.headers on|off          Turn display of headers on or off
.help ?-all? ?PATTERN?   Show help text for PATTERN
.import FILE TABLE       Import data from FILE into TABLE
.indexes ?TABLE?         Show names of indexes
.limit ?LIMIT? ?VAL?     Display or change the value of an SQLITE_LIMIT
.lint OPTIONS            Report potential schema issues.
.load FILE ?ENTRY?       Load an extension library
.log FILE|on|off         Turn logging on or off.  FILE can be stderr/stdout
.mode MODE ?OPTIONS?     Set output mode
.nonce STRING            Suspend safe mode for one command if nonce matches
.nullvalue STRING        Use STRING in place of NULL values
.once ?OPTIONS? ?FILE?   Output for the next SQL command only to FILE
.open ?OPTIONS? ?FILE?   Close existing database and reopen FILE
.output ?FILE?           Send output to FILE or stdout if FILE is omitted
.parameter CMD ...       Manage SQL parameter bindings
.print STRING...         Print literal STRING
.progress N              Invoke progress handler after every N opcodes
.prompt MAIN CONTINUE    Replace the standard prompts
.quit                    Stop interpreting input stream, exit if primary.
.read FILE               Read input from FILE or command output
.recover                 Recover as much data as possible from corrupt db.
.restore ?DB? FILE       Restore content of DB (default "main") from FILE
.save ?OPTIONS? FILE     Write database to FILE (an alias for .backup ...)
.scanstats on|off|est    Turn sqlite3_stmt_scanstatus() metrics on or off
.schema ?PATTERN?        Show the CREATE statements matching PATTERN
.separator COL ?ROW?     Change the column and row separators
.session ?NAME? CMD ...  Create or control sessions
.sha3sum ...             Compute a SHA3 hash of database content
.shell CMD ARGS...       Run CMD ARGS... in a system shell
.show                    Show the current values for various settings
.stats ?ARG?             Show stats or turn stats on or off
.system CMD ARGS...      Run CMD ARGS... in a system shell
.tables ?TABLE?          List names of tables matching LIKE pattern TABLE
.timeout MS              Try opening locked tables for MS milliseconds
.timer on|off            Turn SQL timer on or off
.trace ?OPTIONS?         Output each SQL statement as it is run
.version                 Show source, library and compiler versions
.vfsinfo ?AUX?           Information about the top-level VFS
.vfslist                 List all available VFSes
.vfsname ?AUX?           Print the name of the VFS stack
.width NUM1 NUM2 ...     Set minimum column widths for columnar output
sqlite>
  • SQLite 新建数据库
    直接执行 .open filename.db 打开或创建一个 SQLite 数据库。如果文件不存在,SQLite 会自动创建它。
    示例:打开或创建名为 test.db 的 SQLite 数据库文件。
sqlite> .open test.db

只要创建个数据库就可以了,下面创建表及其其他操作,在可视化工具中执行就可以,笔者使用navicat来操作。navicat的安装使用教程科查看参考文献4.3。


三、Qt集成sqlite3

Qt5以上版本可以直接使用SQLite(Qt自带驱动)。

3.1 关键问题

首先需要一个驱动,就是QSqlDatabase,这个类是管理整个数据库的核心,另外一个是关键类是QSqlQuery,用来对数据库内容增删改查的。
在使用之前要明确几个问题

  1. 数据库,可以直接生成一个数据库吗?还是需要先创建一个数据库再使用?
  2. 数据库的位置:如果使用已经存在的数据库,这个数据库放在哪里?同exe同一个文件夹?如果自动生成,生成在哪里?同exe同一个文件夹?
  3. 哪些函数来生成数据库、打开数据库、表的操作、增删改查的操作?
    首先回答下第一个问题:可以在程序中自动生成一个数据库,不用通过上面第二节中讲的先创建一个数据库,因为Qt已经添加了sqlite驱动就是QSqlDatabase类。
    第二个问题:如果使用默认的方式,需要将数据库放在exe文件的上一级目录中,因为程序会在这个目录中找有没有这个数据库,如果没有,那就在这个目录下自动创建一个,如果有,那就使用这个数据库。
    当然可以自定义数据库的位置,那么程序就会去这个自定义路径下去找或者自动生成数据库。
    在这里插入图片描述
    第三个问题:主要的函数有下面几个
    1)QSqlDatabase QSqlDatabase::addDatabase((const QString & type, const QString & connectionName = QLatin1String( defaultConnection )
    这个就是数据库生成对象,这里面的参数一个是数据库类型,就是使用的什么数据库,第二个参数就是自定义一个连接名,就是要告诉QSqlDatabase咱们定个名,这样你使用这个名的时候QSqlDatabase知道去操作那个数据库。
    这个返回的类型是QSqlDatabase,就是一个数据库实例,有了他就有权利去操作数据库的生成删除,开启关闭了。
    在这里插入图片描述
    在这里插入图片描述
    2)void QSqlDatabase::setDatabaseName ( const QString & name ),这个函数就是设置数据库的函数,它是可以自动生成数据库的,取决于参数中的这个东西他找不找得到,如果找不到就会按规则自动生成。
    这里的参数形式笔者举个例来说明下,比如有一个test.db的数据库,那么调用的时候可以这样
setDatabaseName("test.db")

这里一定要带后缀名,这样,程序会在上面我们说的默认路径下即exe文件的上一级目录中搜索这个数据库,如果找到了,那就直接用,如果没找到,那就创建一个同名的数据库。
第二个问题就是我们想自定义这个数据库的路径(不管已存在还是未存在的),那就需要这样

setDatabaseName("c:\\databases\\test.db")

这样程序就会去我们给的这个路径中去找,找到使用,找不到,在这个路径下生成同名数据库。
在这里插入图片描述
3)void QSqlDatabase::removeDatabase ( const QString & connectionName ) [static]
在这里插入图片描述

3.2 封装sqlite

上面一小节说明了创建打开数据库,下面把封装好的头文件和源文件贴下

#ifndef SQLITEHELPER_H
#define SQLITEHELPER_H
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QHash>
#include <QString>
#include <QVariant>

class SqliteHelper
{
public:
    SqliteHelper();
    ///
    /// \brief OpenSqlite 打开数据库
    /// \param dbName 数据库名
    /// \param connectName 连接名
    /// \return
    ///
    bool OpenSqlite(const QString &dbName,const QString &connectName);
    ///
    /// \brief CloseSqlite 关闭数据库
    /// \return
    ///
    void CloseSqlite();

    /**
     * @brief getConnectName 获取连接名
     * @return
     */
    QString getConnectName() const;

    /**
     * @brief isExistTable 判断数据表是否存在
     * @param tableName 数据表名
     * @return
     */
    bool isExistTable(const QString &tableName);

    /**
     * @brief createTable 创建数据表
     * @param tableName 数据表名
     * @param fields 字段(字段名和类型,如{"name", "varchar(5)"})
     * @param pks 主键
     * @return
     */
    bool createTable(const QString &tableName, const QHash<QString, QString> &fields, const QList<QString> &pks);

    /**
     * @brief selectData 选择数据(适用于单表选择)
     * @param tableName 数据表名
     * @param fields 选择字段
     * @param data [OUT]数据(按fields的顺序)
     * @return
     */
    bool selectData(const QString &tableName, const QList<QString> &fields, QList<QVariantList> &data);

    /**
     * @brief selectData 选择数据(适用于单表选择)
     * @param tableName 数据表名
     * @param fields 选择字段
     * @param whereConditions where条件
     * @param data [OUT]数据(按fields的顺序)
     * @return
     */
    bool selectData(const QString &tableName, const QList<QString> &fields, const QHash<QString, QVariant> &whereConditions,
                    QList<QVariantList> &data);

    /**
     * @brief selectDataBySql 选择数据(通过sql查询, 多表联合查询)
     * @param sql select语句
     * @param fields 选择字段
     * @param data [OUT]数据(按fields的顺序)
     * @return
     */
    bool selectDataBySql(const QString &sql, const QList<QString> &fields, QList<QVariantList> &data);

    /**
     * @brief insertRowData 插入行数据
     * @param tableName 数据表名
     * @param fields 插入字段
     * @param data 插入数据(数据与字段的顺序需一致)
     * @return
     */
    bool insertRowData(const QString &tableName, const QList<QString> &fields, const QVariantList &data);

    /**
     * @brief insertRowsData 插入多行数据
     * @param tableName 数据表名
     * @param fields 字段
     * @param data 插入数据(数据与字段的顺序需一致)
     * @return
     */
    bool insertRowsData(const QString &tableName, const QList<QString> &fields, const QList<QVariantList> &data);

    /**
     * @brief updateData 更新数据
     * @param tableName 数据表名
     * @param data 更新的字段数据(字段名和值,如{"age", 27})
     * @param whereConditions where条件(字段名和值,如{"age", 27})
     * @return
     */
    bool updateData(const QString &tableName, const QHash<QString, QVariant> &data,
                    const QHash<QString, QVariant> &whereConditions);

    /**
     * @brief deleteData 删除数据
     * @param tableName 数据表名
     * @param whereConditions where条件(字段名和值,如{"age", 27})
     * @return
     */
    bool deleteData(const QString &tableName, const QHash<QString, QVariant> &whereConditions);

    /**
     * @brief exec 执行sql语句
     * @param sql sql语句
     * @return 执行结果
     */
    bool exec(const QString &sql);

    /**
     * @brief hasTransactions 是否支持事务
     * @return
     */
    bool hasTransactions();

    /**
     * @brief transaction 开启事务
     * @return
     */
    bool transaction();

    /**
     * @brief commit 事务提交
     * @return
     */
    bool commit();

    /**
     * @brief rollback 事务回滚
     * @return
     */
    bool rollback();

    /**
     * @brief size 记录数量(在执行select语句后,可用该函数获取select的大小)
     * @return
     */
    int size();

    /**
     * @brief getTableFieldsInfo 获取数据表字段
     * @param tableName 数据表名
     * @param fieldsName [OUT]字段
     * @return
     */
    bool getTableFieldsInfo(const QString &tableName, QList<QString> &fieldsName);

    /**
     * @brief lastQuerySql 获取最新一次执行的sql语句
     * @return
     */
    QString lastQuerySql();

    /**
     * @brief lastError 获取最新的错误信息
     * @return 错误信息
     */
    QString lastError() const;

private:
    /**
     * @brief checkTableInfo 校验数据表信息(数据表和字段是否存在)
     * @param tableName 数据表名
     * @param fields 字段
     * @return
     */
    bool checkTableInfo(const QString &tableName, const QList<QString> &fields);


protected:
    QSqlDatabase sqlDb;
    QString m_connectName;
    QSqlQuery m_query;
    QString m_lastError;
};

#endif // SQLITEHELPER_H


#include "sqlitehelper.h"
#include <QDebug>
#include <QSqlError>
#include <QSqlDriver>
//240522 这个构造函数会被引用的时候实例化
SqliteHelper::SqliteHelper() {
    
}

bool SqliteHelper::OpenSqlite(const QString &dbName, const QString &connectName)
{   
    //QPSQL为数据库类型,OTHER为连接名。
    if (QSqlDatabase::connectionNames().contains(connectName)) {
        //240522 返回一个对象实例,并将值复制给sqlDb

        sqlDb = QSqlDatabase::database(connectName);
    } else {
         
        sqlDb = QSqlDatabase::addDatabase("QSQLITE", connectName);
    }

    m_connectName = connectName;

    if (sqlDb.isOpen()) {
        sqlDb.close();
    }
    //240522 设置数据库名称,这个名称可以是数据库名,也可以是数据库所在的路径
    sqlDb.setDatabaseName(dbName);
    if (sqlDb.open()) {
        m_query = QSqlQuery(sqlDb);
        return true;
    }

    m_lastError = sqlDb.lastError().text();
    return false;
}

void SqliteHelper::CloseSqlite()
{
    sqlDb.close();
}

QString SqliteHelper::getConnectName() const
{
    return m_connectName;
}

bool SqliteHelper::isExistTable(const QString &tableName)
{
    return sqlDb.tables().contains(tableName);
}

///
/// \brief SqliteHelper::createTable 创建表
/// \param tableName 表名
/// \param fields 字段
/// \param pks 主键
/// \return
///
bool SqliteHelper::createTable(const QString &tableName, const QHash<QString, QString> &fields,
                               const QList<QString> &pks)
{
    //如果存在就返回
    if (isExistTable(tableName)) {
        m_lastError = QString("Table [%1] is already exist").arg(tableName);
        return false;
    }

    //不存在,开始拼接字符串
    QString sql = QString("create table %1 (").arg(tableName);

    for (auto iter = fields.begin(); iter != fields.end(); ++iter) {
        sql.append(QString("%1 %2, ").arg(iter.key(), iter.value()));
    }

    sql.append(QString("primary key ("));
    qDebug()<<sql;
    for (const auto &item : pks) {
        sql.append(QString("%1, ").arg(item));
    }
    qDebug()<<sql;
    sql.remove(sql.length() - 2, 2);
    sql.append("))");
    qDebug()<<sql;
    if (m_query.exec(sql)) {
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::selectData(const QString &tableName, const QList<QString> &fields, QList<QVariantList> &data)
{
    if (!checkTableInfo(tableName, fields)) {
        return false;
    }

    QString sql = QString("select ");
    for (const auto &item : fields) {
        sql.append(QString("%1, ").arg(item));
    }
    sql.remove(sql.length() - 2, 2);
    sql.append(QString(" from %1").arg(tableName));

    if (m_query.exec(sql)) {
        while (m_query.next()) {
            QVariantList temp;
            for (const auto &item : fields) {
                temp.append(m_query.value(item));
            }
            data.append(temp);
        }
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::selectData(const QString &tableName, const QList<QString> &fields,
                             const QHash<QString, QVariant> &whereConditions, QList<QVariantList> &data)
{
    QList<QString> tempFields;
    tempFields.append(fields);
    tempFields.append(whereConditions.keys());
    if (!checkTableInfo(tableName, tempFields)) {
        return false;
    }

    QString sql = QString("select ");
    for (const auto &item : fields) {
        sql.append(QString("%1, ").arg(item));
    }
    sql.remove(sql.length() - 2, 2);
    sql.append(QString(" from %1").arg(tableName));

    sql.append(QString(" where "));
    for (auto iter = whereConditions.begin(); iter != whereConditions.end(); ++iter) {
        sql.append(QString("%1 = ? and ").arg(iter.key()));
    }
    sql.remove(sql.length() - 5, 5);

    m_query.prepare(sql);
    for (auto iter = whereConditions.begin(); iter != whereConditions.end(); ++iter) {
        m_query.addBindValue(iter.value());
    }

    if (m_query.exec()) {
        while (m_query.next()) {
            QVariantList temp;
            for (const auto &item : fields) {
                temp.append(m_query.value(item));
            }
            data.append(temp);
        }
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::selectDataBySql(const QString &sql, const QList<QString> &fields, QList<QVariantList> &data)
{
    if (m_query.exec(sql)) {
        while (m_query.next()) {
            QVariantList temp;
            for (const auto &item : fields) {
                temp.append(m_query.value(item));
            }
            data.append(temp);
        }
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::insertRowData(const QString &tableName, const QList<QString> &fields, const QVariantList &data)
{
    if (!checkTableInfo(tableName, fields)) {
        return false;
    }

    QString sql = QString("insert into %1(").arg(tableName);
    for (const auto &item : fields) {
        sql.append(QString("%1, ").arg(item));
    }
    sql.remove(sql.length() - 2, 2);
    sql.append(QString(") values"));

    QString tempValue = QString("(");
    for (int i = 0; i < fields.count(); ++i) {
        tempValue.append(QString("?, "));
    }
    tempValue.remove(tempValue.length() - 2, 2);
    tempValue.append(QString(")"));

    sql.append(tempValue);

    m_query.prepare(sql);

    for (int i = 0; i < fields.count(); ++i) {
        m_query.addBindValue(data.at(i));
    }


    if (m_query.exec()) {
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::insertRowsData(const QString &tableName, const QList<QString> &fields, const QList<QVariantList> &data)
{
    if (!checkTableInfo(tableName, fields)) {
        return false;
    }

    QString sql = QString("insert into %1(").arg(tableName);
    for (const auto &item : fields) {
        sql.append(QString("%1, ").arg(item));
    }
    sql.remove(sql.length() - 2, 2);
    sql.append(QString(") values"));

    QString tempValue = QString("(");
    for (int i = 0; i < fields.count(); ++i) {
        tempValue.append(QString("?, "));
    }
    tempValue.remove(tempValue.length() - 2, 2);
    tempValue.append(QString(")"));

    for (int i = 0; i < data.count(); ++i) {
        sql.append(QString("%1, ").arg(tempValue));
    }
    sql.remove(sql.length() - 2, 2);

    m_query.prepare(sql);
    for (const auto &item : data) {
        for (int i = 0; i < fields.count(); ++i) {
            m_query.addBindValue(item.at(i));
        }
    }

    if (m_query.exec()) {
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::updateData(const QString &tableName, const QHash<QString, QVariant> &data,
                             const QHash<QString, QVariant> &whereConditions)
{
    QList<QString> fields;
    fields << data.keys() << whereConditions.keys();
    if (!checkTableInfo(tableName, fields)) {
        return false;
    }

    QString sql = QString("update %1 set ").arg(tableName);
    for (auto iter = data.begin(); iter != data.end(); ++iter) {
        sql.append(QString("%1 = ?, ").arg(iter.key()));
    }
    sql.remove(sql.length() - 2, 2);

    sql.append(" where ");
    for (auto iter = whereConditions.begin(); iter != whereConditions.end(); ++iter) {
        sql.append(QString("%1 = ? and ").arg(iter.key()));
    }
    sql.remove(sql.length() - 5, 5);

    m_query.prepare(sql);
    for (auto iter = data.begin(); iter != data.end(); ++iter) {
        m_query.addBindValue(iter.value());
    }
    for (auto iter = whereConditions.begin(); iter != whereConditions.end(); ++iter) {
        m_query.addBindValue(iter.value());
    }

    if (m_query.exec()) {
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::deleteData(const QString &tableName, const QHash<QString, QVariant> &whereConditions)
{
    QList<QString> fields = whereConditions.keys();
    if (!checkTableInfo(tableName, fields)) {
        return false;
    }

    QString sql = QString("delete from %1 where ").arg(tableName);
    for (auto iter = whereConditions.begin(); iter != whereConditions.end(); ++iter) {
        sql.append(QString("%1 = ? and ").arg(iter.key()));
    }
    sql.remove(sql.length() - 5, 5);

    m_query.prepare(sql);
    for (auto iter = whereConditions.begin(); iter != whereConditions.end(); ++iter) {
        m_query.addBindValue(iter.value());
    }

    if (m_query.exec()) {
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::exec(const QString &sql)
{
    if (m_query.exec(sql)) {
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

bool SqliteHelper::hasTransactions()
{
    if (m_query.driver()->hasFeature(QSqlDriver::Transactions)) {
        return true;
    }

    m_lastError = QString("This database don't support tasnsactions");
    return false;
}

bool SqliteHelper::transaction()
{
    return sqlDb.transaction();
}

bool SqliteHelper::commit()
{
    return sqlDb.commit();
}

bool SqliteHelper::rollback()
{
    return sqlDb.rollback();
}

int SqliteHelper::size()
{
    int count = -1;
    m_query.first();
    if (m_query.next()) {
        if (m_query.driver()->hasFeature(QSqlDriver::QuerySize)) {
            count = m_query.size();
        } else {
            m_query.last();
            // m_query.at()是返回当前记录的编号(从0开始),所以最后一条记录的编号 +1 就为记录数
            count = m_query.at() + 1;
        }
    }

    m_query.first();
    return count;
}

bool SqliteHelper::getTableFieldsInfo(const QString &tableName, QList<QString> &fieldsName)
{
    QString sql = QString("PRAGMA table_info('%1')").arg(tableName);
    if (m_query.exec(sql)) {
        while (m_query.next()) {
            fieldsName.append(m_query.value(1).toString());
        }
        return true;
    }

    m_lastError = m_query.lastError().text();
    return false;
}

QString SqliteHelper::lastQuerySql()
{
    return m_query.lastQuery();
}

QString SqliteHelper::lastError() const
{
    return m_lastError;
}

bool SqliteHelper::checkTableInfo(const QString &tableName, const QList<QString> &fields)
{
    if (!isExistTable(tableName)) {
        m_lastError = QString("Table [%1] is not exist").arg(tableName);
        return false;
    }

    QList<QString> fieldsName;
    QStringList noFieldsName;
    if (getTableFieldsInfo(tableName, fieldsName)) {
        for (const auto &item : fields) {
            if (!fieldsName.contains(item)) {
                noFieldsName << item;
            }
        }

        if (noFieldsName.count() > 0) {
            m_lastError = QString("Table [%1] have no fields [%2]").arg(tableName).arg(noFieldsName.join(','));
            return false;
        }
    } else {
        return false;
    }

    return true;
}

四、参考文献

4.1 https://blog.csdn.net/Javachichi/article/details/138106632

4.2 https://zhuanlan.zhihu.com/p/24993071

4.3 https://blog.csdn.net/weixin_50670076/article/details/136350060

4.4 https://www.cnblogs.com/sfy5848/p/4825771.html

4.5 https://blog.csdn.net/only_a_Heroic_car/article/details/119605906

4.6 https://blog.csdn.net/p154613730/article/details/85144718

4.7 https://blog.csdn.net/lms1008611/article/details/81271712

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C#, PCANBasicd.dll库读写CAN设备数据

PCAN-Basic是一个简单的 PCAN 系统编程接口。 通过 PCAN-Basic Dll,可以将自己的应用程序连接到设备驱动程序和 PCAN 硬件,以与 CAN 总线进行通信。支持C、C++、C#、Delphi、JAVA、VB、Python等语言。 PCAN-Basic库和驱动下载地址 ​ ​https://www.peak-system.com/filead…

【C#】未能加载文件或程序集“CefSharp.Core.Runtime.dll”或它的某一个依赖项。找不到指定的模块。

欢迎来到《小5讲堂》 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 背景错误提示分析原因解决方法Chromium知识点相关文章 背景 最近在使…

LeetCode 131题详解:高效分割回文串的递归与动态规划方法

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容&#xff0c;和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣&#xff01; 推荐&#xff1a;数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航&#xff1a; LeetCode解锁100…

Shell编程之条件判断语句

目录 一、条件判断 1、test命令 2、文件测试 3、整数值比较 4、字符串判断 5、逻辑测试 二、if语句 1、if单分支语句 2、双分支语句 3、多分之语句 4、case 分支语句 一、条件判断 Shell环境根据命令执行后的返回状态值&#xff08;echo $?&#xff09;来判断是否执行成…

力扣刷题---1748.唯一元素的和【简单】

题目描述 给你一个整数数组 nums 。数组中唯一元素是那些只出现 恰好一次 的元素。 请你返回 nums 中唯一元素的 和 。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3,2] 输出&#xff1a;4 解释&#xff1a;唯一元素为 [1,3] &#xff0c;和为 4 。 示例 2&#xff1a;…

基于BERT的医学影像报告语料库构建

大模型时代&#xff0c;任何行业&#xff0c;任何企业的数据治理未来将会以“语料库”的自动化构建为基石。因此这一系列精选的论文还是围绕在语料库的建设以及自动化的构建。 通读该系列的文章&#xff0c;犹如八仙过海&#xff0c;百花齐放。非结构的提取无外乎关注于非结构…

电路笔记 :元器件焊接相关 酒精灯松香浴加热取芯片

记录一下只使用松香和小火源加热&#xff08;如酒精灯、小蜡烛&#xff09;从电路板中取芯片。 过程 多放松香 让松香淹没芯片尽量均匀加热&#xff0c;等芯片旁边的松香开始从芯片里冒细小的“泡泡”&#xff0c;就差不多了 注&#xff1a;这种方法也可以用于焊接&#xff0…

UBUNTU22.04无法安装nvidia-driver-550 依赖于 nvidia-dkms-550 (<= 550.54.15-1)

类似的报错信息&#xff0c;就是卡在了nvidia-dkms-550无法安装 Loading new nvidia-550.40.07 DKMS files… Building for 6.5.0-15-generic Building for architecture x86_64 Building initial module for 6.5.0-15-generic ERROR: Cannot create report: [Errno 17] File e…

VLAN创建及配置

V-- 虚拟 LAN ---局域网 ---地理覆盖范围较小的网络 MAN ---城域网 WAN ---广域网 VLAN ---虚拟局域网 --- 交换机和路由器协同工作后&#xff0c;将原先的一个广播域&#xff0c;逻辑上切分为多个 第一步:创建VLAN [Huawei]display vlan---查看VLAN信息 VID -- VLAN ID ----…

DNS域名解析与智能选路

要开始访问公网了&#xff01;&#xff01; 你在访问百度的时候&#xff0c;你也不知道百度的IP地址是啥&#xff0c;你只知道他的域名是baidu AD这台设备可以做入站的负载平衡&#xff0c;AD来选择你访问的时候是用联通网还是电信网&#xff0c;避免卡顿 pc并不会域名解析&…

[算法] 优先算法(二): 双指针算法(下)

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏:&#x1f355; Collection与数据结构 (91平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 &#x1f9c0;Java …

Python TCP编程简单实例

客户端&#xff1a;创建TCP链接时&#xff0c;主动发起连接的叫做客户端 服务端&#xff1a;接收客户端的连接 连接其他服务器 可以通过tcp连接其他服务器。 示例&#xff1a; import socket# 1.创建一个socket # 参数1&#xff1a;指定协议 AF_INET&#xff08;ipv4&#…

ftp是什么,ftp能做什么,ftp有什么用 -----在Windows搭建ftp服务器

大家好&#xff0c;我是风屿&#xff0c;今天教大家如何从零开始搭建一台属于自己的ftp&#xff0c;本期教大家搭建Windows客户端的&#xff0c;后面是linux的 首先第一步要有一台联网的Windows电脑 1打开控制面板&#xff0c;找到程序&#xff0c;点击打开或关闭Windows功能…

MQTT 5.0 报文解析 05:DISCONNECT

欢迎阅读 MQTT 5.0 报文系列 的第五篇文章。在上一篇中&#xff0c;我们已经介绍了 MQTT 5.0 的 PINGREQ 和 PINGRESP 报文。现在&#xff0c;我们将介绍下一个控制报文&#xff1a;DISCONNECT。 在 MQTT 中&#xff0c;客户端和服务端可以在断开网络连接前向对端发送一个 DIS…

QT项目-欢乐斗地主游戏

QT项目-欢乐斗地主游戏 游戏概述游戏规则牌型牌型的大小游戏角色游戏规则游戏的胜负游戏计分规则 游戏相关的类介绍卡牌类玩家类窗口类游戏控制类游戏策略类线程类音频类 游戏主要组件卡牌玩家窗口 游戏控制源码 游戏概述 游戏规则 不同地域游戏规则可能有些许差异&#xff0c…

CCF20220601——归一化处理

CCF20220601——归一化处理 代码如下&#xff1a; #include<bits/stdc.h> using namespace std; int main() {int n,a[1000],sum0;scanf("%d",&n);for(int i1;i<n;i){scanf("%d",&a[i]);suma[i];}double aver1.0,b0.0,d1.0;aversum/(n*1…

vue3使用mitt.js进行各种组件间通信

我们在vue工程中&#xff0c;除开vue自带的什么父子间&#xff0c;祖孙间通信&#xff0c;还有一个非常方便的通信方式&#xff0c;类似Vue2.x 使用 EventBus 进行组件通信&#xff0c;而 Vue3.x 推荐使用 mitt.js。可以实现各个组件间的通信 优点&#xff1a;首先它足够小&…

0406 组合放大电路

组合放大电路 共射-共基放大电路共集-共集放大电路 4.6.1 共射—共基放大电路 4.6.2 共集—共集放大电路 共射-共基放大电路 共集-共集放大电路 (a) 原理图 (b)交流通路 T1、T2构成复合管&#xff0c;可等效为一个NPN管

c#点击listview控件获取内容

构造函数添加&#xff1a; 点击事件&#xff1a; &#xff08;listview控件确保有内容&#xff0c;比如已查询到数据添加到了listview&#xff09; if (listView_data_base.Items.Count > 0){listView_data_base.FullRowSelect true;listView_data_base.Items[listView_da…

【C语言】VS编译器的scanf

我们在写代码的时候通常需要用到输入函数&#xff1a;scanf&#xff0c;但在vs编译环境下却必须写为&#xff1a;scanf_s&#xff0c;这是为什么呢&#xff1f;这里就是vs规定的了&#xff0c;VS认为这样写更安全&#xff0c;但如果我们非要写成scanf形式也是有办法的。 # 看我…