Go使用lib/pq驱动实现PostgreSQL多列IN/ANY查询问题求助
问题原因
你遇到的input of anonymous composite types is not implemented报错,是因为lib/pq驱动原生不支持直接传入PostgreSQL匿名复合类型的数组,所以不能直接复用单字段ANY的写法传二维数组做多列匹配。
可行解决方案
方案1:拆分双列并行数组,配合unnest展开匹配(无需改数据库结构,推荐)
原理是把要匹配的col1、col2值分别存到两个长度相同的一维数组里,在SQL层用unnest把两个数组按顺序展开为行组成匹配元组。
SQL示例:
SELECT * FROM t1 WHERE (col1, col2) IN ( SELECT unnest($1::varchar[]), unnest($2::varchar[]) );
对应的Go实现代码:
import ( "github.com/lib/pq" "database/sql" ) // 要匹配的元组列表 tuples := [][]string{{"c11", "c12"}, {"c21", "c22"}} // 拆分两个顺序对应的数组 col1List := make([]string, 0, len(tuples)) col2List := make([]string, 0, len(tuples)) for _, t := range tuples { col1List = append(col1List, t[0]) col2List = append(col2List, t[1]) } // 执行查询 rows, err := conn.Query(` SELECT * FROM t1 WHERE (col1, col2) IN ( SELECT unnest($1::varchar[]), unnest($2::varchar[]) ) `, pq.Array(col1List), pq.Array(col2List)) if err != nil { // 自行处理错误 } defer rows.Close()
方案2:动态生成占位符(适合匹配元组数量少的场景)
如果每次查询的匹配元组数量可控,可以动态拼接IN子句的占位符,扁平化传参:
import ( "fmt" "strings" "database/sql" ) tuples := [][]string{{"c11", "c12"}, {"c21", "c22"}} args := make([]interface{}, 0, len(tuples)*2) placeholders := make([]string, 0, len(tuples)) for i, t := range tuples { placeholders = append(placeholders, fmt.Sprintf("($%d,$%d)", i*2+1, i*2+2)) args = append(args, t[0], t[1]) } sql := fmt.Sprintf("SELECT * FROM t1 WHERE (col1, col2) IN (%s)", strings.Join(placeholders, ",")) rows, err := conn.Query(sql, args...) // 后续自行处理结果和错误
方案3:自定义数据库复合类型(适合频繁做这类查询的场景)
首先在PostgreSQL中创建固定的复合类型:
CREATE TYPE col_pair AS (col1 varchar(20), col2 varchar(20));
然后在Go层定义对应结构体实现driver.Valuer接口,即可直接传该类型的数组做匹配:
import ( "github.com/lib/pq" "database/sql" "database/sql/driver" "fmt" ) type ColPair struct { Col1 string Col2 string } // 实现driver.Valuer接口,适配PostgreSQL复合类型输入格式 func (p ColPair) Value() (driver.Value, error) { return fmt.Sprintf("(%s,%s)", pq.QuoteLiteral(p.Col1), pq.QuoteLiteral(p.Col2)), nil } // 调用代码 pairs := []ColPair{{"c11", "c12"}, {"c21", "c22"}} rows, err := conn.Query(` SELECT * FROM t1 WHERE (col1, col2) = any($1::col_pair[]) `, pq.Array(pairs)) // 后续自行处理结果和错误
内容的提问来源于stack exchange,提问作者Chayan Ghosh
相关产品推荐
相关产品推荐

