[Qt教程] 第23篇 数据库(三)利用QSqlQuery类执行SQL语句

简介:
楼主
  发表于 2013-5-15 22:39:29  | 查看: 813 | 回复: 0
利用QSqlQuery类执行SQL语句

版权声明

该文章原创于作者yafeilinux,转载请注明出处!




导语

        SQL即结构化查询语言,是关系数据库的标准语言。前面两节中已经在Qt里利用QSqlQuery类执行了SQL语句,这一节我们将详细讲解该类的使用。需要说明,因为我们重在讲解Qt中的数据库使用,而非专业的讲解数据库知识,所以不会对数据库中的一些知识进行深入讲解。



环境: Windows Xp + Qt 4.8.4+Qt Creator2.6.2




目录

一、创建数据库连接
二、 操作结果集
三、在SQL 语句中使用变量
四、批处理操作
五、事务操作




正文


一、创建数据库连接
        前面我们是在主函数中创建数据库连接,然后打开并使用。实际中为了明了方便,一般将数据库连接单独放在一个头文件中。下面来看一个例子。

1. 新建Qt Gui 应用,项目名称为myquery ,基类为QMainWindow ,类名为MainWindow 。完成后打开myquery.pro 并将第一行代码更改为:

QT        += coregui sql

        然后保存该文件。

2. 向项目中添加新的C++ 头文件,名称为 connection.h ,然后打开该文件,更改如下:
#ifndef   CONNECTION_H
#define   CONNECTION_H
#include   <QMessageBox>
#include   <QSqlDatabase>
#include   <QSqlQuery>
static   bool   createConnection()
{
     QSqlDatabase   db   =   QSqlDatabase ::addDatabase( "QSQLITE" );
     db.setDatabaseName( ":memory:" );
     if   (!db.open())   {
        QMessageBox ::critical( 0 ,   qApp->tr("Cannot open database"),
            qApp->tr("Unable to establisha database connection."
                      ),   QMessageBox :: Cancel );
        return   false ;
     }
     QSqlQuery   query;
     query.exec( "create table student (id int primary key, "
                "name varchar(20))" );
     query.exec( "insert into student values(0, 'first')" );
     query.exec( "insert into student values(1, 'second')" );
     query.exec( "insert into student values(2, 'third')" );
     query.exec( "insert into student values(3, 'fourth')" );
     query.exec( "insert into student values(4, 'fifth')" );
     return   true ;
}
#endif   // CONNECTION_H


        在这个头文件中我们添加了一个建立连接的函数,使用这个头文件的目的就是要简化主函数中的内容。这里先创建了一个SQLite 数据库的默认连接,设置数据库名称时使用了“:memory: ”,表明这个是建立在内存中的数据库,也就是说该数据库只在程序运行期间有效,等程序运行结束时就会将其销毁。当然,大家也可以将其改为一个具体的数据库名称,比如“my.db ”,这样就会在项目目录中创建该数据库文件了。下面使用open() 函数将数据库打开,如果打开失败,则弹出提示对话框。最后使用QSqlQuery 创建了一个student 表,并插入了包含id name 两个属性的五条记录,如下图所示。其中,id 属性是int 类型的,“primary key ”表明该属性是主键,它不能为空,而且不能有重复的值;而name 属性是varchar 类型的,并且不大于20 个字符。这里使用的SQL 语句都要包含在双引号中,如果一行写不完,那么分行后,每一行都要使用两个双引号引起来。
23-1.jpg
        需要注意,代码中的query 没有进行任何指定就可以操作前面打开的数据库,这是因为现在只有一个数据库连接,它就是默认连接,这时候所有的操作都是针对该连接的。但是如果要同时操作多个数据库连接,就需要进行指定了,这方面内容可以参考 《Qt Creator快速入门》 的第17 章。


3. 下面我们到main.cpp 中调用连接函数。
#include   "mainwindow.h"
#include   <QApplication>
#include   "connection.h"
int   main ( int   argc,   char   *argv[])
{
     QApplication   a(argc,   argv);
   
     if   (!createConnection())
            return   1 ;
   
     MainWindow   w;
     w.show();
   
     return   a.exec();
}


4. 我们往界面上添加一个按钮来实现查询操作。双击mainwindow.ui 文件进入设计模式。然后将一个Push Button 拖到界面上,并修改其显示文本为“查询”。效果如下图所示。
23-2.jpg


5. 在查询按钮上点击鼠标右键,选择“转到槽”,然后选择clicked() 单击信号槽并点击确定,如下图所示。
23-3.jpg


