Qt 实现SQLite全部语法
- 【1】SQLite Qt界面设计
- 【2】SQLite Qt数据库创建、打开、关闭、删除
- 【3】SQLite Qt表格的创建
- 【4】SQLite Qt表格的插入
- 【5】SQLite Qt表格的查询
- 【6】SQLite Qt表格的删除
- 【7】SQLite Qt表格的更新
- 【8】SQLite Qt表格的结构
- 【9】SQLite Qt表格的修改
- 【10】SQLite 常用内置函数举例
- 1、计算表格行数
- 2、计算表格某列最大值
- 3、计算表格某列最小值
- 4、计算表格某列平均值
- 5、计算表格某列总和
- 6、计算一个随机数
- 7、计算绝对值
- 8、字符串转化大小写
- 9、计算字符串长度
- 10、效果
- 【11】SQLite 日期函数
- 【12】SQLite LIKE和GLOB子句(通配符)
- 【13】SQLite LIMIT子句 (限定行显示)
- 【14】SQLite 表格排序 (升序、降序)
- 【15】SQLite GROUP BY子句 (分组)
- 【16】SQLite HAVING 子句(分组的条件)
- 【17】SQLite DISTINCT 关键字(去重)
- 【18】SQLite 交叉连接(CROSS JOIN)
- 【19】SQLite 内连接(INNER JOIN)
- 【20】SQLite 外连接(OUTER JOIN)
- 【21】UNION 子句 (查询行不重复、重复)
- 【22】SQLite 触发器(Trigger)
- 【23】SQLite 视图(View)
- 【24】SQLite 事务(Transaction)
- 【25】SQLite 子查询或内部查询或嵌套查询
- 【26】EXPLAIN (注释)
本节SQLite相关概念在鄙人个人公众号:👍Qt历险记👍
感兴趣的朋友可以关注下。
本次将SQLite在Qt中实现,方便用到的时候直接套模板,通过Qt信号与槽机制,将SQLite的语法基本全举例出来,欢迎留言交流。
注意在Qt中使用数据库添加如下:
# User self add
QT += sql
【1】SQLite Qt界面设计
界面都是一些按钮、文本框、表格等,代码中会涉及
【2】SQLite Qt数据库创建、打开、关闭、删除
查看Qt支持的数据库引擎
//数据库引擎
foreach(QString i ,QSqlDatabase::drivers())
{ui->textBrowser->append(i);
}
效果
打开数据库,并设置是数据库的相关参数
// 打开数据库
void MainWindow::on_pushButton_clicked()
{db = QSqlDatabase::addDatabase("QSQLITE","kali");db.setDatabaseName("C:\\aaa\\mysqlite.db");db.setHostName("localhost");db.setUserName("username");db.setPassword("password");ui->textBrowser_2->append("数据库的相关信息如下:");ui->textBrowser_2->append("db.port = " + QString::number(db.port()));ui->textBrowser_2->append("db.hostName = " + db.hostName());ui->textBrowser_2->append("db.password = " + db.password());ui->textBrowser_2->append("db.userName = " + db.userName());ui->textBrowser_2->append("db.driverName = " + db.driverName());ui->textBrowser_2->append("db.databaseName = " + db.databaseName());ui->textBrowser_2->append("db.connectOptions = " + db.connectOptions());ui->textBrowser_2->append("db.connectionName = " + db.connectionName());if (db.isValid()) // 数据库存在{if (db.open()){QMessageBox::information(NULL,"打开数据库","数据库"+db.databaseName()+"打开成功! 数据库引擎: "+db.driverName(),QMessageBox::Close);}else {QMessageBox::critical(NULL,"打开数据库","数据库"+db.databaseName()+"打开失败:"+db.lastError().text(),QMessageBox::Close);return;}}
}
运行效果
删除和关闭数据库
// 数据库删除
void MainWindow::on_pushButton_5_clicked()
{//db.removeDatabase("kali");// 从应用程序中删除数据库对象QSqlDatabase::removeDatabase(db.connectionName());// 删除数据库文件QFile::remove(db.databaseName());
}
// 关闭数据库
void MainWindow::on_pushButton_7_clicked()
{db.close();
}
【3】SQLite Qt表格的创建
这里使用QTableWidget组件显示表内容
在Qt中要使用查询语句,需要将数据库对象连接如下:
QSqlQuery db_query(db);
数据类型:
INTEGER
TEXT
CHAR(15)
PRIMARY KEY :主键
AUTOINCREMENT:自增
check(条件):检查
DEFAULT value:默认值
UNIQUE : 唯一约束,值不能相同
NOT NULL:不能为空
// 创建表
void MainWindow::on_pushButton_2_clicked()
{ui->tableWidget->setRowCount(1000);ui->tableWidget->setColumnCount(5);ui->tableWidget->setHorizontalHeaderLabels(QStringList()<<"id"<<"name"<<"age"<<"qq"<<"phone");ui->tableWidget->resizeRowsToContents();ui->tableWidget->resizeColumnsToContents();ui->tableWidget->setColumnWidth(0,50);ui->tableWidget->setColumnWidth(1,60);ui->tableWidget->setColumnWidth(2,50);ui->tableWidget->setColumnWidth(3,100);ui->tableWidget->setColumnWidth(4,100);ui->tableWidget->setStyleSheet("QTableView {border:2px,solid blue;}");QSqlQuery db_query(db);ui->textBrowser_2->append("\r\n查询类的相关信息如下:");ui->textBrowser_2->append("db_query.size = " + QString::number(db_query.size()));ui->textBrowser_2->append("db_query.lastQuery = " + db_query.lastQuery());ui->textBrowser_2->append("db_query.lastInsertId = " + db_query.lastInsertId().toString());ui->textBrowser_2->append("db_query.executedQuery = " + db_query.executedQuery());if (db_query.exec("CREATE TABLE student (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT NOT NULL,age INTEGER NOT NULL check(age > 0), qq CHAR(15) NOT NULL UNIQUE, phone INTEGER DEFAULT 10086)")){QMessageBox::information(NULL,"创建表","创建成功:"+db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"创建表","表创建失败:" + db_query.lastError().text(),QMessageBox::Close);}
}
效果
【4】SQLite Qt表格的插入
在Qt中插入数据,最好不要使用通配符
*
,指定列名比较好,注意插入的数据匹配数据类型。
// 表格插入
void MainWindow::on_pushButton_3_clicked()
{QSqlQuery db_query(db);if (db_query.exec(QString("INSERT INTO student (id,name,age,qq,phone) VALUES (%1,'%2',%3,'%4',%5)").arg(ui->lineEdit_id->text()).arg(ui->lineEdit_name->text()).arg(ui->lineEdit_age->text()).arg(ui->lineEdit_qq->text()).arg(ui->lineEdit_phone->text()))){QMessageBox::information(NULL,"插入表","插入成功:"+db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"插入表","插入失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}
}
效果
【5】SQLite Qt表格的查询
这里查询的时候以
ORDER BY id ASC
升序显示(从小到大),降序时使用DESC(大到小)。
// 表格查询 升序
void MainWindow::on_pushButton_4_clicked()
{QSqlQuery db_query(db);int row = 0;if (db_query.exec("SELECT id,name,age,qq,phone FROM student ORDER BY id ASC")){QMessageBox::information(NULL,"查询表","查询成功:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {int id = db_query.value(0).toInt();QString name = db_query.value(1).toString();int age = db_query.value(2).toInt();QString qq = db_query.value(3).toString();quint64 phone = db_query.value(4).toULongLong();ui->tableWidget->setItem(row,0,new QTableWidgetItem(QString::number(id)));ui->tableWidget->setItem(row,1,new QTableWidgetItem(name));ui->tableWidget->setItem(row,2,new QTableWidgetItem(QString::number(age)));ui->tableWidget->setItem(row,3,new QTableWidgetItem(qq));ui->tableWidget->setItem(row,4,new QTableWidgetItem(QString::number(phone)));row += 1; //行数动态增加}}else {QMessageBox::critical(NULL,"查询表","查询失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}
}
效果
【6】SQLite Qt表格的删除
// 删除表
void MainWindow::on_pushButton_6_clicked()
{QSqlQuery db_query(db);if (db_query.exec("DROP TABLE IF EXISTS student")){QMessageBox::information(NULL,"删除表","删除成功+命令:"+db_query.lastQuery(),QMessageBox::Close);ui->tableWidget->clearContents();}else{QMessageBox::critical(NULL,"插入表","插入失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}
}
效果
【7】SQLite Qt表格的更新
主要是更新表格的列值,可以是单个也可以是全部。
// 修改表 修改名字和年龄 以id作为条件
void MainWindow::on_pushButton_8_clicked()
{QSqlQuery db_query(db);if (ui->lineEdit_id->text().isEmpty()){QMessageBox::warning(NULL,"id为空"," id是条件,不能为空!!!",QMessageBox::Close);return;}if (!ui->lineEdit_name->text().isEmpty() && !ui->lineEdit_age->text().isEmpty()){if (db_query.exec(QString("UPDATE student SET name='%1', age=%2 WHERE id=%3").arg(ui->lineEdit_name->text()).arg(ui->lineEdit_age->text()).arg(ui->lineEdit_id->text()))){QMessageBox::information(NULL,"修改表","修改name,age成功+命令:"+db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"修改表","修改name,age失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}}else if (!ui->lineEdit_name->text().isEmpty() && ui->lineEdit_age->text().isEmpty()){if (db_query.exec(QString("UPDATE student SET name='%1' WHERE id=%2").arg(ui->lineEdit_name->text()).arg(ui->lineEdit_id->text()))){QMessageBox::information(NULL,"修改表","修改name成功+命令:"+db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"修改表","修改name失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}}else if (ui->lineEdit_name->text().isEmpty() && !ui->lineEdit_age->text().isEmpty()){if (db_query.exec(QString("UPDATE student SET age=%1 WHERE id=%2").arg(ui->lineEdit_age->text()).arg(ui->lineEdit_id->text()))){QMessageBox::information(NULL,"修改表","修改name成功+命令:"+db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"修改表","修改name失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}}else{QMessageBox::critical(NULL,"修改表格","修改name,age 失败" + db_query.lastError().text() ,QMessageBox::Close);return;}
}
效果
【8】SQLite Qt表格的结构
// 表结构
void MainWindow::on_pushButton_9_clicked()
{QSqlQuery db_query(db);QStringList tables = db.tables(); // 获取所有表格的名称for (int i = 0; i < tables.size(); i++) {ui->textBrowser_2->append(QString("表名: %1").arg(tables.at(i)));}// 循环遍历结果集并打印表结构信息ui->textBrowser_2->append(QString("\r\n表的结构如下:"));db_query.exec("SELECT SQLITE_VERSION()");while (db_query.next()) {QString version = db_query.value(0).toString();ui->textBrowser_2->append(QString("SQLITE version: %1").arg(version));}if (tables.contains("student")) {db_query.exec("PRAGMA table_info(student)");while (db_query.next()) {QString index = db_query.value(0).toString();QString name = db_query.value(1).toString();QString type = db_query.value(2).toString();qDebug() <<" index = "<<index<< " Column Name:" << name << ", Type:" << type;ui->textBrowser_2->append(QString("Column Name: %1 , Type:%2").arg(name).arg(type));}}
}
效果
【9】SQLite Qt表格的修改
// 表格新增列
void MainWindow::on_pushButton_10_clicked()
{QSqlQuery db_query(db);if (db_query.exec("ALTER TABLE student ADD age INTEGER")){QMessageBox::information(NULL,"表格新增列","新增列成功+命令:"+db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::information(NULL,"表格新增列","新增列失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}
}
效果
【10】SQLite 常用内置函数举例
1、计算表格行数
// 计算数据库表格行数
void MainWindow::on_pushButton_12_clicked()
{QSqlQuery db_query(db);if (db_query.exec("SELECT count(*) FROM student")){while (db_query.next()) {QString rowCount = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery()+"; 表格行数 = "+rowCount);}}
}
2、计算表格某列最大值
// 计算表格最大值
void MainWindow::on_pushButton_13_clicked()
{QSqlQuery db_query(db);if (db_query.exec("SELECT max(id) FROM student")){while (db_query.next()) {QString max = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; id列的最大值是 = "+max);}}
}
3、计算表格某列最小值
// 计算表格最小值
void MainWindow::on_pushButton_14_clicked()
{QSqlQuery db_query(db);if (db_query.exec("SELECT min(id) FROM student")){while (db_query.next()) {QString min = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; id列的最小值是 = "+min);}}
}
4、计算表格某列平均值
// 计算表格某列平均值
void MainWindow::on_pushButton_15_clicked()
{QSqlQuery db_query(db);if (db_query.exec("SELECT avg(age) FROM student")){while (db_query.next()) {QString avg = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; age列的平均值是 = "+avg);}}
}
5、计算表格某列总和
// 计算表格某列总和
void MainWindow::on_pushButton_16_clicked()
{QSqlQuery db_query(db);if (db_query.exec("SELECT sum(age) FROM student")){while (db_query.next()) {QString sum = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; age列的求和是 = "+sum);}}
}
6、计算一个随机数
// 计算一个随机数
void MainWindow::on_pushButton_18_clicked()
{QSqlQuery db_query(db);if (db_query.exec("SELECT random() AS random")){while (db_query.next()) {QString random = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; random = "+random);}}
}
7、计算绝对值
// 计算绝对值
void MainWindow::on_pushButton_17_clicked()
{QSqlQuery db_query(db);if (db_query.exec("SELECT abs(5),abs(-5),abs(NULL),abs('ABC')")){while (db_query.next()) {QString abs1 = db_query.value(0).toString();QString abs2 = db_query.value(1).toString();QString abs3 = QString::number(db_query.value(2).toInt());QString abs4 = QString::number(db_query.value(3).toDouble());ui->textBrowser_3->append(db_query.lastQuery() +"; abs1 = "+abs1 +", adb2 = "+abs2+", abs3 = "+abs3+" ,abs4 = "+abs4);}}
}
8、字符串转化大小写
// 字符串转化大写
void MainWindow::on_pushButton_20_clicked()
{QSqlQuery db_query(db);if (db_query.exec("SELECT upper('myname')")){while (db_query.next()) {QString upper = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; upper(myname) = "+upper);}}
}
// 字符串转化小写
void MainWindow::on_pushButton_19_clicked()
{QSqlQuery db_query(db);if (db_query.exec("SELECT lower('MYNAME')")){while (db_query.next()) {QString upper = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; lower(MYNAME) = "+upper);}}
}
9、计算字符串长度
// 计算字符串长度
void MainWindow::on_pushButton_21_clicked()
{QSqlQuery db_query(db);if (db_query.exec("SELECT name, length(name) FROM student")){while (db_query.next()) {QString name = db_query.value(0).toString();quint32 len = db_query.value(1).toUInt();ui->textBrowser_3->append(db_query.lastQuery() +"; name = "+name+" len = "+QString::number(len));}}
}
10、效果
【11】SQLite 日期函数
这里只是举例了部分,根据实际需要进行修改即可
// date 当前日期
void MainWindow::on_pushButton_24_clicked()
{QSqlQuery db_query(db);if (db_query.exec("SELECT date('now')")){while (db_query.next()) {QString date = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; date = "+date);}}if (db_query.exec("SELECT date()")){while (db_query.next()) {QString date = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; date = "+date);}}// 计算当前月份的最后一天:if (db_query.exec("SELECT date('now','start of month','+1 month','-1 day')")){while (db_query.next()) {QString date = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; date = "+date);}}// 给定 UNIX 时间戳 1092941466 的日期和时间:if (db_query.exec("SELECT datetime()")){while (db_query.next()) {QString datetime = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; datetime = "+datetime);}}if (db_query.exec("SELECT datetime(1092941466, 'unixepoch')")){while (db_query.next()) {QString datetime = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; datetime = "+datetime);}}// 计算给定 UNIX 时间戳 1092941466 相对本地时区的日期和时间:if (db_query.exec("SELECT datetime(1092941466, 'unixepoch', 'localtime')")){while (db_query.next()) {QString datetime = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; datetime = "+datetime);}}// 一周中的第几天,0-6 (0 is Sunday)if (db_query.exec("SELECT strftime('%w','now')")){while (db_query.next()) {QString strftime = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; strftime = "+strftime + "【 '%w' 一周中的第几天,0-6 (0 is Sunday)】");}}if (db_query.exec("SELECT strftime('%s', 'now')")){while (db_query.next()) {QString strftime = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; strftime = "+strftime + "【 \"%s\" 从 1970-01-01 算起的秒数】");}}if (db_query.exec("SELECT strftime('%Y-%m-%d %H', 'now')")){while (db_query.next()) {QString strftime = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; strftime = "+strftime);}}// 计算从 2004 年某一特定时刻以来的秒数:if (db_query.exec("SELECT strftime('%s','now') - strftime('%s','2004-01-01 02:34:56')")){while (db_query.next()) {QString strftime = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; strftime = "+strftime + "【 \"%s\" 从 1970-01-01 算起的秒数】");}}if (db_query.exec("SELECT strftime('%Y年%m月%d日 %H时:%M分:%S秒 周%w')")){while (db_query.next()) {QString strftime = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; strftime = "+strftime +"\r\n");}}// 计算当年 10 月的第一个星期二的日期:if (db_query.exec("SELECT date('now','start of year','+9 months','weekday 2')")){while (db_query.next()) {QString date = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; date = "+date);}}// 在 UTC 与本地时间值之间进行转换,当格式化日期时,使用 utc 或 localtime 修饰符,如下所示:if (db_query.exec("SELECT time('12:00', 'localtime')")){while (db_query.next()) {QString time = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; time = "+time);}}// 在 UTC 与本地时间值之间进行转换,当格式化日期时,使用 utc 或 localtime 修饰符,如下所示:if (db_query.exec("SELECT time('12:00', 'utc')")){while (db_query.next()) {QString time = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; time = "+time);}}
}
效果
SELECT date('now'); date = 2023-06-24
SELECT date(); date = 2023-06-24
SELECT date('now','start of month','+1 month','-1 day'); date = 2023-06-30
SELECT datetime(); datetime = 2023-06-24 01:16:14
SELECT datetime(1092941466, 'unixepoch'); datetime = 2004-08-19 18:51:06
SELECT datetime(1092941466, 'unixepoch', 'localtime'); datetime = 2004-08-20 02:51:06
SELECT strftime('%w','now'); strftime = 6【 '%w' 一周中的第几天,0-6 (0 is Sunday)】
SELECT strftime('%s', 'now'); strftime = 1687569374【 "%s" 从 1970-01-01 算起的秒数】
SELECT strftime('%Y-%m-%d %H', 'now'); strftime = 2023-06-24 01
SELECT strftime('%s','now') - strftime('%s','2004-01-01 02:34:56'); strftime = 614644878【 "%s" 从 1970-01-01 算起的秒数】
SELECT strftime('%Y年%m月%d日 %H时:%M分:%S秒 周%w'); strftime = 2023年06月24日 01时:16分:14秒 周6SELECT date('now','start of year','+9 months','weekday 2'); date = 2023-10-03
SELECT time('12:00', 'localtime'); time = 20:00:00
SELECT time('12:00', 'utc'); time = 04:00:00
【12】SQLite LIKE和GLOB子句(通配符)
LIKE
// 百分号 (%)下划线 (_) 百分号(%)代表零个、一个或多个数字或字符。下划线(_)代表一个单一的数字或字符。这些符号可以被组合使用。
void MainWindow::on_pushButton_22_clicked()
{QSqlQuery db_query(db);if (db_query.exec(QString("SELECT *FROM student WHERE name LIKE '%1'").arg(ui->lineEdit_search->text()))){while (db_query.next()) {QString id = db_query.value(0).toString();QString name = db_query.value(1).toString();QString age = db_query.value(2).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; id = "+id +" name = "+name+" age = "+age);}}else{QMessageBox::information(NULL,"查询","查询失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}
}
GLOB
// 星号(*)代表零个、一个或多个数字或字符。问号(?)代表一个单一的数字或字符。这些符号可以被组合使用。
void MainWindow::on_pushButton_25_clicked()
{QSqlQuery db_query(db);if (db_query.exec(QString("SELECT *FROM student WHERE name GLOB '%1'").arg(ui->lineEdit_search->text()))){while (db_query.next()) {QString id = db_query.value(0).toString();QString name = db_query.value(1).toString();QString age = db_query.value(2).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; id = "+id +" name = "+name+" age = "+age);}}else{QMessageBox::information(NULL,"查询","查询失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}
}
效果
LIKE
GLOB
【13】SQLite LIMIT子句 (限定行显示)
// SQLite 的 LIMIT 子句用于限制由 SELECT 语句返回的数据数量。
void MainWindow::on_pushButton_23_clicked()
{QSqlQuery db_query(db);// Limit 提取的行数 Offet 从第一行开始跳过多少行if (db_query.exec(QString("SELECT * FROM student LIMIT %1 OFFSET %2").arg(ui->lineEdit_search->text().split('/').at(0)).arg(ui->lineEdit_search->text().split('/').at(1)))){while (db_query.next()) {QString id = db_query.value(0).toString();QString name = db_query.value(1).toString();QString age = db_query.value(2).toString();QString qq = db_query.value(3).toString();QString phone = db_query.value(4).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; id = "+id +" name = "+name+" age = "+age +" qq = "+qq +" phone = "+phone);}}else{QMessageBox::information(NULL,"查询","查询失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}
}
效果
【14】SQLite 表格排序 (升序、降序)
// 表格排序
void MainWindow::on_pushButton_26_clicked()
{QSqlQuery db_query(db);if (db_query.exec(QString("SELECT * FROM student ORDER BY %1").arg(ui->lineEdit_search->text()))){while (db_query.next()) {QString id = db_query.value(0).toString();QString name = db_query.value(1).toString();QString age = db_query.value(2).toString();QString qq = db_query.value(3).toString();quint64 phone = db_query.value(4).toULongLong();ui->textBrowser_3->append(db_query.lastQuery() +"; id = "+id +" name = "+name+" age = "+age+" qq = "+qq+" phone = "+phone);}}else{QMessageBox::information(NULL,"查询","查询失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}
}
效果
降序
升序
【15】SQLite GROUP BY子句 (分组)
// 在 SELECT 语句中,GROUP BY 子句必须放在 WHERE 子句之后,放在 ORDER BY 子句之前。
void MainWindow::on_pushButton_30_clicked()
{QSqlQuery db_query(db);if (db_query.exec(QString("SELECT name, SUM(age) FROM student GROUP BY name ORDER BY name DESC"))){while (db_query.next()) {QString name = db_query.value(0).toString();QString sum = db_query.value(1).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; name = "+name +" sum = "+sum);}}else{QMessageBox::information(NULL,"查询","查询失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}
}
效果 降序显示name
【16】SQLite HAVING 子句(分组的条件)
// WHERE 子句在所选列上设置条件,而 HAVING 子句则在由 GROUP BY 子句创建的分组上设置条件。
void MainWindow::on_pushButton_29_clicked()
{QSqlQuery db_query(db);if (db_query.exec(QString("SELECT * FROM student GROUP BY name HAVING length(name) < 2"))){while (db_query.next()) {QString name = db_query.value(1).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; name = "+name);}}else{QMessageBox::information(NULL,"查询","查询失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}if (db_query.exec(QString("SELECT * FROM student GROUP BY name HAVING length(name) >= 2"))){while (db_query.next()) {QString name = db_query.value(1).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; name = "+name);}}else{QMessageBox::information(NULL,"查询","查询失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}
}
效果
【17】SQLite DISTINCT 关键字(去重)
// 在一个表中有多个重复的记录。当提取这样的记录时,DISTINCT 关键字就显得特别有意义,它只获取唯一一次记录,而不是获取重复记录。
void MainWindow::on_pushButton_33_clicked()
{QSqlQuery db_query(db);if (db_query.exec(QString("SELECT DISTINCT name FROM student"))) // 查询没有重复的name{while (db_query.next()) {QString name = db_query.value(0).toString();ui->textBrowser_3->append(db_query.lastQuery() +"; name = "+name);}}else{QMessageBox::information(NULL,"查询","查询失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}
}
效果
【18】SQLite 交叉连接(CROSS JOIN)
交叉连接往往在两个表,所以这里我们在创建一个教师表。
//=======老师表创建======
void MainWindow::on_pushButton_28_clicked()
{QSqlQuery db_query(db);if (db_query.exec("CREATE TABLE teacher (id_t INTEGER,name_t TEXT,age_t INTEGER)")){QMessageBox::information(NULL,"创建表","创建成功:"+db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"创建表","表创建失败:" + db_query.lastError().text(),QMessageBox::Close);}if (db_query.exec(QString("INSERT INTO teacher (id_t,name_t,age_t) VALUES (%1,'%2',%3)").arg(ui->lineEdit_id->text()).arg(ui->lineEdit_name->text()).arg(ui->lineEdit_age->text()))){QMessageBox::information(NULL,"插入表","插入成功:"+db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"插入表","插入失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}if (db_query.exec("SELECT id_t,name_t,age_t FROM teacher ORDER BY id_t ASC")){QMessageBox::information(NULL,"查询表","查询成功:"+db_query.lastQuery(),QMessageBox::Close);int row = 9;while (db_query.next()) {int id = db_query.value(0).toInt();QString name = db_query.value(1).toString();int age = db_query.value(2).toInt();ui->tableWidget->setItem(row,0,new QTableWidgetItem(QString::number(id)));ui->tableWidget->setItem(row,1,new QTableWidgetItem(name));ui->tableWidget->setItem(row,2,new QTableWidgetItem(QString::number(age)));row += 1; //行数动态增加}}else {QMessageBox::critical(NULL,"查询表","查询失败:" +db_query.lastError().text() ,QMessageBox::Close);return;}
}
交叉连接
// 交叉连接(CROSS JOIN)把第一个表的每一行与第二个表的每一行进行匹配。如果两个输入表分别有 x 和 y 列,则结果表有 x*y 列。
// 由于交叉连接(CROSS JOIN)有可能产生非常大的表,使用时必须谨慎,只在适当的时候使用它们。
void MainWindow::on_pushButton_31_clicked()
{QSqlQuery db_query(db);if (db_query.exec("SELECT id_t, name, age_t FROM student CROSS JOIN teacher")){QMessageBox::information(NULL,"交叉连接","交叉连接成功:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {int id = db_query.value(0).toUInt();QString name = db_query.value(1).toString();int age = db_query.value(2).toUInt();ui->textBrowser_4->append(db_query.lastQuery() +"; id_t = "+QString::number(id) +" name = " +name +" age_t = "+QString::number(age));}}else{QMessageBox::critical(NULL,"交叉连接","交叉连接失败:" + db_query.lastError().text(),QMessageBox::Close);}
}
效果
学生表
老师表
交叉连接效果
交叉连接会增大行数,学生表的名字对应表的行数,学生表一个名字对应教师表有多少行就对应多少次。
【19】SQLite 内连接(INNER JOIN)
// 内连接(INNER JOIN)根据连接谓词结合两个表(table1 和 table2)的列值来创建一个新的结果表。
void MainWindow::on_pushButton_32_clicked()
{QSqlQuery db_query(db);// 在id 相等时 连接成一个新表if (db_query.exec("SELECT id_t, name, age_t FROM student INNER JOIN teacher ON student.id = teacher.id_t")){QMessageBox::information(NULL,"内连接","内连接成功:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {int id = db_query.value(0).toUInt();QString name = db_query.value(1).toString();int age = db_query.value(2).toUInt();ui->textBrowser_4->append(db_query.lastQuery() +"; id_t = "+QString::number(id) +" name = " +name +" age_t = "+QString::number(age));}}else{QMessageBox::critical(NULL,"内连接","内连接失败:" + db_query.lastError().text(),QMessageBox::Close);}
}
效果
学生表
老师表
【20】SQLite 外连接(OUTER JOIN)
// 外连接(OUTER JOIN)是内连接(INNER JOIN)的扩展。虽然 SQL 标准定义了三种类型的外连接:LEFT、RIGHT、FULL,但 SQLite 只支持 左外连接(LEFT OUTER JOIN)。
void MainWindow::on_pushButton_34_clicked()
{QSqlQuery db_query(db);if (db_query.exec("SELECT id_t, name, age_t FROM student LEFT OUTER JOIN teacher ON student.id = teacher.id_t")){QMessageBox::information(NULL,"外连接","外连接成功:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {int id_t = db_query.value(0).toUInt();QString name = db_query.value(1).toString();int age = db_query.value(2).toUInt();ui->textBrowser_4->append(db_query.lastQuery() +"; id_t = "+QString::number(id_t) +" name = " +name +" age_t = "+QString::number(age));}}else{QMessageBox::critical(NULL,"外连接","外连接失败:" + db_query.lastError().text(),QMessageBox::Close);}
}
效果
好像只有第一个有效
【21】UNION 子句 (查询行不重复、重复)
SQLite的 UNION 子句/运算符用于合并两个或多个 SELECT 语句的结果,不返回任何重复的行。
为了使用 UNION,每个 SELECT 被选择的列数必须是相同的,相同数目的列表达式,相同的数据类型,并确保它们有相同的顺序,但它们不必具有相同的长度。
// SQLite的 UNION 子句/运算符用于合并两个或多个 SELECT 语句的结果,不返回任何重复的行。
// UNION ALL 运算符用于结合两个 SELECT 语句的结果,包括重复行。
void MainWindow::on_pushButton_35_clicked()
{QSqlQuery db_query(db);if (db_query.exec("SELECT id_t, name, age_t FROM student INNER JOIN teacher \ON student.id = teacher.id_t \UNION \SELECT id_t, name, age_t FROM student LEFT OUTER JOIN teacher \ON student.id = teacher.id_t")){QMessageBox::information(NULL,"UNION 子句","UNION 子句成功:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {int id_t = db_query.value(0).toUInt();QString name = db_query.value(1).toString();int age = db_query.value(2).toUInt();ui->textBrowser_4->append(db_query.lastQuery() +"; id_t = "+QString::number(id_t) +" name = " +name +" age_t = "+QString::number(age));}}else{QMessageBox::critical(NULL,"UNION 子句","UNION 子句失败:" + db_query.lastError().text(),QMessageBox::Close);}if (db_query.exec("SELECT id_t, name, age_t FROM student INNER JOIN teacher \ON student.id = teacher.id_t \UNION ALL\SELECT id_t, name, age_t FROM student LEFT OUTER JOIN teacher \ON student.id = teacher.id_t")){QMessageBox::information(NULL,"UNION 子句","UNION 子句成功:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {int id_t = db_query.value(0).toUInt();QString name = db_query.value(1).toString();int age = db_query.value(2).toUInt();ui->textBrowser_4->append(db_query.lastQuery() +"; id_t = "+QString::number(id_t) +" name = " +name +" age_t = "+QString::number(age));}}else{QMessageBox::critical(NULL,"UNION 子句","UNION 子句失败:" + db_query.lastError().text(),QMessageBox::Close);}
}
效果
学生表
老师表
SELECT id_t, name, age_t FROM student INNER JOIN teacher ON student.id = teacher.id_t UNION
SELECT id_t, name, age_t FROM student LEFT OUTER JOIN teacher ON student.id = teacher.id_t;
`id_t = 0 name = 4 age_t = 0`
SELECT id_t, name, age_t FROM student INNER JOIN teacher ON student.id = teacher.id_t UNION
SELECT id_t, name, age_t FROM student LEFT OUTER JOIN teacher ON student.id = teacher.id_t;
`id_t = 0 name = 小红花给你 age_t = 0`
SELECT id_t, name, age_t FROM student INNER JOIN teacher ON student.id = teacher.id_t UNION
SELECT id_t, name, age_t FROM student LEFT OUTER JOIN teacher ON student.id = teacher.id_t;
`id_t = 0 name = 李不白 age_t = 0`
SELECT id_t, name, age_t FROM student INNER JOIN teacher ON student.id = teacher.id_t UNION
SELECT id_t, name, age_t FROM student LEFT OUTER JOIN teacher ON student.id = teacher.id_t;
`id_t = 1 name = 李不白 age_t = 23`
SELECT id_t, name, age_t FROM student INNER JOIN teacher ON student.id = teacher.id_t UNION
SELECT id_t, name, age_t FROM student LEFT OUTER JOIN teacher ON student.id = teacher.id_t;
`id_t = 2 name = 3 age_t = 22`SELECT id_t, name, age_t FROM student INNER JOIN teacher ON student.id = teacher.id_t UNION ALL SELECT id_t, name, age_t FROM student LEFT OUTER JOIN teacher ON student.id = teacher.id_t;
`id_t = 1 name = 李不白 age_t = 23`
SELECT id_t, name, age_t FROM student INNER JOIN teacher ON student.id = teacher.id_t UNION ALL SELECT id_t, name, age_t FROM student LEFT OUTER JOIN teacher ON student.id = teacher.id_t;
`id_t = 2 name = 3 age_t = 22`
SELECT id_t, name, age_t FROM student INNER JOIN teacher ON student.id = teacher.id_t UNION ALL SELECT id_t, name, age_t FROM student LEFT OUTER JOIN teacher ON student.id = teacher.id_t;
`id_t = 1 name = 李不白 age_t = 23`
SELECT id_t, name, age_t FROM student INNER JOIN teacher ON student.id = teacher.id_t UNION ALL SELECT id_t, name, age_t FROM student LEFT OUTER JOIN teacher ON student.id = teacher.id_t;
`id_t = 2 name = 3 age_t = 22`
SELECT id_t, name, age_t FROM student INNER JOIN teacher ON student.id = teacher.id_t UNION ALL SELECT id_t, name, age_t FROM student LEFT OUTER JOIN teacher ON student.id = teacher.id_t;
`id_t = 0 name = 4 age_t = 0`
SELECT id_t, name, age_t FROM student INNER JOIN teacher ON student.id = teacher.id_t UNION ALL SELECT id_t, name, age_t FROM student LEFT OUTER JOIN teacher ON student.id = teacher.id_t;
`id_t = 0 name = 小红花给你 age_t = 0`
SELECT id_t, name, age_t FROM student INNER JOIN teacher ON student.id = teacher.id_t UNION ALL SELECT id_t, name, age_t FROM student LEFT OUTER JOIN teacher ON student.id = teacher.id_t;
`id_t = 0 name = 李不白 age_t = 0`
【22】SQLite 触发器(Trigger)
比作:中断,信号
SQLite 的触发器是数据库的回调函数,它会在指定的数据库事件发生时自动执行/调用。
以下是关于SQLite的触发器的要点:
SQLite 触发器(Trigger)是数据库的回调函数,它会在指定的数据库事件发生时自动执行/调用。以下是关于 SQLite 的触发器(Trigger)的要点:
SQLite 的触发器(Trigger)可以指定在特定的数据库表发生 DELETE、INSERT 或 UPDATE 时触发,或在一个或多个指定表的列发生更新时触发。
SQLite 只支持 FOR EACH ROW 触发器(Trigger),没有 FOR EACH STATEMENT 触发器(Trigger)。因此,明确指定 FOR EACH ROW 是可选的。
WHEN 子句和触发器(Trigger)动作可能访问使用表单 NEW.column-name 和 OLD.column-name 的引用插入、删除或更新的行元素,其中 column-name 是从与触发器关联的表的列的名称。
如果提供 WHEN 子句,则只针对 WHEN 子句为真的指定行执行 SQL 语句。如果没有提供 WHEN 子句,则针对所有行执行 SQL 语句。
BEFORE 或 AFTER 关键字决定何时执行触发器动作,决定是在关联行的插入、修改或删除之前或者之后执行触发器动作。
当触发器相关联的表删除时,自动删除触发器(Trigger)。
要修改的表必须存在于同一数据库中,作为触发器被附加的表或视图,且必须只使用 tablename,而不是 database.tablename。
一个特殊的 SQL 函数 RAISE() 可用于触发器程序内抛出异常。
// SQLite 触发器(Trigger)是数据库的回调函数,它会在指定的数据库事件发生时自动执行/调用。
void MainWindow::on_pushButton_36_clicked()
{QSqlQuery db_query(db);if (db_query.exec("CREATE TABLE AUDIT(EMP_ID INTEGER ,ENTRY_DATE TEXT)")){QMessageBox::information(NULL,"Trigger","Trigger成功:"+db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"Trigger","Trigger失败:" + db_query.lastError().text(),QMessageBox::Close);}if (db_query.exec("CREATE TRIGGER audit_log AFTER INSERT\ON student\BEGIN\INSERT INTO AUDIT(EMP_ID, ENTRY_DATE) VALUES (new.ID, datetime('now'));\END")){QMessageBox::information(NULL,"Trigger","Trigger成功:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {int id_t = db_query.value(0).toUInt();QString name = db_query.value(1).toString();int age = db_query.value(2).toUInt();ui->textBrowser_4->append(db_query.lastQuery() +"; id_t = "+QString::number(id_t) +" name = " +name +" age_t = "+QString::number(age));}}else{QMessageBox::critical(NULL,"Trigger","Trigger失败:" + db_query.lastError().text(),QMessageBox::Close);}if (db_query.exec("SELECT EMP_ID, ENTRY_DATE FROM AUDIT")){QMessageBox::information(NULL,"Trigger","Trigger成功:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {int id_t = db_query.value(0).toUInt();QString name = db_query.value(1).toString();ui->textBrowser_4->append(db_query.lastQuery() +"; EMP_ID = "+QString::number(id_t) +" ENTRY_DATE = " +name);}}else{QMessageBox::critical(NULL,"Trigger","Trigger失败:" + db_query.lastError().text(),QMessageBox::Close);}
}
效果,在学生表插入时,会自动保存触发表
插入id = 2时
【23】SQLite 视图(View)
视图(View)只不过是通过相关的名称存储在数据库中的一个 SQLite 语句。视图(View)实际上是一个以预定义的 SQLite 查询形式存在的表的组合。
视图(View)可以包含一个表的所有行或从一个或多个表选定行。视图(View)可以从一个或多个表创建,这取决于要创建视图的 SQLite 查询。、
视图(View)是一种虚表,允许用户实现以下几点:
用户或用户组查找结构数据的方式更自然或直观。
限制数据访问,用户只能看到有限的数据,而不是完整的表。
汇总各种表中的数据,用于生成报告。
SQLite 视图是只读的,因此可能无法在视图上执行 DELETE、INSERT 或 UPDATE 语句。但是可以在视图上创建一个触发器,当尝试 DELETE、INSERT 或 UPDATE 视图时触发,需要做的动作在触发器内容中定义。
// 视图(View)只不过是通过相关的名称存储在数据库中的一个 SQLite 语句。视图(View)实际上是一个以预定义的 SQLite 查询形式存在的表的组合。
void MainWindow::on_pushButton_37_clicked()
{QSqlQuery db_query(db);if (db_query.exec("CREATE VIEW student_VIEW AS SELECT id, name, age FROM student")){QMessageBox::information(NULL,"视图(View)","视图(View)成功:"+db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"视图(View)","视图(View)失败:" + db_query.lastError().text(),QMessageBox::Close);}if (db_query.exec("SELECT * FROM student_VIEW")){QMessageBox::information(NULL,"视图(View)","视图(View)成功:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {int id = db_query.value(0).toUInt();QString name = db_query.value(1).toString();int age = db_query.value(2).toUInt();ui->textBrowser_4->append(db_query.lastQuery() +"; id = "+QString::number(id) +" name = " +name +" age = "+QString::number(age));}}else{QMessageBox::critical(NULL,"视图(View)","视图(View)失败:" + db_query.lastError().text(),QMessageBox::Close);}if (db_query.exec("DROP VIEW student_VIEW")){QMessageBox::information(NULL,"视图(View)","视图(View)成功:"+db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"视图(View)","视图(View)失败:" + db_query.lastError().text(),QMessageBox::Close);}
}
效果
【24】SQLite 事务(Transaction)
事务(Transaction)是一个对数据库执行工作单元。事务(Transaction)是以逻辑顺序完成的工作单位或序列,可以是由用户手动操作完成,也可以是由某种数据库程序自动完成。
事务(Transaction)是指一个或多个更改数据库的扩展。例如,如果您正在创建一个记录或者更新一个记录或者从表中删除一个记录,那么您正在该表上执行事务。重要的是要控制事务以确保数据的完整性和处理数据库错误。
实际上,您可以把许多的 SQLite 查询联合成一组,把所有这些放在一起作为事务的一部分进行执行。
事务的属性 事务(Transaction)具有以下四个标准属性,通常根据首字母缩写为 ACID:
原子性(Atomicity):确保工作单位内的所有操作都成功完成,否则,事务会在出现故障时终止,之前的操作也会回滚到以前的状态。
一致性(Consistency):确保数据库在成功提交的事务上正确地改变状态。
隔离性(Isolation):使事务操作相互独立和透明。
持久性(Durability):确保已提交事务的结果或效果在系统发生故障的情况下仍然存在。
事务控制
使用下面的命令来控制事务:
BEGIN TRANSACTION:开始事务处理。
COMMIT:保存更改,或者可以使用 ENDTRANSACTION 命令。
ROLLBACK:回滚所做的更改。
事务控制命令只与 DML 命令 INSERT、UPDATE 和DELETE 一起使用。他们不能在创建表或删除表时使用,因为这些操作在数据库中是自动提交的。
// 事务(Transaction)是一个对数据库执行工作单元。事务(Transaction)是以逻辑顺序完成的工作单位或序列,可以是由用户手动操作完成,也可以是由某种数据库程序自动完成。
void MainWindow::on_pushButton_38_clicked()
{QSqlQuery db_query(db);if (db_query.exec("BEGIN")){ // 开始事务QMessageBox::information(NULL,"事务(Transaction)","事务(Transaction)成功:" + db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"事务(Transaction)","事务(Transaction)失败:" + db_query.lastError().text(),QMessageBox::Close);}if (db_query.exec(QString("DELETE FROM student WHERE age = %1").arg(ui->lineEdit->text().toUInt()))){QMessageBox::information(NULL,"事务(Transaction)","事务(Transaction)成功:" + db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"事务(Transaction)","事务(Transaction)失败:" + db_query.lastError().text(),QMessageBox::Close);}if (db_query.exec("SELECT age FROM student")){QMessageBox::information(NULL,"语句","命令:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {int age = db_query.value(0).toUInt();ui->textBrowser_4->append(db_query.lastQuery() +"; age = "+QString::number(age));}}if (db_query.exec("ROLLBACK")){ // 撤销以上操作QMessageBox::information(NULL,"事务(Transaction)","事务(Transaction)成功:" + db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"事务(Transaction)","事务(Transaction)失败:" + db_query.lastError().text(),QMessageBox::Close);}//==========================================保存更改=====================================if (db_query.exec("BEGIN")){ // 开始事务QMessageBox::information(NULL,"事务(Transaction)","事务(Transaction)成功:" + db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"事务(Transaction)","事务(Transaction)失败:" + db_query.lastError().text(),QMessageBox::Close);}if (db_query.exec(QString("DELETE FROM student WHERE age = %1").arg(ui->lineEdit->text().toUInt()))){QMessageBox::information(NULL,"事务(Transaction)","事务(Transaction)成功:" + db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"事务(Transaction)","事务(Transaction)失败:" + db_query.lastError().text(),QMessageBox::Close);}if (db_query.exec("COMMIT")){ // 提交事务QMessageBox::information(NULL,"事务(Transaction)","事务(Transaction)成功:"+db_query.lastQuery(),QMessageBox::Close);}else{QMessageBox::critical(NULL,"事务(Transaction)","事务(Transaction)失败:" + db_query.lastError().text(),QMessageBox::Close);}if (db_query.exec("SELECT age FROM student")){QMessageBox::information(NULL,"语句","命令:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {int age = db_query.value(0).toUInt();ui->textBrowser_4->append(db_query.lastQuery() +"; age = "+QString::number(age));}}
}
效果
22被删除
【25】SQLite 子查询或内部查询或嵌套查询
子查询或内部查询或嵌套查询是在另一个 SQLite 查询内嵌入在 WHERE 子句中的查询。
使用子查询返回的数据将被用在主查询中作为条件,以进一步限制要检索的数据。
子查询可以与 SELECT、INSERT、UPDATE 和 DELETE 语句一起使用,可伴随着使用运算符如 =、<、>、>=、<=、IN、BETWEEN 等。
以下是子查询必须遵循的几个规则:
子查询必须用括号括起来。
子查询在 SELECT 子句中只能有一个列,除非在主查询中有多列,与子查询的所选列进行比较。
ORDER BY 不能用在子查询中,虽然主查询可以使用 ORDER BY。可以在子查询中使用 GROUP BY,功能与 ORDER BY 相同。
子查询返回多于一行,只能与多值运算符一起使用,如 IN 运算符。
BETWEEN 运算符不能与子查询一起使用,但是,BETWEEN 可在子查询内使用。
// 子查询或内部查询或嵌套查询是在另一个 SQLite 查询内嵌入在 WHERE 子句中的查询。
void MainWindow::on_pushButton_40_clicked()
{QSqlQuery db_query(db);if (db_query.exec("SELECT *FROM student WHERE id IN (SELECT id FROM student WHERE id > 1) ")){QMessageBox::information(NULL,"子查询","子查询成功:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {int id = db_query.value(0).toUInt();QString name = db_query.value(1).toString();int age = db_query.value(2).toUInt();ui->textBrowser_4->append(db_query.lastQuery() +"; id = "+QString::number(id) +" name = " +name +" age = "+QString::number(age));}}else{QMessageBox::critical(NULL,"子查询","子查询失败:" + db_query.lastError().text(),QMessageBox::Close);}if (db_query.exec("UPDATE student SET id = id * 5 WHERE age IN (SELECT age FROM student WHERE age >= 1 )")){QMessageBox::information(NULL,"子查询","子查询成功:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {int id = db_query.value(0).toUInt();QString name = db_query.value(1).toString();int age = db_query.value(2).toUInt();ui->textBrowser_4->append(db_query.lastQuery() +"; id = "+QString::number(id) +" name = " +name +" age = "+QString::number(age));}}else{QMessageBox::critical(NULL,"子查询","子查询失败:" + db_query.lastError().text(),QMessageBox::Close);}if (db_query.exec(" DELETE FROM student WHERE age IN (SELECT age FROM student WHERE age > 60 )")){QMessageBox::information(NULL,"子查询","子查询成功:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {int id = db_query.value(0).toUInt();QString name = db_query.value(1).toString();int age = db_query.value(2).toUInt();ui->textBrowser_4->append(db_query.lastQuery() +"; id = "+QString::number(id) +" name = " +name +" age = "+QString::number(age));}}else{QMessageBox::critical(NULL,"子查询","子查询失败:" + db_query.lastError().text(),QMessageBox::Close);}
}
效果
【26】EXPLAIN (注释)
在 SQLite 语句之前,可以使用 “EXPLAIN” 关键字或 “EXPLAIN QUERY PLAN” 短语,用于描述表的细节。
如果省略了 EXPLAIN 关键字或短语,任何的修改都会引起 SQLite 语句的查询行为,并返回有关 SQLite 语句如何操作的信息。
来自 EXPLAIN 和 EXPLAIN QUERY PLAN 的输出只用于交互式分析和排除故障。
输出格式的细节可能会随着 SQLite 版本的不同而有所变化。
应用程序不应该使用 EXPLAIN 或 EXPLAIN QUERY PLAN,因为其确切的行为是可变的且只有部分会被记录。
// 来自 EXPLAIN 和 EXPLAIN QUERY PLAN 的输出只用于交互式分析和排除故障。
void MainWindow::on_pushButton_41_clicked()
{QSqlQuery db_query(db);if (db_query.exec("EXPLAIN SELECT * FROM student WHERE age >= 1")){QMessageBox::information(NULL,"子查询","子查询成功:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {QString detail = db_query.value(0).toString(); // 获取查询计划的详细信息ui->textBrowser_4->append(db_query.lastQuery() +"; detail = "+detail);}}else{QMessageBox::critical(NULL,"子查询","子查询失败:" + db_query.lastError().text(),QMessageBox::Close);}ui->textBrowser_4->append("\n");if (db_query.exec("EXPLAIN QUERY PLAN SELECT * FROM student WHERE age >= 1")){QMessageBox::information(NULL,"子查询","子查询成功:"+db_query.lastQuery(),QMessageBox::Close);while (db_query.next()) {QString detail = db_query.value(0).toString(); // 获取查询计划的详细信息ui->textBrowser_4->append(db_query.lastQuery() +"; detail = "+detail);}}else{QMessageBox::critical(NULL,"子查询","子查询失败:" + db_query.lastError().text(),QMessageBox::Close);}
}
效果
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 0
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 1
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 2
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 3
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 4
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 5
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 6
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 7
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 8
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 9
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 10
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 11
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 12
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 13
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 14
EXPLAIN SELECT * FROM student WHERE age >= 1; detail = 15EXPLAIN QUERY PLAN SELECT * FROM student WHERE age >= 1; detail = 2