
本文介绍如何将 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"`
ClassID string `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) }。


