6. 将槽的内容更改如下:
void   MainWindow ::on_pushButton_clicked()
{
     QSqlQuery   query;
     query.exec( "select * from student" );
     while (query.next())
     {
        qDebug()   <<   query.value( 0 ).toInt()
                                      << query.value(1).toString();
     }
}

7. mainwindow.cpp 文件中添加头文件:
#include   <QSqlQuery>
#include   <QDebug>


8. 运行程序,然后按下查询按钮,在应用程序输出窗口将会输出结果,效果如下图所示。
23-4.jpg



二、操作结果集

在前面的程序中,我们使用query.exec("select * from student");查询出表中所有的内容。其中的SQL语句“select * from student”中“*”号表明查询表中记录的所有属性。而当query.exec("select * from student");这条语句执行完后,我们便获得了相应的执行结果,因为获得的结果可能不止一条记录,所以称之为结果集。
结果集其实就是查询到的所有记录的集合,在QSqlQuery类中提供了多个函数来操作这个集合,需要注意这个集合中的记录是从0开始编号的。最常用的操作有:
  • seek(int n) query指向结果集的第n条记录;
  • first() query指向结果集的第一条记录;
  • last() query指向结果集的最后一条记录;
  • next() query指向下一条记录,每执行一次该函数,便指向相邻的下一条记录;
  • previous() query指向上一条记录,每执行一次该函数,便指向相邻的上一条记录;
  • record() :获得现在指向的记录;
  • value(int n) :获得属性的值。其中n表示你查询的第n个属性,比方上面我们使用“select * from student”就相当于“select id, name from student”,那么value(0)返回id属性的值,value(1)返回name属性的值。该函数返回QVariant类型的数据,关于该类型与其他类型的对应关系,可以在帮助中查看QVariant
  • at() :获得现在query指向的记录在结果集中的编号。
        需要特别注意,刚执行完query.exec("select *from student"); 这行代码时,query 是指向结果集以外的,我们可以利用query.next() 使得 query 指向结果集的第一条记录。当然我们也可以利用seek(0) 函数或者first() 函数使query 指向结果集的第一条记录。但是为了节省内存开销,推荐的方法是,在query.exec("select * from student"); 这行代码前加上query.setForwardOnly(true); 这条代码,此后只能使用next() seek() 函数。
        下面我们通过例子来演示一下这些函数的使用。将槽更改如下:
void   MainWindow ::on_pushButton_clicked()
{
     QSqlQuery   query;
     query.exec( "select * from student" );
     qDebug()   <<   "exec next() :" ;
     // 开始就先执行一次next()函数,那么query指向结果集的第一条记录
     if (query.next())
     {
        // 获取query所指向的记录在结果集中的编号
        int   rowNum   =   query.at();
        // 获取每条记录中属性(即列)的个数
        int   columnNum   =   query.record().count();
        // 获取"name"属性所在列的编号,列从左向右编号,最左边的编号为0
        int   fieldNo   =   query.record().indexOf( "name" );
        // 获取id属性的值,并转换为int型
        int   id   =   query.value( 0 ).toInt();
        // 获取name属性的值
        QString   name   =   query.value(fieldNo).toString();
        // 将结果输出
        qDebug()   <<   "rowNum is : "   <<   rowNum
                  <<   " id is : "   <<   id
                  <<   " name is : "   <<   name
                  <<   " columnNum is : "   <<   columnNum;
     }
// 定位到结果集中编号为2的记录,即第三条记录,因为第一条记录的编号为0
     qDebug()   <<   "exec seek(2) :" ;
     if (query.seek( 2 ))
     {
        qDebug()   <<   "rowNum is : "   <<   query.at()
                  <<   " id is : "   <<   query.value( 0 ).toInt()
                  <<   " name is : "   <<   query.value( 1 ).toString();
     }
     // 定位到结果集中最后一条记录
     qDebug()   <<   "exec last() :" ;
     if (query.last())
     {
        qDebug()   <<   "rowNum is : "   <<   query.at()
                  <<   " id is : "   <<   query.value( 0 ).toInt()
                  <<   " name is : "   <<   query.value( 1 ).toString();
     }
}

        最后在mainwindow.cpp 中添加 #include   <QSqlRecord> 头文件包含,运行程序,点击查询按钮,输出结果如下图所示。
23-5.jpg


三、在SQL语句中使用变量


1. 我们先来看一个例子。首先在设计模式往界面上添加一个Spin Box 部件,如下图所示。
23-6.jpg


