我试图使用
pq driver对Go中的Postgresql数据库执行以下查询:
SELECT COUNT(id) FROM tags WHERE id IN (1,2,3)
其中1,3在切片标签处传递:= [] string {“1”,“2”,“3”}.
我尝试了很多不同的东西,比如:
s := "(" + strings.Join(tags,",") + ")" if err := Db.QueryRow(` SELECT COUNT(id) FROM tags WHERE id IN $1`,s,).Scan(&num); err != nil { log.Println(err) }
这导致pq:语法错误在“$1”或附近.我也试过了
if err := Db.QueryRow(` SELECT COUNT(id) FROM tags WHERE id IN ($1)`,strings.Join(stringTagIds,"),).Scan(&num); err != nil { log.Println(err) }
这也失败了pq:整数的输入语法无效:“1,3”
我也尝试直接传递一片整数/字符串并得到sql:转换Exec参数#0的类型:不支持的type []字符串,一个切片.
那么如何在Go中执行此查询?
预构建SQL查询(防止sql注入)
如果您为每个值生成带有param占位符的sql字符串,则可以更轻松地立即生成最终sql.
请注意,由于值是字符串,因此存在sql注入攻击的位置,因此我们首先测试所有字符串值是否确实是数字,我们只在这样做:
tags := []string{"1","2","3"} buf := bytes.NewBufferString("SELECT COUNT(id) FROM tags WHERE id IN(") for i,v := range tags { if i > 0 { buf.WriteString(",") } if _,err := strconv.Atoi(v); err != nil { panic("Not number!") } buf.WriteString(v) } buf.WriteString(")")
执行它:
num := 0 if err := Db.QueryRow(buf.String()).Scan(&num); err != nil { log.Println(err) }
使用任何
您也可以使用Postgresql’s ANY
,其语法如下:
expression operator ANY (array expression)
使用它,我们的查询可能如下所示:
SELECT COUNT(id) FROM tags WHERE id = ANY('{1,3}'::int[])
在这种情况下,您可以将数组的文本形式声明为参数:
SELECT COUNT(id) FROM tags WHERE id = ANY($1::int[])
这可以简单地像这样构建:
tags := []string{"1","3"} param := "{" + strings.Join(tags,") + "}"
请注意,在这种情况下不需要检查,因为数组表达式不允许sql注入(但会导致查询执行错误).
那么完整的代码:
tags := []string{"1","3"} q := "SELECT COUNT(id) FROM tags WHERE id = ANY($1::int[])" param := "{" + strings.Join(tags,") + "}" num := 0 if err := Db.QueryRow(q,param).Scan(&num); err != nil { log.Println(err) }