#概要
エンジニア1年目の初投稿です。
sqlxを使ってDB操作をしていたら、下記のエラーに悩まされたので記録します。
コメント、ダメ出しなど頂けると嬉しいです。
converting argument $1 type: unsupported type []string, a slice of string
シナリオ
SELECT文のWHERE句にIN条件を使った操作を行おうとしていたところ、エラーに嵌まりました。
今回は,以下のUSERテーブルからgoとpythonを使えるUSERを抽出する操作を書いていきます。
Name | Skill |
---|---|
Ichiro | C |
Jiro | C# |
Saburo | Java |
Shiro | python |
Goro | go |
Rokuro | Ruby |
Shichiro | go |
各種ツール
- go 1.14
- github.com/jmoiron/sqlx v1.2.0
- github.com/go-sql-driver/mysql v1.5.0
- mysql:5.7
- VSCode(1.50.1)
#ダメだったコード
query := "SELECT Name,Skill FROM USER WHERE Skill IN (?,?);"
searchSkills := []string{"go", "python"}
var records []User
err := db.Select(&records, query, searchSkills)
if err != nil {
log.Fatal(err)
}
//converting argument $1 type: unsupported type []string, a slice of string
db.Selectにパラメータとして、[ ]stringを渡します。
コンパイルが通るのでうまくいくかと思いきや,掲題のエラーが発生します。
ちなみに、第三引数をsearchSkills...
にするとコンパイルが通りません。
#どうしたか
エラーメッセージ的に引数で渡している型が良くないってのはなんとなく分かります。
とりあえず、ドキュメントを読んでみる。
https://godoc.org/github.com/jmoiron/sqlx#DB.Select
第三引数がinterface{}
の可変長引数だったため、[]interface{}
を展開して投げてみます。
query := "SELECT Name,Skill FROM USER WHERE Skill IN (?,?)"
// searchSkills := []string{"go", "python"}
searchSkills := []interface{}{"go", "python"}
var records []User
err := db.Select(&records, query, searchSkills...)
if err != nil {
log.Fatal(err)
}
// Name:Jiro,Skill:go
// Name:Saburo,Skill:go
// Name:Goro,Skill:python
エラーの発生は抑えられてやりたいことも出来てます。
でも、あんまりスマートじゃないですね...。
抽出条件によって?
の数変えなきゃいけないってのがよろしくない。
[ ]interface{}で定義しているのもなんとなく違和感...。
sqlx.In
便利なのがありました。
sqlxに用意されているIn( )関数を使うともっとスマートに出来ます。
func In(query string, args ...interface{}) (string, []interface{}, error)
https://godoc.org/github.com/jmoiron/sqlx#In
queryBase := "SELECT Name,Skill FROM USER WHERE Skill IN (?)"
searchSkills := []string{"go", "python"}
query, param, err := sqlx.In(queryBase, searchSkills)
if err != nil {
log.Fatal(err)
}
var records []User
err = db.Select(&records, query, param...)
if err != nil {
log.Fatal(err)
}
// Name:Jiro,Skill:go
// Name:Saburo,Skill:go
// Name:Goro,Skill:python
In( )関数に土台となるSQL文とパラメータに使いたいスライスを渡すことで,スライスの要素数に合わせて、プレースホルダの数を調節したクエリを作ってくれます。
あとは、[]interface{}
になったparam
と一緒にdb.Select()
に渡せば、In条件を使った検索ができます。
これなら、抽出条件の数もパラメータの型も気にする必要がなくなりそうです。
素晴らしい。
ちなみに、In( )関数に要素数が0のスライスを渡すと、下記のエラーが発生するので注意が必要です。
empty slice passed to 'in' query
#参考
golang: sql: converting argument $1 type: unsupported type []int32, a slice of int32