2. 将查询按钮槽里面的内容更改如下:
void   MainWindow ::on_pushButton_clicked()
{
     QSqlQuery   query;
     int   id   =   ui -> spinBox ->value();
     query.exec( QString ( "select name from student where id =%1" )
                .arg(id));
     query.next();
     QString   name   =   query.value( 0 ).toString();
     qDebug()   <<   name;
}
        这里使用了QString 类的arg() 函数实现了在SQL 语句中使用变量,我们运行程序,更改Spin Box 的值,然后点击查询按钮,效果如下图所示。
23-7.jpg

3. 其实在QSqlQuery 类中提供了数据绑定同样可以实现在SQL 语句中使用变量,虽然它也是通过占位符来实现的,不过使用它形式上更明了一些。下面先来看一个例子,将查询按钮槽更改如下:
  1. void MainWindow::on_pushButton_clicked()
  2. {
  3.     QSqlQuery query;
  4.     query.prepare("insert into student (id, name) "
  5.                   "values (:id, :name)");
  6.     query.bindValue(0, 5);
  7.     query.bindValue(1, "sixth");
  8.     query.exec();
  9.     query.exec("select * from student");
  10.     query.last();
  11.     int id = query.value(0).toInt();
  12.     QString name = query.value(1).toString();
  13.     qDebug() << id << name;
  14. }
复制代码
        这里在student 表的最后又添加了一条记录。然后我们先使用了prepare() 函数,在其中利用了“:id” “:name” 来代替具体的数据,而后又利用bindValue() 函数给id name 两个属性赋值,这称为绑定操作。其中编号0 1 分别代表“:id” “:name” ,就是说按照prepare() 函数中出现的属性从左到右编号,最左边是
特别注意,在最后一定要执行exec()函数,所做的操作才能被真正执行。运行程序,点击查询按钮,可以看到前面添加的记录的信息。这里的“:id”和“:name”,叫做占位符,这是ODBC数据库的表示方法,还有一种Oracle的表示方法就是全部用“?”号。例如:
query.prepare("insert into student(id, name) "
                   "values (?, ?)" );
query.bindValue(0, 5);
query.bindValue(1, "sixth");
query.exec();


也可以利用addBindValue() 函数,这样就可以省去编号,它是按顺序给属性赋值的,如下:


query.prepare("insert into student(id, name) "
                   "values (?, ?)" );
query.addBindValue(5);
query.addBindValue("sixth");
query.exec();


当用ODBC 的表示方法时,我们也可以将编号用实际的占位符代替,如下:


query.prepare("insert into student(id, name) "
                       "values (:id, :name)" );
query.bindValue(":id", 5);
query.bindValue(":name", "sixth");
query.exec();
以上各种形式的表示方式效果是一样的。


4. 下面我们演示一下通过绑定操作在SQL 语句中使用变量。更改槽函数如下:
void   MainWindow ::on_pushButton_clicked()
{
     QSqlQuery   query;
     query.prepare( "select name from student where id = ?" );
     int   id   =   ui -> spinBox ->value();
     query.addBindValue(id);
     query.exec();
     query.next();
     qDebug()   <<   query.value( 0 ).toString();
}
        运行程序,可以实现通过Spin Box 的值来进行查询。



四、批处理操作

        当要进行多条记录的操作时,我们就可以利用绑定进行批处理。将槽更改如下:
void   MainWindow ::on_pushButton_clicked()
{
     QSqlQuery   q;
     q.prepare( "insert into student values (?, ?)" );
     QVariantList   ints;
     ints   <<   10   <<   11   <<   12   <<   13 ;
     q.addBindValue(ints);
     QVariantList   names;
     //  最后一个是空字符串,应与前面的格式相同
        names << "xiaoming" << "xiaoliang"
                      << "xiaogang" << QVariant(QVariant::String);
     q.addBindValue(names);
     if   (!q.execBatch())   // 进行批处理,如果出错就输出错误
        qDebug()   <<   q.lastError();
     // 下面输出整张表
     QSqlQuery   query;
     query.exec( "select * from student" );
     while (query.next())
     {
        int   id   =   query.value( 0 ).toInt();
        QString   name   =   query.value( 1 ).toString();
        qDebug()   <<   id   <<   name;
     }
}
        然后需要在mainwindow.cpp 上添加头文件包含: #include   <QSqlError> 我们在程序中利用列表存储了同一属性的多个值,然后进行了值绑定。最后执行execBatch() 函数进行批处理。注意程序中利用QVariant(QVariant::String) 来输入空值NULL ,因为前面都是QString 类型的,所以这里要使用QVariant::String  使格式一致化。
运行程序,效果如下图所示:
27-8.jpg



