我有一个struct Person:

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

应该从person表获取其数据:
id | name
---------
1  | Joe
2  | Moe

和一个person_color表:
person_id | color
-----------------
1         | black
1         | blue
2         | green

通过SELECT p.id, p.name, pc.color FROM person AS p INNER JOIN person_color AS pc ON pc.person_id = p.id我将两个表合并到:
id | name | color
-----------------
1  | Joe  | black
1  | Joe  | blue
2  | Moe  | green

目前,我唯一想到的就是在rows.Next()上迭代时手动映射颜色(注意:只是伪代码):
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)
    }
}

尽管这可以工作,但是这很烦人,因为映射到 slice 字段是一种常见的操作。

是否可以通过sqlsqlx在所有 slice 字段上使上述通用化?

最佳答案

我几乎肯定会从SQL方面解决这个问题。在PostgreSQL中,您可以使用array_agg取回数组类型,在适当的Scanner实现下,该数组类型应能够抵抗怪异的数据值:

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;

这将返回:
 id | name |  array_agg
----+------+--------------
  1 | Joe  | {black,blue}
  2 | Moe  | {green}

您可以自行创建Go类型,例如type pgarraystring []stringimplement Scanner,尽管有可能我有一天很快会在github.com/jmoiron/sqlx/types包中为PostgreSQL添加其中一些类型。

在MySQL或SQLite中,将缺少数组类型,但是可以使用GROUP_CONCAT [1]来实现类似的结果。在其他数据库中,应该有一个类似的concat聚合,可以与文本表示形式一起使用。

选择此路线有几个原因。您使用SQL数据库是有原因的;它应该能够以所需格式返回您想要的数据;除非它确实会成为一个问题并且您已经对其进行了度量,然后再依靠它,否则这就是它作为数据存储库的优势。它还减少了通过导线发送回的数据量和由游标执行的获取次数,因此通常它应该表现得更好。

[1]抱歉,由于我没有任何StackOverflow信誉,因此我无法发布GROUP_CONCAT的链接,但是您应该可以使用它进行Google搜索。

关于sql - 如何将m:n关系映射到 slice 字段?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25582848/

10-16 14:56