見出し画像

SQLBoilerのクエリ構築 - 複数カラムに対応したWHERE IN句の使い方

テクノロジーセクション プロダクト開発部の岩瀬です。
弊社では Go言語でシステムの開発を行っており、ORM は SQLBoiler( https://github.com/volatiletech/sqlboiler ) を使っています。
SQLBoiler は多くのメリットがある反面、いくつか独特な使い方があったので、今回はその共有をしたいと思います。


はじめに

SQLBoiler は、Go言語における ORM(Object-Relational Mapping)ライブラリです。主な利点は、データベーススキーマに基づいて自動生成されるコードによって、データベースとのやり取りをシンプルかつ型安全に実現できる点です。さらに、SQLBoiler の Query Mod System を活用すれば、複雑なSQLクエリを柔軟に構築することができます。
私は実際に使っていく中で、WHERE IN句の複数カラムの指定方法が独特で戸惑いました。
本記事では、この WHERE IN句の構築方法に焦点を当て、具体的な使い方を解説することで、SQLBoiler の特性を活かしたクエリ構築の方法を紹介します。

本記事の留意点

  • SQLBoiler によって生成されたモデルが modelsパッケージに配置されているとして説明します

  • クエリの構築に github.com/volatiletech/sqlboiler/v4/queries/qmパッケージを使用しています

クエリ構築の基礎

SQLBoiler では、クエリの構築・実行を StarterQuery ModFinisher の3つの要素を使って行います。

1. Starter: クエリを開始するためのメソッドです。データを取得するテーブルやモデルを指定します。例えば、以下のように書きます。

query := models.Users(/* Query Mod をここに指定する */)

2. Query Mod: クエリに条件や修飾を追加するためのメソッドです。これにより、取得するデータをフィルタリングしたり並び替えたりすることができます。例えば、Where や OrderBy などのメソッドを使って条件を指定できます。

mods := []qm.QueryMod{
    qm.Select(models.UserColumns.Name, models.UserColumns.Age)
}

query := models.Users(mods...)

このコードは、Usersテーブルから name と ageカラムを選択するクエリを生成しています。 カラム名やテーブル名は、SQLBoiler によって自動的に定義されたものを使うと良いです。

3. Finisher: クエリの実行を行うメソッドです。これにより実際にデータを取得します。

mods := []qm.QueryMod{
qm.Select(models.UserColumns.Name, models.UserColumns.Age)
}
users, err := models.Users(mods...).All(ctx, db)

Finisher は、取得したいデータの形式をもとに選択します。

  • One(): 1件取得 (LIMIT(1)と同じ)

  • All(): 全て取得

  • Count(): 件数を取得

  • Bind(&myObj): 独自に定義した型で取得

基本的な WHERE IN の書き方

単一カラムに対する WHERE INクエリの基本的な記述方法を確認します。以下のように記述することができます。qmパッケージに WhereIn の QueryMod を生成するメソッドが用意されています。第1引数に ”カラム名 IN ?” を指定します。第2引数以降に取得したい値を指定します。

mods := []qm.QueryMod{
    qm.WhereIn(
        fmt.Sprintf("%s IN ?", models.UserColumns.Name),
        "Alice", "Brian", "Chris"
    )
}

users, err := models.Users(mods...).All(ctx, db)

これにより以下のようなクエリの条件文が生成されます。

WHERE ("name") IN (($1,$2,$3))

また、今回の例のように単一のカラムを取得するクエリである場合、自動生成でモデル内に定義されたメソッドを使用するともっとシンプリに記述できます。

mods := []qm.QueryMod{
    models.UserWhere.Name.IN([]string{"Alice", "Brian", "Chris"})
}

users, err := models.Users(mods...).All(ctx, db)

複数カラムに対する WHERE IN の使い方

複数のカラムに対して WHERE IN句を使用する際には、いくつかポイントに留意する必要があります。

  • プレースホルダー(?)は一つだけ記載し、カラムをカッコで囲んで指定します。

  • 値はフラットな interface{} に展開して指定します。

以下は、複数カラムに対する WHERE INクエリの具体的な例です。

mods := []qm.QueryMod{
    qm.WhereIn(
        fmt.Sprintf("(%s, %s) IN ?", models.UserColumns.Name, models.UserColumns.Sex),
        "Alice", "Male", "Brian", "Female"
    )
}

users, err := models.Users(mods...).All(ctx, db)

このコードでは、Name と Sex の2つのカラムに対して、特定の値を持つレコードを取得しています。これにより以下のようなクエリの条件文が生成されます。プレースホルダーの部分は指定したカラム数に応じて自動的にカッコで囲んでくれます。

WHERE ("name","age") IN (($1,$2),($3,$4))

より実践的な条件の生成部分も含めたコードは以下のようになります。

// 条件を設定
userConditions := []struct {
    Name string
    Sex string
}{
    {"Alice", "Female"},
    {"Bob", "Male"},
}

// 引数リストを生成
var queryArgs []interface{}
for _, condition := range userConditions {
    queryArgs = append(queryArgs, condition.Name, condition.Sex)
}

// Query Modを生成
queryMods := []qm.QueryMod{
    qm.WhereIn(
        fmt.Sprintf("(%s, %s) IN ?", models.UserColumns.Name, models.UserColumns.Sex),
        queryArgs...,
    ),
}

// クエリを実行
users, err := models.Users(queryMods...).All(ctx, db)

このようにして、複数のカラムに対する条件を設定することができます。

まとめ

本記事では、SQLBoiler を使用した複数カラムに対する WHERE INクエリの記述方法を解説しました。SQLBoiler を活用したデータ取得の参考になればと思います。

▼株式会社テックオーシャン 中途採用募集ポジションはこちらから


いいなと思ったら応援しよう!