You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang使用sqlc生成带嵌套数组的结构体失败求助

在Golang中用sqlc和PostgreSQL实现带嵌套分类数组的产品列表问题

我在Golang项目里用sqlc配合PostgreSQL,想要实现返回包含嵌套产品分类数组的产品列表功能,试了几种方法都没解决,具体情况如下:

表结构

create table products
(
    id    serial primary key,
    title text unique not null,
    url   text
);

create table product_categories
(
    id         serial primary key,
    title      text unique not null,
    product_id integer     not null
        constraint products_id_fk references products (id),
    url        text
);

尝试过的方案与问题

方案1:直接关联查询

使用如下查询语句:

select p.*, sqlc.embed(pc)
from products p
         join product_categories pc on pc.product_id = p.id

期望生成的结构体:

type GetAllProductsAndSubcatsRow struct {
    ID                int32           `db:"id" json:"id"`
    Title             string          `db:"title" json:"title"`
    Url               pgtype.Text     `db:"url" json:"url"`
    ProductCategory []ProductCategory `db:"product_category" json:"product_category"`
}

实际生成的结构体:

type GetAllProductsAndSubcatsRow struct {
    ID              int32           `db:"id" json:"id"`
    Title           string          `db:"title" json:"title"`
    Url             pgtype.Text     `db:"url" json:"url"`
    ProductCategory ProductCategory `db:"product_category" json:"product_category"`
}

问题:sqlc将关联后的每一行结果映射为单个对象,不会自动把同一产品的多个分类聚合为数组。

方案2:使用array_agg函数

尝试用array_agg聚合分类,生成的结构体中分类字段变成了interface{},无法直接使用:

type GetAllProductsAndSubcatsRow struct {
    ID              int32           `db:"id" json:"id"`
    Title           string          `db:"title" json:"title"`
    Url             pgtype.Text     `db:"url" json:"url"`
    ProductCategory interface{}     `db:"product_category" json:"product_category"`
}

问题:PostgreSQL的array_agg默认返回匿名复合类型数组,sqlc无法识别为自定义的ProductCategory结构体,只能推断为interface{}。

错误原因分析

  1. 直接关联查询返回的是平级多行数据,每个产品对应多条分类记录,sqlc按行映射结构体,自然会把分类字段处理为单个对象。
  2. array_agg聚合匿名复合类型时,sqlc没有足够的类型信息来映射到自定义结构体,只能 fallback 到interface{}。

解决方法

方法1:用json_agg+sqlc类型映射

这是最简便的方案,利用PostgreSQL的json_agg将分类转为JSON数组,再通过sqlc的类型映射把JSON数组绑定到[]ProductCategory。

步骤1:修改查询语句

select 
    p.id,
    p.title,
    p.url,
    json_agg(pc) as product_categories
from products p
join product_categories pc on pc.product_id = p.id
group by p.id, p.title, p.url

注意:必须用group by聚合产品的所有非聚合字段,否则PostgreSQL会报错。

步骤2:配置sqlc类型映射

在你的sqlc.yaml配置文件中,添加JSON数组到[]ProductCategory的类型映射:

sql:
  - schema: "schema.sql"  # 你的表结构文件路径
    queries: "queries.sql" # 你的查询语句文件路径
    engine: "postgresql"
    gen:
      go:
        out: "internal/db" # 生成代码的输出目录
        overrides:
          - db_type: "jsonb"
            go_type:
              type: "[]ProductCategory"
              import: "your/project/path/to/db" # 替换为ProductCategory结构体所在的包路径

这样sqlc就能把json_agg返回的JSON数组正确映射为[]ProductCategory类型。

方法2:自定义PostgreSQL类型+array_agg

如果不想用JSON,可通过自定义PostgreSQL类型让sqlc识别聚合后的数组类型。

步骤1:创建自定义类型

create type product_category_type as (
    id int,
    title text,
    product_id int,
    url text
);

步骤2:修改查询语句

select 
    p.*,
    array_agg(pc::product_category_type) as product_categories
from products p
join product_categories pc on pc.product_id = p.id
group by p.id, p.title, p.url

步骤3:配置sqlc类型映射

在sqlc.yaml中添加自定义类型数组到[]ProductCategory的映射:

sql:
  - schema: "schema.sql"
    queries: "queries.sql"
    engine: "postgresql"
    gen:
      go:
        out: "internal/db"
        overrides:
          - db_type: "product_category_type[]"
            go_type:
              type: "[]ProductCategory"
              import: "your/project/path/to/db"

内容的提问来源于stack exchange,提问作者Anton Bychek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 09:53:17