dpde7365 2014-08-30 13:26
浏览 38
已采纳

如何将m:n关系映射到切片字段?

I have a struct Person:

type Person struct {
    Id     int64
    Name   string
    Colors []string
}

which should get its data from a person table:

id | name
---------
1  | Joe
2  | Moe

and a person_color table:

person_id | color
-----------------
1         | black
1         | blue
2         | green

Via SELECT p.id, p.name, pc.color FROM person AS p INNER JOIN person_color AS pc ON pc.person_id = p.id I merge both tables to:

id | name | color
-----------------
1  | Joe  | black
1  | Joe  | blue
2  | Moe  | green

At the moment the only thing I could think of would be to manually map colors while iterating over rows.Next() (NOTE: just dummy code):

ps := make([]People, 0)

rows, err := db.Query("SELECT ...")

for rows.Next() {
    var p Person

    err := rows.Scan(&p.Id, &p.Name, &p.Color[0])

    exists := false

    for _, ps := range ps {
        if ps.Id == p {
            exists = true

            ps.Color = append(ps.Color, p.Color)
        }
    }

    if !exists {
        ps = append(ps, p)
    }
}

Though this would work this is quite annoying as mapping to a slice field is a common operation.

Is there any way to make the above generic on all slice fields with sql or sqlx?

  • 写回答

2条回答 默认 最新

  • dongniechi7825 2014-08-30 19:48
    关注

    I'd almost certainly approach this from the SQL side. In PostgreSQL you can use the array_agg to get array types back, which given the proper Scanner implementation should be resistant to weird data values:

    SELECT p.id, p.name, pc.color FROM 
           person AS p INNER JOIN 
           array_agg(person_color) AS pc 
        ON
           pc.person_id = p.id
        GROUP BY p.id;
    

    This would return:

     id | name |  array_agg
    ----+------+--------------
      1 | Joe  | {black,blue}
      2 | Moe  | {green}
    

    It's up to you to create a Go type like type pgarraystring []string and implement Scanner, though it's possible I will add some of these types for PostgreSQL someday soon in the github.com/jmoiron/sqlx/types package.

    In MySQL or SQLite, you're going to lack array types, but you can use GROUP_CONCAT[1] to achieve similar results. In other databases, there should be a similar concat aggregate which works with the text representation.

    There are a few reasons for going this route. You're using an SQL database for a reason; it should be able to return you the data you want in the desired format; unless it's really going to be a problem and you've measured it, fall back on it, that's its strength as a datastore. It also reduces the amount of data being sent back over the wire and the number of fetches being done by the cursor, so in general it should behave better.

    [1] Sorry, I can't post a link to GROUP_CONCAT because I don't have any StackOverflow reputation, but you should be able to google it.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 mmocr的训练错误,结果全为0
  • ¥15 python的qt5界面
  • ¥15 无线电能传输系统MATLAB仿真问题
  • ¥50 如何用脚本实现输入法的热键设置
  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