位置:首页 > Go > Go中如何将SQL查询结果映射为多维结构体并序列化JSON

Go中如何将SQL查询结果映射为多维结构体并序列化JSON

时间:2026-08-17  |  作者:星河游者  |  阅读:0

这段内容要解决的,是一个很常见但也很实际的问题:把 SQL 查询结果(比如 SELECT * FROM policy)返回的多行数据,按照 name 字段做分组,再动态组装成嵌套结构体,例如 table{Policy string, P []Parameters} 这样的形式,最后输出为前端能够直接消费的 JSON 格式。

如何在 Go 中将 SQL 查询结果映射到多维结构体并序列化为 JSON

这段内容主要讲的是,如何把 SQL 查询结果(比如 `SELECT * FROM policy`)返回的多行数据,按照 `name` 字段做分组,再动态组装成嵌套结构体(例如 `table{Policy string, P []Parameters}`)这样的形式,最后输出成符合前端预期的 JSON 格式。

在 Go 中处理关系型数据库查询结果并映射到嵌套结构体时,关键在于按逻辑维度聚合数据,而不是逐行硬编码赋值。

根据需求,目标 JSON 形如:

{
"policy": "policyName1",
"parameters": [
{"policy_id": "1", "class_id": "01", "name": "policyName1"},
{"policy_id": "2", "class_id": "02", "name": "policyName1"}
]
}

核心要求是:同一 name 值的所有记录,应归入同一个 table 实例;其 P 字段为该 name 下所有 Parameters 的切片。

正确实现方式

使用 map[string]table 动态分组

首先修正结构体命名与 JSON 标签。Go 中首字母大写才可导出:

type Table struct { // 首字母大写,确保可导出
Policy string `json:"policy"`
P[]Parameters `json:"parameters"` // 建议字段名语义清晰,避免单字母
}

type Parameters struct {
PolicyID string `json:"policy_id"`
ClassIDstring `json:"class_id"`
Name string `json:"name"`
// 其他字段...
}

然后,在扫描 SQL 行时,以 p.Name 为键维护一个 map[string]Table

ts := make(map[string]Table)

defer rows.Close()
for rows.Next() {
var p Parameters
if err := rows.Scan(&p.PolicyID, &p.ClassID, &p.Name); err != nil {
log.Printf("scan error: %v", err)
continue // 或根据业务决定是否中断
}

// 若该 policy name 尚未初始化,则创建新 table 实例
if _, exists := ts[p.Name]; !exists {
ts[p.Name] = Table{
Policy: p.Name,
P:make([]Parameters, 0), // 显式初始化空切片
}
}

// 将当前参数追加到对应 policy 的参数列表中
ts[p.Name].P = append(ts[p.Name].P, p)
}

// 转换为 JSON(例如返回给 HTTP 响应)
jsonData, err := json.Marshal(ts)
if err != nil {
http.Error(w, "JSON marshal error", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(jsonData)

注意事项

  • 结构体字段必须导出tableTablepP,否则 json.Marshal 无法访问字段,输出为空对象 {}
  • 避免类型混淆:原问题中 t := table{Policy: p.Name, P: p} 错误地将单个 Parameters 赋值给 []Parameters 类型字段,Go 会编译报错。正确做法是 append 到切片。
  • 内存与性能:若 name 唯一性高、数据量大,map 是高效选择;若需保持插入顺序,可额外维护 []string 记录 key 顺序。
  • SQL 字段一致性:确保 rows.Scan 中的参数顺序、类型与 SELECT 字段严格匹配;推荐显式列名(如 SELECT policy_id, class_id, name FROM policy)而非 SELECT *,提升可维护性。

最终效果

输入 SQL 数据:

policy_id | class_id | name
----------|----------|---------
1 | 01 | policyName1
2 | 02 | policyName1
3 | 03 | policyName2

输出 JSON:

{
"policyName1": {
"policy": "policyName1",
"parameters": [
{"policy_id": "1", "class_id": "01", "name": "policyName1"},
{"policy_id": "2", "class_id": "02", "name": "policyName1"}
]
},
"policyName2": {
"policy": "policyName2",
"parameters": [
{"policy_id": "3", "class_id": "03", "name": "policyName2"}
]
}
}

如需扁平化为 []Table,而非 map,可在循环结束后执行 values := make([]Table, 0, len(ts)); for _, t := range ts { values = append(values, t) }

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多