You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C++17标准库按列名和类型访问SQLite的SQLITE_ROW条目

用C++17标准库实现按列名访问的SQLite查询结果存储

核心方案:自定义行结构体 + std::variant + std::unordered_map

C++17的std::variant支持存储多种数据类型,搭配std::unordered_map<std::string, std::variant<...>>可以实现按列名索引不同类型的值。我们可以定义一个代表单条查询结果的结构体,再用std::vector存储所有行,就能满足你的需求。

具体实现步骤

1. 预获取列名与类型映射

在遍历查询结果前,先获取所有列的名称和对应SQLite数据类型,方便后续按类型解析数据:

// 先获取列数
int columnCount = sqlite3_column_count(stmt);
// 存储列名到索引的映射
std::unordered_map<std::string, int> colNameToIndex;
// 存储列的类型(可选,用于后续类型校验)
std::vector<int> colTypes(columnCount);

for (int i = 0; i < columnCount; ++i) {
    const char* colName = sqlite3_column_name(stmt, i);
    colNameToIndex[colName] = i;
    colTypes[i] = sqlite3_column_type(stmt, i);
}

2. 定义自定义行类型

使用std::variant支持常见SQLite数据类型(整数、浮点数、字符串、NULL),并提供按列名访问的方法:

#include <unordered_map>
#include <variant>
#include <string>
#include <stdexcept>
#include <string>

struct QueryRow {
    // 存储列名到对应值的映射,支持多种数据类型
    std::unordered_map<std::string, std::variant<int, double, std::string, std::nullptr_t>> fields;

    // 模拟你想要的fieldByColumnName接口,返回可转换类型的包装
    struct FieldWrapper {
        const std::variant<int, double, std::string, std::nullptr_t>& var;

        std::string AsString() const {
            if (std::holds_alternative<int>(var)) {
                return std::to_string(std::get<int>(var));
            } else if (std::holds_alternative<double>(var)) {
                return std::to_string(std::get<double>(var));
            } else if (std::holds_alternative<std::string>(var)) {
                return std::get<std::string>(var);
            } else if (std::holds_alternative<std::nullptr_t>(var)) {
                return "NULL";
            }
            return "";
        }
    };

    FieldWrapper fieldByColumnName(const std::string& colName) const {
        auto it = fields.find(colName);
        if (it == fields.end()) {
            throw std::invalid_argument("Column not found: " + colName);
        }
        return FieldWrapper{it->second};
    }

    // 额外提供直接获取原始类型的方法(可选)
    template<typename T>
    T get(const std::string& colName) const {
        auto it = fields.find(colName);
        if (it == fields.end()) {
            throw std::invalid_argument("Column not found: " + colName);
        }
        if (std::holds_alternative<T>(it->second)) {
            return std::get<T>(it->second);
        } else {
            throw std::bad_variant_access();
        }
    }
};

3. 遍历SQLite结果并填充数据

将每一行的数据按列名和对应类型存入自定义的QueryRow,再加入到结果vector中:

std::vector<QueryRow> resultRows;

while (sqlite3_step(stmt) == SQLITE_ROW) {
    QueryRow row;
    for (const auto& [colName, index] : colNameToIndex) {
        int colType = sqlite3_column_type(stmt, index);
        switch (colType) {
            case SQLITE_INTEGER:
                row.fields[colName] = sqlite3_column_int(stmt, index);
                break;
            case SQLITE_FLOAT:
                row.fields[colName] = sqlite3_column_double(stmt, index);
                break;
            case SQLITE_TEXT: {
                const char* text = reinterpret_cast<const char*>(sqlite3_column_text(stmt, index));
                row.fields[colName] = text ? std::string(text) : std::string("");
                break;
            }
            case SQLITE_NULL:
                row.fields[colName] = nullptr;
                break;
            // 按需处理BLOB等其他类型
            default:
                row.fields[colName] = std::string("Unsupported type");
                break;
        }
    }
    resultRows.push_back(std::move(row));
}

4. 使用示例

按照你想要的方式访问数据:

for (const auto& row : resultRows) {
    // 用你指定的fieldByColumnName接口获取字符串形式的值
    std::cout << row.fieldByColumnName("columnname").AsString() << '\n';

    // 也可以直接获取原始类型(比如整数)
    try {
        int idVal = row.get<int>("id");
        std::cout << "ID: " << idVal << '\n';
    } catch (const std::exception& e) {
        std::cerr << "Error getting ID: " << e.what() << '\n';
    }
}

补充说明

  • std::variant是C++17新增特性,无需额外第三方库即可实现多类型存储。
  • 如果追求更高性能,可以将std::unordered_map替换为预先维护的列名索引映射,用std::vector<std::variant<...>>存储行数据,内存更紧凑,但按列名访问的可读性会稍弱。
  • 对于NULL值,这里用std::nullptr_t标记,你也可以自定义空类型替代。

内容的提问来源于stack exchange,提问作者Namal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 09:37:55