Linux下GCC和C++實現帶多組標簽的Snowflake SQL查詢批量數據導出程序

設計一個基于多個帶標簽Snowflake SQL語句作為json配置文件的Linux下GCC的C++代碼程序,實現根據不同的輸入參數自動批量地將Snowflake數據庫的數據導出為CSV文件到本地目錄上,標簽加擴展名.csv為導出數據文件名,文件已經存在則覆蓋原始文件。需要考慮SQL結果集是大數據量分批數據導出的情況,通過多線程和異步操作來提高程序性能,程序需要異常處理和輸出,輸出出錯時的錯誤信息,每次每個查詢導出數據的運行狀態和表數據行數以及運行時間戳,導出時間,輸出每個文件記錄數量的日志。

C++程序實現,該程序使用多線程和分頁查詢從Snowflake導出數據到CSV文件,并記錄詳細日志:

此代碼實現了需求中的核心功能,實際部署時可能需要根據具體環境調整:

  1. ODBC連接字符串參數
  2. 分頁策略(可能需要優化分頁方式)
  3. 數據類型轉換(當前按字符串處理所有類型)
  4. 錯誤處理策略(增加重試機制等)
  5. 線程池實現(當前為每個任務創建獨立線程)
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <thread>
#include <mutex>
#include <atomic>
#include <chrono>
#include <iomanip>
#include <nlohmann/json.hpp>
#include <sql.h>
#include <sqlext.h>using namespace std;
using json = nlohmann::json;// 配置結構
struct ExportTask {string label;string sql;int batch_size;
};// 日志類(線程安全)
class Logger {
private:mutex log_mutex;ofstream log_file;string current_time() {auto now = chrono::system_clock::now();time_t now_time = chrono::system_clock::to_time_t(now);tm tm = *localtime(&now_time);stringstream ss;ss << put_time(&tm, "%Y-%m-%d %H:%M:%S");return ss.str();}public:Logger(const string& filename) {log_file.open(filename, ios::app);}~Logger() {log_file.close();}void log(const string& label, const string& status, int rows, const string& error_msg, long duration_ms) {lock_guard<mutex> lock(log_mutex);log_file << current_time() << " | "<< label << " | "<< status << " | "<< rows << " | "<< duration_ms << "ms | "<< error_msg << endl;}
};// Snowflake導出器
class SnowflakeExporter {
private:string conn_str;void handle_odbc_error(SQLHANDLE handle, SQLSMALLINT type) {SQLCHAR sqlstate[6], message[SQL_MAX_MESSAGE_LENGTH];SQLINTEGER native_error;SQLSMALLINT length;SQLGetDiagRec(type, handle, 1, sqlstate, &native_error, message, SQL_MAX_MESSAGE_LENGTH, &length);throw runtime_error(string((char*)message));}public:SnowflakeExporter(const string& conn_str) : conn_str(conn_str) {}vector<vector<string>> execute_paged_query(const string& base_sql, int limit, int offset) {SQLHENV env;SQLHDBC dbc;SQLHSTMT stmt;vector<vector<string>> results;try {// 初始化ODBC環境SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);// 建立連接SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);SQLCHAR out_str[1024];SQLSMALLINT out_str_len;if (SQLDriverConnect(dbc, NULL, (SQLCHAR*)conn_str.c_str(), SQL_NTS,out_str, sizeof(out_str), &out_str_len,SQL_DRIVER_COMPLETE) != SQL_SUCCESS) {handle_odbc_error(dbc, SQL_HANDLE_DBC);}// 構造分頁SQLstring sql = base_sql + " LIMIT " + to_string(limit) + " OFFSET " + to_string(offset);// 執行查詢SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);if (SQLExecDirect(stmt, (SQLCHAR*)sql.c_str(), SQL_NTS) != SQL_SUCCESS) {handle_odbc_error(stmt, SQL_HANDLE_STMT);}// 獲取結果列數SQLSMALLINT num_cols;SQLNumResultCols(stmt, &num_cols);// 綁定列并獲取數據while (SQLFetch(stmt) == SQL_SUCCESS) {vector<string> row;for (int i = 1; i <= num_cols; ++i) {SQLCHAR val[4096];SQLLEN indicator;SQLGetData(stmt, i, SQL_C_CHAR, val, sizeof(val), &indicator);row.emplace_back(indicator == SQL_NULL_DATA ? "" : string((char*)val));}results.push_back(row);}// 清理資源SQLFreeHandle(SQL_HANDLE_STMT, stmt);SQLDisconnect(dbc);SQLFreeHandle(SQL_HANDLE_DBC, dbc);SQLFreeHandle(SQL_HANDLE_ENV, env);}catch (...) {SQLFreeHandle(SQL_HANDLE_STMT, stmt);SQLDisconnect(dbc);SQLFreeHandle(SQL_HANDLE_DBC, dbc);SQLFreeHandle(SQL_HANDLE_ENV, env);throw;}return results;}
};// CSV寫入器
class CSVWriter {
private:ofstream file;mutex file_mutex;string escape_csv(const string& s) {if (s.find('"') != string::npos || s.find(',') != string::npos) {return "\"" + regex_replace(s, regex("\""), "\"\"") + "\"";}return s;}public:CSVWriter(const string& filename) {file.open(filename, ios::out | ios::trunc);}~CSVWriter() {file.close();}void write_rows(const vector<vector<string>>& rows) {lock_guard<mutex> lock(file_mutex);for (const auto& row : rows) {string line;for (size_t i = 0; i < row.size(); ++i) {line += escape_csv(row[i]);if (i != row.size() - 1) line += ",";}file << line << "\n";}}
};// 導出任務處理函數
void process_export_task(const ExportTask& task, const SnowflakeExporter& exporter,CSVWriter& writer,Logger& logger) {auto start_time = chrono::high_resolution_clock::now();int total_rows = 0;string error_msg;try {int offset = 0;while (true) {auto data = exporter.execute_paged_query(task.sql, task.batch_size, offset);if (data.empty()) break;writer.write_rows(data);total_rows += data.size();offset += task.batch_size;}}catch (const exception& e) {error_msg = e.what();}auto end_time = chrono::high_resolution_clock::now();auto duration = chrono::duration_cast<chrono::milliseconds>(end_time - start_time).count();logger.log(task.label, error_msg.empty() ? "SUCCESS" : "FAILED",total_rows,error_msg,duration);
}int main(int argc, char* argv[]) {// 加載配置文件ifstream config_file("config.json");json config = json::parse(config_file);// 解析連接字符串string conn_str = "DRIVER=SnowflakeDSIIDriver;""SERVER=" + config["server"].get<string>() + ";""DATABASE=" + config["database"].get<string>() + ";""SCHEMA=" + config["schema"].get<string>() + ";""UID=" + config["user"].get<string>() + ";""PWD=" + config["password"].get<string>() + ";";// 初始化組件Logger logger("export.log");SnowflakeExporter exporter(conn_str);// 創建線程池vector<thread> threads;vector<unique_ptr<CSVWriter>> writers;for (auto& task_json : config["tasks"]) {ExportTask task{task_json["label"],task_json["sql"],task_json["batch_size"]};writers.emplace_back(make_unique<CSVWriter>(task.label + ".csv"));threads.emplace_back(process_export_task, task, ref(exporter),ref(*writers.back()), ref(logger));}// 等待所有線程完成for (auto& t : threads) {t.join();}return 0;
}

編譯說明:

  1. 需要安裝Snowflake ODBC驅動
  2. 需要鏈接ODBC庫(-lodbc)
  3. 需要nlohmann/json庫
  4. 推薦使用C++17或更高標準編譯

配置文件示例(config.json):

{"server": "your_account.snowflakecomputing.com","database": "your_db","schema": "your_schema","user": "your_user","password": "your_password","tasks": [{"label": "orders","sql": "SELECT * FROM orders ORDER BY order_date","batch_size": 10000},{"label": "customers","sql": "SELECT * FROM customers WHERE status = 'ACTIVE'","batch_size": 5000}]
}

程序特點:

  1. 多線程處理多個導出任務
  2. 分頁查詢處理大數據集
  3. CSV文件自動覆蓋寫入
  4. 線程安全的日志記錄
  5. 詳細的錯誤處理
  6. CSV特殊字符轉義
  7. 性能指標記錄(耗時、行數)

日志格式示例:

2024-03-20 14:30:45 | orders | SUCCESS | 250000 | 4500ms | 
2024-03-20 14:31:02 | customers | FAILED | 12000 | 17000ms | Network connection error

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/73433.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/73433.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/73433.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Trae AI 輔助修復uniapp 微信小程序的Bug

一、transparent的兼容問題 設計稿&#xff1a; 實際在iphone 6 plu上&#xff1a; 直接讓Trae AI修復&#xff1a; 修改后驗證通過。 二、v-if分支中子元素根據輸入框中內容長度動態添加class樣式失效 遇到了個“怪問題”&#xff0c;在其他手機或者開發者工具都正常。也…

conda install 和 pip install 的區別

conda install 和 pip install 是兩個常用的包安裝命令&#xff0c;但它們在很多方面存在差異。 1. 所屬管理系統不同 1.1 conda install conda install 是Anaconda和Miniconda發行版自帶的包管理工具 conda 的安裝命令。conda 是一個跨平臺的開源包管理系統和環境管理系統&…

uni-app App 端分段導出 JSON 數據為文件

在開發過程中&#xff0c;我們經常需要將大量數據導出為 JSON 文件&#xff0c;尤其是在處理長列表或大數據集時。然而&#xff0c;直接將所有數據寫入一個文件可能會導致性能問題&#xff0c;尤其是在移動設備上。為了優化性能并提高用戶體驗&#xff0c;我們可以將數據分段導…

視頻推拉流EasyDSS案例分析:互聯網直播/點播技術與平臺創新應用

隨著互聯網技術的快速發展&#xff0c;直播/點播平臺已成為信息傳播和娛樂的重要載體。特別是在電視購物領域&#xff0c;互聯網直播/點播平臺與技術的應用&#xff0c;不僅為用戶帶來了全新的購物體驗&#xff0c;也為商家提供了更廣闊的營銷渠道。傳統媒體再一次切實感受到了…

MySQL再次基礎 向初級工程師邁進

作者&#xff1a;在計算機行業找不到工作的大四失業者 Run run run ! ! ! 1、MySQL概述 1.1數據庫相關概念 1.2MySQL數據庫 2、SQL 2.1SQL通用語法 SQL語句可以單行或多行書寫&#xff0c;以分號結尾。SQL語句可以使用空格/縮進來增強語句的可讀性。MySQL數據庫的SQL語句不區…

手寫一個簡易版的tomcat

Tomcat 是一個廣泛使用的開源 Servlet 容器&#xff0c;用于運行 Java Web 應用程序。深入理解 Tomcat 的工作原理對于 Java 開發者來說是非常有價值的。本文將帶領大家手動實現一個簡易版的 Tomcat&#xff0c;通過這個過程&#xff0c;我們可以更清晰地了解 Tomcat 是如何處理…

VSTO(C#)Excel開發8:打包發布安裝卸載

初級代碼游戲的專欄介紹與文章目錄-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代碼都將會位于ctfc庫中。已經放入庫中我會指出在庫中的位置。 這些代碼大部分以Linux為目標但部分代碼是純C的&#xff0c;可以在任何平臺上使用。 源碼指引&#xff1a;github源…

如何逐步迭代衍生出一個網絡安全產品

逐步迭代衍生出一個網絡安全產品需要結合市場需求、技術趨勢和用戶反饋&#xff0c;通過系統化的開發和優化過程來實現。以下是逐步迭代的詳細步驟&#xff1a; 1. 確定市場需求和產品定位 市場調研&#xff1a;分析當前網絡安全市場的痛點和趨勢&#xff0c;如云安全、零信任、…

uni-app打包h5并部署到nginx,路由模式history

uni-app打包有些坑&#xff0c;當時運行的基礎路徑填寫了./&#xff0c;導致在二級頁面刷新之后&#xff0c;頁面直接空白。就只能換一個路徑了&#xff0c;nginx也要跟著改&#xff0c;下面是具體步驟。 manifest.json配置web 運行路徑寫/h5/&#xff0c;或者寫你們網站的目…

Ceph(1):分布式存儲技術簡介

1 分布式存儲技術簡介 1.1 分布式存儲系統的特性 &#xff08;1&#xff09;可擴展 分布式存儲系統可以擴展到幾百臺甚至幾千臺的集群規模&#xff0c;而且隨著集群規模的增長&#xff0c;系統整體性能表現為線性增長。分布式存儲的水平擴展有以下幾個特性&#xff1a; 節點…

Linux驅動開發實戰(五):Qt應用程序點RGB燈(保姆級快速入門!)

Linux驅動開發實戰&#xff08;五&#xff09;&#xff1a;Qt應用程序點RGB燈&#xff08;保姆級快速入門&#xff01;&#xff09; 文章目錄 Linux驅動開發實戰&#xff08;五&#xff09;&#xff1a;Qt應用程序點RGB燈&#xff08;保姆級快速入門&#xff01;&#xff09;前…

Docker安裝Kafka(內含zookeeper)

因為kafka是基于zookeeper做的&#xff0c;所以必須要有zookeeper 一、Zookeeper 1.拉取鏡像 docker pull zookeeper:3.7.02.運行 docker run --restartalways \--log-driver json-file \--log-opt max-size100m \--log-opt max-file2 \--name zookeeper -p 2181:2181 \-v…

芯谷D8563TS實時時鐘/日歷芯片詳解可替代PCF8563

概述 芯谷D8563TS是一款低功耗CMOS實時時鐘/日歷芯片&#xff0c;廣泛應用于移動電話、便攜式儀器、傳真機和電池供電產品等領域。該芯片通過兩線雙向IC總線進行數據傳輸&#xff0c;最大總線速度為400 kbits/s。D8563TS內置了自動遞增的字地址寄存器&#xff0c;支持多種功能…

【一次成功】Win10本地化單機部署k8s v1.31.2版本及可視化看板

【一次成功】Win10本地化單機部署k8s v1.31.2版本及可視化看板 零、安裝清單一、安裝Docker Desktop軟件1.1 安裝前<啟用或關閉Windows功能> 中的描紅的三項1.2 查看軟件版本1.3 配置Docker鏡像 二、更新裝Docker Desktop三、安裝 k8s3.1 點擊啟動安裝3.2 查看狀態3.3 查…

MoonSharp 文檔五

目錄 13.Coroutines&#xff08;協程&#xff09; Lua中的協程 從CLR代碼中的協程 從CLR代碼中的協程作為CLR迭代器 注意事項 搶占式協程 14.Hardwire descriptors&#xff08;硬編碼描述符&#xff09; 為什么需要“硬編碼” 什么是“硬編碼” 如何進行硬編碼 硬編…

【初級篇】如何使用DeepSeek和Dify構建高效的企業級智能客服系統

在當今數字化時代,企業面臨著日益增長的客戶服務需求。使用Dify創建智能客服不僅能夠提升客戶體驗,還能顯著提高企業的運營效率。關于DIfy的安裝部署,大家可以參考之前的文章: 【入門級篇】Dify安裝+DeepSeek模型配置保姆級教程_mindie dify deepseek-CSDN博客 AI智能客服…

【網絡編程】HTTP網絡編程

13.1 HTTP 簡介 HTTP(Hyper Text Transfer Protocol,超文本傳輸協議)是用于從萬維網(WWW:World Wide Web) 服務器(簡稱Web 服務器)傳輸超文本到本地瀏覽器的傳送協議&#xff0c;基于TCP/IP 通信協 議來傳遞數據 (HTML 文件、圖片文件、查詢結果等)。 13.2 HTTP 的工作原理 …

用Scrum敏捷的視角看《哪吒2》的創作

去年我們公司邀請Scrum中文網的老師培訓了敏捷開發課程&#xff0c;讓我對敏捷有了更深入的理解。前陣子我參加了scrum中文網的一個直播&#xff0c;老師分享了敏捷在個人領域或生活其他領域的應用&#xff0c;很有意思。因為我學習敏捷&#xff0c;除了應用到本身軟件研發的工…

Docker+Flask 實戰:打造高并發微服務架構

DockerFlask 實戰&#xff1a;打造高并發微服務架構 今天我們要深入探討一個非常熱門且實用的主題&#xff1a;基于 Docker 部署 Python Flask 應用。Docker 作為當下最流行的容器化技術&#xff0c;已經廣泛應用于各種開發和部署場景&#xff0c;尤其是在微服務架構中。而 Fl…

Linux find 命令完全指南

find 是 Linux 系統最強大的文件搜索工具&#xff0c;支持 嵌套遍歷、條件篩選、執行動作。以下通過場景分類解析核心用法&#xff0c;涵蓋高效搜索、文件管理及高級技巧&#xff1a; 一、基礎搜索模式 1. 按文件名搜索&#xff08;精確/模糊匹配&#xff09; <BASH> f…