简体   繁体   English

Golang db 查询使用 slice IN 子句

[英]Golang db query using slice IN clause

Can someone explain to me why this does not work?有人可以向我解释为什么这不起作用吗?

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)

And this does这确实

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)

I'm trying to do a simple IN clause with a slice of ints, and every solution suggested doesn't seem very idiomatic我正在尝试用一个整数切片做一个简单的 IN 子句,并且建议的每个解决方案似乎都不太惯用

Tried to do this, but the problem appears to be the string substitution.试图这样做,但问题似乎是字符串替换。

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

I'm a bit surprised that go doesn't seem to have a graceful way to handle this query.我有点惊讶 go 似乎没有一种优雅的方式来处理这个查询。

Because database/sql does not inspect your query and it passes your arguments directly to the driver, it makes dealing with queries with IN clauses difficult:由于 database/sql 不会检查您的查询,而是将您的参数直接传递给驱动程序,因此很难处理带有 IN 子句的查询:

SELECT * FROM users WHERE level IN (?);

When this gets prepared as a statement on the backend, the bindvar ?当它准备好作为后端的语句时, bindvar ? will only correspond to a single argument, but what is often desired is for that to be a variable number of arguments depending on the length of some slice将只对应一个参数,但通常需要的是根据某个切片的长度,它是可变数量的参数

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

There is a way to handle these types of queries using sqlx package which provide more control over database queries.有一种方法可以使用sqlx处理这些类型的查询, sqlx提供对数据库查询的更多控制。

This pattern is possible by first processing the query with sqlx.In:这种模式可以通过首先使用 sqlx.In 处理查询来实现:

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

For more information Go through Godoc for InQueries有关更多信息,请访问 Godoc for InQuery

If you have been careful to build your inq string from real ints (to avoid injection), you can just build the string yourself and avoid using ?:如果您小心地从真实整数构建您的 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)

If you do it a lot, better to have a WhereIn function that does this for you, or use an orm.如果您经常这样做,最好有一个 WhereIn 函数为您执行此操作,或者使用 orm。 Be careful which args you accept though, as if you accept arbitrary strings anything could be injected.但是请注意您接受哪些参数,就好像您接受任意字符串一样可以注入任何内容。

You need the number of "?"您需要“?”的数量in the "IN" clause to match the number of arguments , so you need to do something like this:在“IN”子句中匹配参数的数量,所以你需要做这样的事情:

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM