Go中如何将SQL查询结果映射为多维结构体并序列化JSON
时间:2026-08-17 | 作者:星河游者 | 阅读:0这段内容要解决的,是一个很常见但也很实际的问题:把 SQL 查询结果(比如 SELECT * FROM policy)返回的多行数据,按照 name 字段做分组,再动态组装成嵌套结构体,例如 table{Policy string, P []Parameters} 这样的形式,最后输出为前端能够直接消费的 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)
注意事项
- 结构体字段必须导出:
table→Table,p→P,否则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) }。
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- Scalatra 返回 JSON 时最容易踩的几个坑,顺手把正确写法梳理清楚
- 时间:2026-08-25
-
- SQL 如何对 JSON 字段进行分组聚合
- 时间:2026-08-24
-
- 怎样用 SQL JSON 函数查询数组中的指定元素
- 时间:2026-08-24
-
- Markdown流中嵌入JSON如何校验?Fluxmend用字符级FSM实现方案
- 时间:2026-08-18
-
- MySQL JSON函数提取与更新嵌套JSON字段值方法
- 时间:2026-08-18
-
- 如何高效动态修改JSON配置文件中的变量值方法
- 时间:2026-08-17
-
- 检测嵌套JSON同级节点重复label值的方法与技巧
- 时间:2026-08-17
-
- Symfony中如何验证单个嵌套JSON对象而不是数组
- 时间:2026-08-17
精选合集
更多大家都在玩
大家都在看
更多-
- 糖尿病完全不能吃糖吗
- 时间:2026-09-15
-
- 蚂蚁庄园小课堂2026年9月16日最新题目答案
- 时间:2026-09-15
-
- 小鸡答题今天的答案是什么2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园每日答题答案2026年9月16日
- 时间:2026-09-15
-
- 以下哪种粮食是酿造绍兴黄酒的主要原料 蚂蚁庄园今日答案9月16日
- 时间:2026-09-15
-
- 劝学名句“及时当勉励,岁月不待人”出自哪位诗人 蚂蚁庄园今日答案9.16
- 时间:2026-09-15
-
- 蚂蚁庄园今天答题答案2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园答题今日答案2026年9月16日
- 时间:2026-09-15
