1
0

More than 3 years have passed since last update.

converting argument $1 type: unsupported type []string, a slice of stringに悩まされた話

Posted at

概要

エンジニア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

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0