SQL进阶——C++与SQL进阶实践

news2024/12/26 22:39:24

在C++开发中,SQL数据库的操作是开发者常见的任务之一。虽然前面我们已经介绍了如何在C++中通过数据库连接执行基本的SQL查询,但在实际项目中,我们通常需要更加复杂和高效的数据库操作。存储过程与函数的调用复杂SQL查询的编写、以及动态构造SQL语句与参数绑定是进阶数据库操作中的重要内容。

本章将深入探讨如何在C++中调用存储过程与函数,如何编写复杂的SQL查询,以及如何动态构造SQL语句与进行参数绑定。通过对最新技术、最佳实践和优化方法的详细讨论,你将能够在C++项目中灵活运用这些技术,提高应用的数据库访问效率、可维护性和安全性。


1. 使用C++调用存储过程与函数

1.1 存储过程与函数的概述

在SQL中,存储过程和函数是预定义的SQL代码块,可以被应用程序调用来执行特定的任务。它们可以简化数据库操作,减少重复的SQL代码,同时提高数据库查询的效率。

  • 存储过程:是封装了多个SQL语句的代码块,可以包含逻辑控制、条件判断等。
  • 存储函数:与存储过程类似,但它有返回值,可以在查询中作为表达式使用。

在C++中调用存储过程或函数通常依赖于数据库提供的API(如MySQL Connector/C++、SQLite、PostgreSQL等)。

1.2 使用C++调用存储过程

为了在C++中调用MySQL等数据库的存储过程,我们需要使用数据库的API来连接数据库并执行存储过程。在这里,我们以MySQL Connector/C++为例。

基本步骤

  1. 建立数据库连接:首先,建立数据库连接。
  2. 创建存储过程:在数据库中定义存储过程。
  3. 调用存储过程:使用CALL语句调用存储过程。

示例:

假设我们已经在MySQL数据库中定义了一个存储过程,计算员工的平均薪资。

DELIMITER //
CREATE PROCEDURE get_avg_salary(IN department_id INT, OUT avg_salary DECIMAL)
BEGIN
    SELECT AVG(salary) INTO avg_salary
    FROM employees
    WHERE department_id = department_id;
END //
DELIMITER ;

在C++中调用该存储过程:

#include <mysql_driver.h>
#include <mysql_connection.h>
#include <cppconn/prepared_statement.h>
#include <cppconn/callable_statement.h>
#include <iostream>

int main() {
    sql::mysql::MySQL_Driver *driver;
    sql::Connection *con;

    // Initialize driver and connect to database
    driver = sql::mysql::get_mysql_driver_instance();
    con = driver->connect("tcp://127.0.0.1:3306", "user", "password");

    // Select database
    con->setSchema("company_db");

    // Prepare and execute stored procedure
    sql::CallableStatement *stmt = con->prepareCall("{CALL get_avg_salary(?, ?)}");

    int department_id = 10;
    sql::SQLString avg_salary;
    
    // Bind parameters
    stmt->setInt(1, department_id);
    stmt->registerOutParameter(2, sql::DataType::VARCHAR);
    
    // Execute the statement
    stmt->execute();

    // Fetch the result
    avg_salary = stmt->getString(2);
    std::cout << "Average salary for department " << department_id << ": " << avg_salary << std::endl;

    delete stmt;
    delete con;
    return 0;
}

说明

  • prepareCall("{CALL procedure_name(?, ?)}") 用于准备存储过程的调用。
  • setInt(1, department_id) 用于绑定输入参数。
  • registerOutParameter(2, sql::DataType::VARCHAR) 用于注册输出参数的类型。
  • execute() 执行存储过程。
  • 使用getString(2)获取输出参数的值。
1.3 使用C++调用SQL函数

SQL函数通常用于计算某些值并返回结果。在C++中调用SQL函数与调用存储过程类似,但需要注意的是,函数返回一个值,而存储过程则不一定返回值。

示例:

假设我们有一个SQL函数get_employee_salary,用于获取某个员工的薪水。

DELIMITER //
CREATE FUNCTION get_employee_salary(employee_id INT) 
RETURNS DECIMAL
BEGIN
    DECLARE salary DECIMAL;
    SELECT salary INTO salary
    FROM employees
    WHERE id = employee_id;
    RETURN salary;
