使用slice IN子句的Golang db查询

wgmfuz8q  于 2023-05-11  发布在  Go
关注(0)|答案(4)|浏览(111)

有人能解释一下为什么这不起作用吗?

inq := "6,7" //strings.Join(artIds, ",")
rows, err = db.Query("SELECT DISTINCT title FROM tags_for_articles LEFT JOIN tags ON tags.id = tags_for_articles.tag_id WHERE article_id IN (?)", inq)

而这个

rows, err = db.Query("SELECT DISTINCT title FROM tags_for_articles LEFT JOIN tags ON tags.id = tags_for_articles.tag_id WHERE article_id IN (6,7)", inq)

我尝试用一个int片段来创建一个简单的IN子句,但建议的每个解决方案似乎都不太符合习惯用法
尝试这样做,但问题似乎是字符串替换。

inq := strings.Join(artIds, ",")

我有点惊讶,go似乎没有一种优雅的方式来处理这个查询。

s8vozzvw

s8vozzvw1#

因为database/sql不检查你的查询,而是直接将参数传递给驱动程序,所以处理带有IN子句的查询很困难:

SELECT * FROM users WHERE level IN (?);

当这在后端准备为一条语句时,bindvar?将只对应于一个参数,但通常需要的是,根据某个切片的长度,参数的数量是可变的

var levels = []int{4, 6, 7}
rows, err := db.Query("SELECT * FROM users WHERE level IN (?);", levels)

有一种方法可以使用sqlx package来处理这些类型的查询,它提供了对数据库查询的更多控制。
这种模式可以通过首先使用sqlx处理查询来实现。

var levels = []int{4, 6, 7}
query, args, err := sqlx.In("SELECT * FROM users WHERE level IN (?);", levels)

有关更多信息,请访问Godoc for InQueries

vh0rcniy

vh0rcniy2#

你要的是“的号码?“来匹配参数的数量,所以你需要这样做:

inq := "6,7" //strings.Join(artIds, ",")
qms := strings.Repeat("?,", len(inq))
qms = params[:len(params)-1] // remove the trailing ","

rows, err = db.Query("SELECT DISTINCT title FROM tags_for_articles LEFT JOIN tags ON tags.id = tags_for_articles.tag_id WHERE article_id IN (" + qms + ")", inq)
dhxwm5r4

dhxwm5r43#

如果你已经很小心地从真实的的int构建你的inq字符串(以避免注入),你可以自己构建字符串,避免使用?:

inq := "6,7" 
sql := fmt.Sprintf("SELECT DISTINCT title FROM tags_for_articles LEFT JOIN tags ON tags.id = tags_for_articles.tag_id WHERE article_id IN (%s)",inq)
rows, err := db.Query(sql)

如果你做了很多,最好有一个WhereIn函数来为你做这件事,或者使用一个orm。不过要小心接受哪些参数,就像接受任意字符串一样,任何东西都可以被注入。

jmo0nnb3

jmo0nnb34#

我只是遇到了同样的问题,然后我想出了另一个更安全的解决方案。所以,你不需要知道SQL注入。

params := []string{"A", "B"}
jsonParams, err := json.Marshal(params)
if err != nil {
    return err
}

rows, err = db.Query(`
 WITH compared_values as(
   SELECT * 
     FROM JSON_TABLE(
      ?,
      "$[*]" COLUMNS( 
       value TEXT PATH "$"
     )
   ) as compared_values
 ) 
 SELECT * FROM target_table
 WHERE target_value IN (SELECT value FROM compared_values);
`, jsonParams)

你也可以像这样在SQL查询中使用纯选择部分,但我不确定性能如何。我认为使用WITH cause可以防止重复解析JSON。

SELECT * FROM  target_table
 WHERE target_value IN (
   SELECT value FROM JSON_TABLE(
     ?,
     "$[*]" COLUMNS( 
       value TEXT PATH "$"
     )
   ) as compared_values
  );

相关问题