// 1 次查询所有用户 rows, _ := db.Query("SELECT id, name FROM users") var users []User for rows.Next() { var u User rows.Scan(&u.ID, &u.Name) users = append(users, u) }
// 对于每个用户,再发 1 次查询获取订单 (N 次) for i, u := range users { rows, _ := db.Query("SELECT id, amount FROM orders WHERE user_id = ?", u.ID) for rows.Next() { var o Order rows.Scan(&o.ID, &o.Amount) users[i].Orders = append(users[i].Orders, o) } }
// 一次 JOIN 查询 rows, _ := db.Query(` SELECT u.id, u.name, o.id, o.amount FROM users u LEFT JOIN orders o ON u.id = o.user_id ORDER BY u.id `) // 用 map 在应用层合并数据 userMap := make(map[int]*User) for rows.Next() { var uID, oID int var uName string var oAmount sql.NullFloat64 // 可能没有订单,用 Null 类型 rows.Scan(&uID, &uName, &oID, &oAmount)
// 如果用户还没放进 map,创建一个 if _, ok := userMap[uID]; !ok { userMap[uID] = &User{ID: uID, Name: uName} } // 如果有订单数据,追加进去 if oAmount.Valid { userMap[uID].Orders = append(userMap[uID].Orders, Order{ID: oID, Amount: oAmount.Float64}) } } users := make([]*User, 0, len(userMap)) for _, u := range userMap { users = append(users, u) }
首先用一次JOIN得到所有数据,然后在应用层用map合并数据,当然用preload会更省代码:
1 2
var users []User db.Preload("Orders").Find(&users)