英文:
How do I get a slice from a Postgres array in Golang?
问题
假设我有一个像这样的 PostgreSQL 查询:
SELECT
id,
ARRAY_AGG(code) AS code
FROM
codes
WHERE id = '9252781'
GROUP BY id;
我的返回结果如下:
id | codes
---------+-------------
9252781 | {H01,H02}
id
和 codes
都是 varchar
类型。
在 Golang 中,当我遍历结果的行时,它会卡住,没有错误,也没有任何提示。
英文:
Let's say I have a postgres query like:
SELECT
id,
ARRAY_AGG(code) AS code
FROM
codes
WHERE id = '9252781'
GROUP BY id;
My return looks like:
id | codes
-----------+-------------
9252781 | {H01,H02}
Both id
and codes
are varchar
.
In Golang when I scan along the rows for my result, it just freezes. No error, nothing.
答案1
得分: 5
如果你正在使用github.com/lib/pq
的PostgreSQL驱动程序,你可以使用它们的pq.Array辅助函数来扫描和存储PostgreSQL数组。
var id string
var arr []string
row := db.QueryRow(`SELECT '9252781', ARRAY['H01','H02']`)
if err := row.Scan(&id, pq.Array(&arr)); err != nil {
log.Fatal(err)
}
log.Println(id, arr)
// 9252781 [H01 H02]
英文:
If you're using the github.com/lib/pq
postgres driver you can use their pq.Array helper function to scan and store postgres arrays.
var id string
var arr []string
row := db.QueryRow(`SELECT '9252781', ARRAY['H01','H02']`)
if err := row.Scan(&id, pq.Array(&arr)); err != nil {
log.Fatal(err)
}
log.Println(id, arr)
// 9252781 [H01 H02]
答案2
得分: 1
我不想使用额外的驱动程序(github.com/lib/pq
),而且我没有找到任何pgx
的方法来实现,除非创建自己的类型。
所以我创建了一个:
type Tags []string
func (t *Tags) Scan(v interface{}) error {
if v == nil {
*t = Tags{}
return nil
}
s, ok := v.(string)
if !ok {
return fmt.Errorf("从数据库接收到的值应为字符串,但得到了 [%+v]", v)
}
s = strings.TrimPrefix(s, "{")
s = strings.TrimSuffix(s, "}")
*t = strings.Split(s, ",")
return nil
}
func (t *Tags) Value() (driver.Value, error) {
s := fmt.Sprintf("{%v}", strings.Join(([]string)(*t), ","))
return s, nil
}
然后你可以像这样扫描从数据库返回的行:
...
err := rows.Scan(
...
&Tags,
...
)
然后你可以直接在你的Exec
查询中使用它。
这段代码可以很好地处理数组中的常量,但如果要在逗号和括号中使用它,你需要做更多的工作。
英文:
I don't want to use a additional driver (github.com/lib/pq
), and I did not found any pgx
way to do it other than creating my own type.
So I did one:
type Tags []string
func (t *Tags) Scan(v interface{}) error {
if v == nil {
*t = Tags{}
return nil
}
s, ok := v.(string)
if !ok {
return fmt.Errorf("Scan is expected to receive a string from database, but got [%+v]", v)
}
s = strings.TrimPrefix(s, "{")
s = strings.TrimSuffix(s, "}")
*t = strings.Split(s, ",")
return nil
}
func (t *Tags) Value() (driver.Value, error) {
s := fmt.Sprintf("{%v}", strings.Join(([]string)(*t), ","))
return s, nil
}
then you can scan the row returned from database like:
...
err := rows.Scan(
...
&Tags,
...
)
and you can use it directly you your Exec
queries.
This code works well with constants in arrays, but you need more work if want to use it in commas and brackets.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论