
本文介绍通过 array_to_json() 将 PostgreSQL 的 character varying[] 数组转换为 JSON 字符串,再用 json.Unmarshal 解析为 Go 原生 []string 的可靠方案,避免 sql.Scanner 默认不支持数组类型导致的空切片问题。
本文介绍通过 `array_to_json()` 将 postgresql 的 `character varying[]` 数组转换为 json 字符串,再用 `json.unmarshal` 解析为 go 原生 `[]string` 的可靠方案,避免 `sql.scanner` 默认不支持数组类型导致的空切片问题。
在使用 database/sql 驱动(如 lib/pq 或 pgx)查询 PostgreSQL 时,原生数组类型(如 text[]、varchar[])无法被 Go 的 rows.Scan(&slice) 直接解码为 []string——这是因为标准 sql.Scanner 接口未内置对 PostgreSQL 数组的解析逻辑,导致变量保持零值(如 len(arr) == 0),而非预期的元素集合。
✅ 推荐解决方案:SQL 层转 JSON + Go 层反序列化
利用 PostgreSQL 内置函数 array_to_json() 将数组安全地转为标准 JSON 格式(如 ["a","b"]),再在 Go 中用 json.Unmarshal 解析。该方法稳定、跨驱动兼容,且无需引入额外 ORM 或复杂类型注册。
✅ 正确实现示例
import (
"database/sql"
"encoding/json"
"fmt"
_ "github.com/lib/pq" // 或 github.com/jackc/pgx/v5
)
// 查询语句:显式将 PostgreSQL 数组转为 JSON 字符串
const query = `SELECT array_to_json(urls) FROM posts WHERE id = $1`
var arrStr string
var urls []string
rows, err := db.Query(query, postID)
if err != nil {
panic(err)
}
defer rows.Close()
for rows.Next() {
if err := rows.Scan(&arrStr); err != nil {
panic(err)
}
if err := json.Unmarshal([]byte(arrStr), &urls); err != nil {
panic(fmt.Sprintf("failed to unmarshal JSON '%s': %v", arrStr, err))
}
fmt.Printf("Parsed %d URLs: %v\n", len(urls), urls)
}? 输出示例:
Parsed 2 URLs: [http://wp.me/p62MJv-Jc http://tyrant.click/1LGBoD6]
⚠️ 关键注意事项
- 不要省略 array_to_json():直接 SELECT urls 返回的是 PostgreSQL 的文本表示(如 {a,b}),非标准 JSON,json.Unmarshal 会报错 invalid character '{'。
- 空数组与 NULL 处理:array_to_json(NULL) 返回 null,需提前检查 arrStr == "null" 或使用指针 *[]string;空数组 ARRAY[]::text[] 会转为 [],可正常解析。
- 类型一致性:确保数据库列类型与目标 Go 切片类型匹配(如 text[] → []string,int[] → []int),否则 json.Unmarshal 可能静默失败或类型错误。
- 性能考量:对高频小数组场景影响极小;若需极致性能且数组结构固定,可考虑 pgx 的自定义 pgtype.Array 扫描器,但需额外类型绑定,牺牲通用性。
✅ 总结
array_to_json() + json.Unmarshal 是当前最简洁、健壮、无依赖的 PostgreSQL 数组到 Go 切片映射方案。它规避了驱动限制,符合 SQL 标准,代码清晰易维护。对于绝大多数 Web/API 场景,此模式应作为首选实践。