END //
DELIMITER ;

在C++中调用该函数:

#include <mysql_driver.h>
#include <mysql_connection.h>
#include <cppconn/prepared_statement.h>
#include <iostream>

int main() {
    sql::mysql::MySQL_Driver *driver;
    sql::Connection *con;

    // Initialize driver and connect to database
    driver = sql::mysql::get_mysql_driver_instance();
    con = driver->connect("tcp://127.0.0.1:3306", "user", "password");

    // Select database
    con->setSchema("company_db");

    // Prepare the SQL query
    sql::PreparedStatement *stmt = con->prepareStatement("SELECT get_employee_salary(?)");

    int employee_id = 101;

    // Bind input parameter
    stmt->setInt(1, employee_id);

    // Execute the statement and fetch the result
    sql::ResultSet *res = stmt->executeQuery();
    while (res->next()) {
        std::cout << "Employee Salary: " << res->getDouble(1) << std::endl;
    }

    delete res;
    delete stmt;
    delete con;
    return 0;
}

说明

  • 使用prepareStatement来准备SQL查询。
  • executeQuery执行查询并返回结果。

2. 编写复杂的SQL查询

2.1 复杂SQL查询的设计

在数据库应用中,常常需要编写复杂的查询来满足多种数据需求。例如,查询可能需要多个表的联合、嵌套的子查询、复杂的聚合函数等。编写复杂SQL查询时,需要注意查询性能,避免冗余的计算。

常见的复杂SQL查询包括:

  • 多表联合查询(使用JOIN)。
  • 带有聚合函数的查询(使用GROUP BYHAVING等)。
  • 嵌套查询(子查询与视图结合)。
  • 条件查询(结合CASE语句进行条件逻辑)。
2.2 多表联合查询

例如,查询每个部门的员工姓名及其所属部门名称:

SELECT e.name AS employee_name, d.name AS department_name
FROM employees e
JOIN departments d ON e.department_id = d.id;
2.3 聚合函数与分组

如果要查询每个部门的平均薪资,可以使用GROUP BY和聚合函数AVG()

SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id;
2.4 子查询

可以使用子查询来查询某些特定的数据。例如,查询所有薪资高于公司平均薪资的员工:

SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
2.5 使用WITH子句

在复杂查询中,我们可以使用WITH子句来定义临时的视图或数据集,便于在后续查询中使用:

WITH DepartmentSalaries AS (
    SELECT department_id, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department_id
)
SELECT e.name, d.avg_salary
FROM employees e
JOIN DepartmentSalaries d ON e.department_id = d.department_id
WHERE e.salary > d.avg_salary;

3. 动态构造SQL语句与参数绑定

3.1 动态构造SQL语句

在一些应用场景下,我们可能无法在编译时确定查询的具体条件或表结构,而是根据用户输入或程序逻辑来动态构建SQL查询。动态构造SQL语句需要谨慎处理,以避免SQL注入等安全风险。

示例:

假设我们需要根据用户输入的字段动态构建查询语句来检索员工数据:

#include <mysql_driver.h>
#include <mysql_connection.h>
#include <cppconn/prepared_statement.h>
#include <iostream>

int main() {
    sql::mysql::MySQL_Driver *driver;
    sql::Connection *con;

    // Initialize driver and connect to database
    driver = sql::mysql::get_mysql_driver_instance();
    con = driver->connect("tcp://127.0.0.1:3306", "user", "password");

    // Select database
    con->setSchema("company_db");

    // Dynamic query construction
    std::string column = "salary";
    std::string condition = "salary > 50000";

    std::string query = "SELECT name, " + column + " FROM employees WHERE " + condition;

    // Prepare and execute the query
    sql::PreparedStatement *stmt = con->prepareStatement(query);
    sql::ResultSet *res = stmt->executeQuery();

    while (res->next()) {
        std::cout << res->getString("name") << ": " << res->getDouble(column) << std::endl;
    }

    delete res;
    delete stmt;
    delete con;
    return 0;
}

注意事项

  • 动态构造SQL时要确保避免SQL注入,避免直接将用户输入嵌入SQL查询字符串中。
  • 使用参数化查询或准备语句来防止SQL注入。
3.2 参数绑定与执行

为了提高安全性和执行效率,我们应始终使用参数绑定而非直接拼接SQL查询。MySQL Connector提供了PreparedStatement对象来绑定参数。

