golangにはsqlxというdatabase/sql
の拡張機能を提供するライブラリがあります。
このライブラリはSelectクエリを発行する際に同時にstructへ結果をマッピングしてくれる機能を提供しており非常に便利なのですが、READMEを見てみると名前付きクエリを発行しつつ、structへのマッピングする方法が書かれていません。
※MySQLだとsql.Named
が利用出来ないため、名前付きクエリを実現するにはこのようなライブラリに頼る必要があります。
structへのマッピングを行うクエリ
type User struct {
NameA string `db:"name_a"`
NameB string `db:"name_b"`
}
query := `SELECT * FROM users WHERE name_a = ? OR name_b = ?`
var user User
// 同じ名前を重複して指定しないといけない。
if err := sqlx.Get(&user, query, "Tom", "Tom"); err != nil {
log.Print(err)
}
REAMEで紹介されている名前付きクエリの実行方法
query := `SELECT * FROM users WHERE name_a = :name OR name_b = :name`
// 名前付きクエリを発行する機能はあるものの、結果がsql.Rowsで返ってきてしまう…
rows, err = db.NamedQuery(query, map[string]interface{}{"name": "Tom"})
じゃあ方法が無いのかと言うとそういうわけではなくsqlx.Named
という機能が提供されており、これを利用することでstructへのマッピングと名前付きクエリをあわせて行えるようになります。
query := `SELECT * FROM users WHERE name_a = :name OR name_b = :name`
bindParams := map[string]interface{}{
"name": "Tom",
}
// sqlx.Namedを利用すると、名前付きパラメタが?に置換され、それに対応するバインドパラメタのsliceが返される
query, params, err := sqlx.Named(query, bindParams)
if err != nil {
log.Print(err)
}
log.Print(query) // SELECT * FROM users WHERE name_a = ? OR name_b = ?
log.Print(params) // ["Tom" "Tom"]
var user User
if err := sqlx.Get(&user, query, params...); err != nil {
log.Print(err)
}