SQLの取得結果をHas Manyの形で格納したいことがあるかもしれません。しかし、SQLでのSELECTの結果は階層化されていないので、ソースコードでロジックを組んで組み立てる必要があります。
Goの場合、SQLの取得結果を1行ずつ処理できるrow.Next()があるので、用意した構造体に格納するロジックをソースコードで組めば、Has Manyを実現することができます。
type Group struct {
GroupID int `json:"group_id"`
GroupName string `json:"group_name"`
Workers []Worker`json:"workers"`
}
type Worker struct {
WorkerID int `json:"worker_id"`
WorkerName string `json:"worker_name"`
Jobs []Job`json:"jobs"`
}
type Job struct {
JobID int `json:"job_id"`
JobName string `json:"job_name"`
}
func main() {
rtns := []*Group{}
cnn := sql.Open("mysql", "...")
rows, err := cnn.Query("SELECT ... FROM ...")
for rows.Next() {
group := &Group{}
worker := &Worker{}
job := &Job{}
err := rows.Scan(
&group.GroupID,
&group.GroupName,
&worker.WorkerID,
&worker.WorkerName,
&job.JobID,
&job.JobName,
)
if err != nil {
...
return nil, err
}
rtns = buildGroups(rtns, group, worker, job)
}
return rtns, nil
}
// 前回のrowの内容と比較して、IDが一致する場合は前回のrowの格納結果のsliceに追加して階層構造を作る関数
func buildGroups(rtns []*Group, group *Group, worker *Worker, job *Job) []*Group {
if len(rtns) > 0 {
lastW := rtns[len(rtns)-1].Workers
lastWorkerID := lastW[len(lastW)-1].WorkerID
if worker.WorkerID == lastWorkerID {
lastW[len(lastW)-1].Jobs = append(lastW[len(lastW)-1].Jobs, *job)
} else {
worker.Jobs = append(worker.Jobs, *job)
lastGroupID := rtns[len(rtns)-1].GroupID
if group.GroupID == lastGroupID {
rtns[len(rtns)-1].Workers = append(lastW, *worker)
} else {
group.Workers = append(group.Workers, *worker)
rtns = append(rtns, group)
}
}
} else {
worker.Jobs = append(worker.Jobs, *job)
group.Workers = append(group.Workers, *worker)
rtns = append(rtns, group)
}
return rtns
}