示例:

std::string query = "SELECT name FROM employees WHERE department_id = ?";
sql::PreparedStatement *stmt = con->prepareStatement(query);
stmt->setInt(1, 10);  // Bind the department_id parameter
sql::ResultSet *res = stmt->executeQuery();

小结

通过本章的学习,你已经掌握了在C++中调用存储过程与函数、编写复杂SQL查询以及动态构造SQL语句的技巧。在实际项目中,灵活运用这些技术不仅能提高代码的可维护性和效率,也能帮助你在数据库操作中处理更加复杂的需求。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

论文概览 |《Urban Analytics and City Science》2023.05 Vol.50 Issue.4

本次给大家整理的是《Environment and Planning B: Urban Analytics and City Science》杂志2023年5月第50卷第4期的论文的题目和摘要&#xff0c;一共包括19篇SCI论文&#xff01; 论文1 Data analytics and sustainable urban development in global cities 全球城市的数据…

HarmonyOS4+NEXT星河版入门与项目实战(24)------Stage模型

文章目录 1、概念2、配置文件1、全局配置文件2、模块配置文件3、UIAbility生命周期1、图文归纳2、生命周期方法入口4、页面生命周期1、图文描述1、概念 2、配置文件 1、全局配置文件 2、模块配置文件 统一修改配置文件技巧:点击任意json 文件,选择 Open editor ,在显示的列表…

kubernetes——part3-2 集群声明式文件YAML

一、YAML介绍 YAML 的意思是&#xff1a;仍是一种标记语言&#xff0c;但为了强调这种语言以数据做为中心&#xff0c;而不是以标记语言为重点。是一个可读性高&#xff0c;用来表达数据序列的格式。 二、基本语法 1.低版本缩进时不允许使用Tab键&#xff0c;只允许使用空格…

告别 Kafka,拥抱 Databend:构建高效低成本的用户行为分析体系

用户行为数据埋点指标是数据仓库中不可或缺的重要数据源之一&#xff0c;同时也是企业最宝贵的资产之一。通常情况下&#xff0c;用户行为数据分析包含两大数据源&#xff1a;用户行为分析日志和上游关系型数据库&#xff08;如 MySQL&#xff09;。基于这些数据&#xff0c;企…

产出一篇论文的各个步骤

产出一篇论文的各个步骤 建议–实用 如何看论文&#xff1a; &#xff08;前提&#xff1a;优秀论文&#xff0c;如顶会论文/杂志&#xff0c;了解顶会是那些&#xff0c;召开时间是什么时候&#xff09; 创新点 记录下来说过的别的文章/方法的缺陷 – 看文章就是看优点/指出…

AtomicIntegerFieldUpdater能否降低内存

1. 代码如下&#xff1a; import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger;public class AtomicIntegerTest {final AtomicInteger startPosition new AtomicInteger(0);final AtomicInteger wrotePosition new Atom…

ClickHouse数据迁移(远程)

一、背景 公司最近买了新的服务器&#xff0c;旧的服务器上面安装了ClickHouse22.2.2.1&#xff0c;新的服务器上面安装了ClickHouse24.9.2.42&#xff0c;两个版本之间要做历史数据迁移 旧服务器&#xff1a;80(IP最后一段&#xff0c;以下代称)&#xff0c;ClickHouse版本&am…

Flutter:页面滚动

1、单一页面&#xff0c;没有列表没分页的&#xff0c;推荐使用&#xff1a;SingleChildScrollView() return Scaffold(backgroundColor: Color(0xffF6F6F6),body: SingleChildScrollView(child: _buildView()) );2、列表没分页&#xff0c;如购物车页&#xff0c;每个item之间…

Artec Leo:航海设备维护的便携式3D扫描利器【沪敖3D】

挑战&#xff1a;海军服务提供商USP Maritime需要CAD数据来执行维修和改装任务&#xff0c;特别是在偏远地区的任务&#xff0c;以及原始设计丢失的情况下。 解决方案&#xff1a;Artec Leo, Artec Studio, Autodesk Inventor 效果&#xff1a;高精度船舶组件和船坞机械模型&…

复杂网络(三)

