[Go] 关于 SQL 中 IN 子句参数的传递
在Go中使用GORM操作数据库的时候,它的IN
子句是支持直接使用切片作为参数的。比如:
names := []string{"one", "two", "three"}
db.Where("name IN (?)", names)
这样使用时,IN
子句的?
被绑定到整个切片上,GORM内部会自动根据参数的个数把问号转换成对应的个数,这会带来极大的便利。比如上面的name IN (?)
会在内部被替换成name IN (?,?,?)
。
但是,GO语言原生的SQL不支持这么做。它的每一个?
只绑定一个参数。所以在使用原生SQL的IN子句的时候,需要动态计算问号的个数。
原生的Query
查询语句是这样的:
func Query(query string, args ...interface{}) (*sql.Rows, error)
query
里面有多少个?
,args
的个数就得多少个。
假设我们要这样一个查询(IN的参数个数不确定):
SELECT * FROM users_tab WHERE name IN ('one','two','three')
首先,我们需要知道参数的个数,求出问号的个数:
func CreateQuestionMarks(n int) string {
s := "?"
for i := 1; i < n; i++ {
s += ",?"
}
return s
}
第二,Query
的args
是[]interface{}
,但由于Go不支持把非interface切片自动转换成interface切片,所以这一步也得手动来做:
func ConvertToInterfaces(slice []string) []interface{} {
s := make([]interface{}, len(slice))
for i, v := range slice {
s[i] = v
}
return s
}
最后,完成Query
的调用:
query := fmt.Sprintf("SELECT * FROM users_tab WHERE name IN (%s)", CreateQuestionMarks(len(names)))
args := ConvertToInterfaces(names)
rows, err := db.Query(query, args...)
总之,这个过程很艰辛。