如何用Golang+SQLC将PostgreSQL IN查询转为变量并通过结构体传递
问题概述
在使用Golang结合sqlc工具将PostgreSQL查询转为带变量的代码时,遇到类型不匹配问题:
- 原查询中
fos."name" IN ('IT & Software', 'Analisis Data & Statistik')替换为变量$2后,sqlc生成的参数类型为string,但实际需要接收Golang结构体SearchMajorReq中FieldOfStudies []string类型的数组参数(对应JSON请求体中的数组字段),导致类型错误。
原查询语句:
SELECT mou."id", mou."name", mou.description, mou.img_url, um.favorite FROM majors_of_universities mou JOIN field_of_studies fos ON mou.field_of_studies_id = fos."id" JOIN univ_major um ON mou."id" = um.majors_of_universities_id WHERE mou."name" ILIKE '%%' AND fos."name" IN ( 'IT & Software', 'Analisis Data & Statistik' ) ORDER BY mou."name" LIMIT 99 OFFSET 0;
用户修改后的变量化查询(存在类型问题):
SELECT mou."id", mou."name", mou.description, mou.img_url, um.favorite FROM majors_of_universities mou JOIN field_of_studies fos ON mou.field_of_studies_id = fos."id" JOIN univ_major um ON mou."id" = um.majors_of_universities_id WHERE mou."name" ILIKE $1 AND fos."name" IN ($2) ORDER BY mou."name" LIMIT $3 OFFSET $4;
Golang结构体定义:
type SearchMajorReq struct { Name string `json:"name"` FieldOfStudies []string `json:"field_of_studies"` Limit int32 `json:"limit"` Page int32 `json:"page"` }
期望接收的JSON请求体:
{ "name":"", "field_of_studies": ["1", "2", "3"], "limit": 10, "page": 1 }
解决方法
1. 修改SQL查询的IN子句为ANY语法
PostgreSQL支持使用= ANY($2)接收数组参数,sqlc会自动将其映射为Golang的[]string类型。修改后的SQL需添加sqlc必要注释:
-- name: SearchMajors :many SELECT mou."id", mou."name", mou.description, mou.img_url, um.favorite FROM majors_of_universities mou JOIN field_of_studies fos ON mou.field_of_studies_id = fos."id" JOIN univ_major um ON mou."id" = um.majors_of_universities_id WHERE mou."name" ILIKE $1 AND fos."name" = ANY($2) ORDER BY mou."name" LIMIT $3 OFFSET $4;
2. 处理分页参数转换
请求体中的page从1开始,需计算OFFSET值:offset = (page - 1) * limit,在Golang代码中完成计算后传入sqlc生成的函数。
3. Golang调用示例
// 解析请求体到SearchMajorReq var req SearchMajorReq if err := json.NewDecoder(r.Body).Decode(&req); err != nil { // 处理解析错误 } // 处理空数组场景(避免PostgreSQL报错,可根据业务调整) if len(req.FieldOfStudies) == 0 { req.FieldOfStudies = []string{""} } // 计算分页偏移量 offset := (req.Page - 1) * req.Limit // 调用sqlc生成的查询函数 majors, err := db.SearchMajors(ctx, db.SearchMajorsParams{ Name: "%" + req.Name + "%", // 补全LIKE通配符 FieldOfStudies: req.FieldOfStudies, Limit: req.Limit, Offset: offset, }) if err != nil { // 处理查询错误 }
4. 验证参数类型
sqlc生成的SearchMajorsParams结构体中,FieldOfStudies会自动匹配为[]string类型,与SearchMajorReq的字段完全兼容,解决类型不匹配问题。
内容的提问来源于stack exchange,提问作者Adhitya Resadikara
相关产品推荐
相关产品推荐