一、几种常见的中心性指标 1.1 度中心性 度中心性分为节点度中心性和网络度中心性。前者指的是节点在其与之直接相连的邻居节点当中的中心程度&#xff0c;二后者则侧重节点在整个网络的中心程度&#xff0c;表征的是整个网络的集中或集权程度&#xff0c;即整个网络围绕一个…

蓝桥杯嵌入式入门指南-UART【7】

在all.c定义缓存变量 char uart_tx[50];//uart缓冲区 char uart_rx[50];//uart缓冲区USRT发送(使用strlen时需要在all.h添加string.h) sprintf(uart_tx ," PB15:%.4f V \r\n ",adc_data_PB15);HAL_UART_Transmit(&huart1,(uint8_t *)uart_tx,strlen(uart_tx)…

docker 在ubuntu系统安装,以及常用命令,配置阿里云镜像仓库,搭建本地仓库等

1.docker安装 1.1 先检查ubuntu系统有没有安装过docker 使用 docker -v 命令 如果有请先卸载旧版本&#xff0c;如果没有直接安装命令如下&#xff1a; 1.1.0 首先&#xff0c;确保你的系统包是最新的&#xff1a; 如果是root 权限下面命令的sudo可以去掉 sudo apt-get upda…

IOS ARKit进行图像识别

先讲一下基础控涧&#xff0c;资源的话可以留言&#xff0c;抽空我把它传到GitHub上&#xff0c;这里没写收积分&#xff0c;竟然充值才能下载&#xff0c;我下载也要充值&#xff0c;牛&#xff01; ARSCNView 可以理解画布或者场景 1 配置 ARWorldTrackingConfiguration AR追…

CSS笔记(二)类名复用

这里我通过两张不同位置的卡片来实现效果 代码 <!DOCTYPE html> <html><head><style>/*设置画布*/body{/* 方便排列与对齐*/display: flex; /*画布布满整个窗口*/height: 100vh;/*水平居中*/justify-content: center;/*垂直居中*/align-items: cente…

远程协助软件Todesk免费版有什么限制

大名鼎鼎的远程todesk也开始出限制了&#xff0c;国内远程协助一直是向日葵一家独大&#xff0c;todesk起来以后慢慢占领了部分市场&#xff0c;随用户越来越多&#xff0c;其服务器也开始不堪重负了&#xff0c;于2024年的6月发了公告&#xff0c;出告了限制发表的措施具体如下…

【力扣热题100】[Java版] 刷题笔记-3. 无重复字符的最长子串

题目:3. 无重复字符的最长子串 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 解题思路 根据题目&#xff0c;只需要返回无重复字符串的最长子串的长度&#xff0c;所以我们不需要知道知道字符串内容是什么&#xff0c;在整个字符串 s 中&…

【03】Selenium+Python 八种定位元素方法

操作元素&#xff0c;需要先查找定位到对应的元素。 查找单个元素&#xff1a;driver.find_element() 返回是一个web element 对象 查找多个元素&#xff1a;driver.find_elements() 返回是一个list对象 By 是 Selenium 中一个非常重要的类&#xff0c;用于定位网页元素。 使…

【文献阅读】自动化构音障碍严重程度分类:声学特征与深度学习技术的研究

自动化构音障碍严重程度分类:声学特征与深度学习技术的研究 文章目录 自动化构音障碍严重程度分类:声学特征与深度学习技术的研究思维导图摘要I. 引言A. 动机与相关工作II. 数据库III. 实验设计A. 分析 MFCC 和 CQCCB. 分析语言障碍特定特征C. 分析 i-向量IV. 特征设计V. 分类…

设计模式 外观模式 门面模式

结构性模式-外观模式 门面模式 适用场景&#xff1a;如果你需要一个指向复杂子系统的直接接口&#xff0c; 且该接口的功能有限&#xff0c; 则可以使用外观模式。 不用关心后面的查询具体操作 /*** 聚合查询接口*/ RestController RequestMapping("/search") Slf…

【DB】根据某字段生成序号

如下图所示&#xff1a;根据RCV_ORD_NUM,生成明细行号&#xff0c;当RCV_ORD_NUM相同时&#xff0c;序号自增&#xff0c;不同时&#xff0c;从1开始并始终保持四位字符串 直接更新的方式 SET i : 0, now_region_id : NULL; UPDATE tqt_pl_prod.t_receipt_order_line l1 JOIN …