五、事务操作

        事务可以保证一个复杂的操作的原子性,就是对于一个数据库操作序列,这些操作要么全部做完,要么一条也不做,它是一个不可分割的工作单位。在Qt 中,如果底层的数据库引擎支持事务,那么QSqlDriver::hasFeature(QSqlDriver::Transactions) 会返回true 。可以使用QSqlDatabase::transaction() 来启动一个事务,然后编写一些希望在事务中执行的SQL 语句,最后调用QSqlDatabase::commit() 或者QSqlDatabase::rollback() 。当使用事务时必须在创建查询以前就开始事务,例如:
QSqlDatabase::database().transaction();
QSqlQuery   query;
query.exec("SELECT id FROMemployee WHERE name = 'Torild Halvorsen'");
if   ( query.next()) {
     int   employeeId = query.value(0).toInt();
     query.exec("INSERT INTO project(id, name, ownerid) "
                "VALUES (201, 'ManhattanProject', "
                +   QString ::number( employeeId) + ')');
}
QSqlDatabase::database().commit();



结语

        对执行SQL 语句我们就介绍这么多,其实Qt 中提供了更为简单的不需要SQL 语句就可以操作数据库的方法,我们在下一节讲述这些内容。




涉及到的源码:  myquery01.zip (3.2 KB, 下载次数: 7)  myquery02.zip (3.23 KB, 下载次数: 5) 



相关文章
|
7天前
|
SQL 人工智能 算法
【SQL server】玩转SQL server数据库:第二章 关系数据库
【SQL server】玩转SQL server数据库:第二章 关系数据库
45 10
|
24天前
|
SQL 存储 BI
【软件设计师备考 专题 】数据库语言(SQL)
【软件设计师备考 专题 】数据库语言(SQL)
89 0
|
28天前
|
SQL 数据库
sql server中创建数据库和表的语法
sql server中创建数据库和表的语法
17 1
|
7天前
|
SQL 算法 数据库
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
61 6
|
3天前
|
SQL 数据库
数据库SQL语言实战(二)
数据库SQL语言实战(二)
|
4天前
|
SQL 关系型数据库 数据库
【后端面经】【数据库与MySQL】SQL优化:如何发现SQL中的问题?
【4月更文挑战第12天】数据库优化涉及硬件升级、操作系统调整、服务器/引擎优化和SQL优化。SQL优化目标是减少磁盘IO和内存/CPU消耗。`EXPLAIN`命令用于检查SQL执行计划,关注`type`、`possible_keys`、`key`、`rows`和`filtered`字段。设计索引时考虑外键、频繁出现在`where`、`order by`和关联查询中的列,以及区分度高的列。大数据表改结构需谨慎,可能需要停机、低峰期变更或新建表。面试中应准备SQL优化案例,如覆盖索引、优化`order by`、`count`和索引提示。优化分页查询时避免大偏移量,可利用上一批的最大ID进行限制。
22 3
|
6天前
|
SQL 监控 数据库
数据库管理与电脑监控软件:SQL代码优化与实践
本文探讨了如何优化数据库管理和使用电脑监控软件以提升效率。通过SQL代码优化,如使用索引和调整查询语句,能有效提高数据库性能。同时,合理设计数据库结构,如数据表划分和规范化,也能增强管理效率。此外,利用Python脚本自动化收集系统性能数据,并实时提交至网站,可实现对电脑监控的实时性和有效性。这些方法能提升信息系统稳定性和可靠性,满足用户需求。
29 0
|
7天前
|
SQL 存储 数据挖掘
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
服务器数据恢复环境: 一台安装windows server操作系统的服务器。一组由8块硬盘组建的RAID5,划分LUN供这台服务器使用。 在windows服务器内装有SqlServer数据库。存储空间LUN划分了两个逻辑分区。 服务器故障&初检: 由于未知原因,Sql Server数据库文件丢失,丢失数据涉及到3个库,表的数量有3000左右。数据库文件丢失原因还没有查清楚,也不能确定数据存储位置。 数据库文件丢失后服务器仍处于开机状态,所幸没有大量数据写入。 将raid5中所有磁盘编号后取出,经过硬件工程师检测,没有发现明显的硬件故障。以只读方式将所有磁盘进行扇区级的全盘镜像,镜像完成后将所
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
|
15天前
|
数据库 SQL 索引
什么是数据库 SQL Execution Plan
什么是数据库 SQL Execution Plan
10 0
|
17天前
qt开发使用camera类获取摄像头信息并拍照保存
qt开发使用camera类获取摄像头信息并拍照保存

推荐镜像

更多