我有一个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 字段是一种常见的操作。
是否可以通过sql或sqlx在所有 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 []string
和implement 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/