データ選択

この章では、ldbcデータセットを使用してデータを選択する方法を説明します。

コレクションへの行の読み込み

最初のクエリでは、低レベルのクエリを目指して、いくつかのユーザーをリストに選択し、最初の数件をプリントアウトしてみましょう。ここにはいくつかのステップがあるので、途中のタイプを記しておきます。

sql"SELECT name FROM user"
  .query[String] // Query[IO, String]
  .to[List] // Executor[IO, List[String]]
  .readOnly(conn) // IO[List[String]]
  .unsafeRunSync() // List[String]
  .foreach(println) // Unit

これを少し分解してみよう。

複数列クエリ

もちろん、複数のカラムを選択してタプルにマッピングすることもできます。

sql"SELECT name, email FROM user"
  .query[(String, String)] // Query[IO, (String, String)]
  .to[List] // Executor[IO, List[(String, String)]]
  .readOnly(conn) // IO[List[(String, String)]]
  .unsafeRunSync() // List[(String, String)]
  .foreach(println) // Unit

クラスへのマッピング

ldbcは、複数のカラムを選択してクラスにマッピングすることもできます。これは、Userクラスを定義して、クエリの結果をUserクラスにマッピングする例です。

case class User(id: Long, name: String, email: String)

sql"SELECT id, name, email FROM user"
  .query[User] // Query[IO, User]
  .to[List] // Executor[IO, List[User]]
  .readOnly(conn) // IO[List[User]]
  .unsafeRunSync() // List[User]
  .foreach(println) // Unit

クラスのフィールドは、クエリのカラム名と一致する必要があります。これは、Userクラスのフィールドがidnameemailであるため、クエリのカラム名がidnameemailであることを意味します。

Selecting Data

Joinなどを使用して複数のテーブルからデータを選択する方法を見てみましょう。

これは、City, Country, CityWithCountryクラスそれぞれを定義して、citycountryテーブルをJoinしたクエリの結果をCityWithCountryクラスにマッピングする例です。

case class City(id: Long, name: String)
case class Country(code: String, name: String, region: String)
case class CityWithCountry(coty: City, country: Country)

sql"""
  SELECT
    city.id,
    city.name,
    country.code,
    country.name,
    country.region
  FROM city
  JOIN country ON city.country_code = country.code
"""
  .query[CityWithCountry] // Query[IO, CityWithCountry]
  .to[List] // Executor[IO, List[CityWithCountry]]
  .readOnly(conn) // IO[List[CityWithCountry]]
  .unsafeRunSync() // List[CityWithCountry]
  .foreach(println) // Unit

クラスのフィールドは、クエリのカラム名と一致する必要があると先ほど述べました。 この場合、Cityクラスのフィールドがidnameであり、Countryクラスのフィールドがcodenameregionであるため、クエリのカラム名がidnamecodenameregionであることを意味します。

Joinを行った場合、それぞれのカラムはテーブル名と共に指定しどのテーブルのカラムかを明示する必要があります。 この例では、city.idcity.namecountry.codecountry.namecountry.regionとして指定しています。

ldbcではこのようにテーブル名.カラム名クラス名.フィールド名にマッピングすることによって、複数のテーブルから取得したデータをネストしたクラスにマッピングすることができます。

Selecting Data

ldbcではJoinを行い複数のテーブルからデータを取得する際に、単体のクラスのみではなくクラスのTupleにマッピングすることもできます。

case class City(id: Long, name: String)
case class Country(code: String, name: String, region: String)

sql"""
  SELECT
    city.id,
    city.name,
    country.code,
    country.name,
    country.region
  FROM city
  JOIN country ON city.country_code = country.code
"""
  .query[(City, Country)]
  .to[List]
  .readOnly(conn)
  .unsafeRunSync()
  .foreach(println)

この例では、CityクラスとCountryクラスをTupleにマッピングしています。

ここで注意したいのが、先ほどと異なりテーブル名.カラム名クラス名.フィールド名にマッピングすること際にテーブル名はクラス名を使用しています。

そのため、このマッピングには制約がありテーブル名とクラス名は等価でなければいけません。つまり、エイリアスなどを使ってテーブル名をcityからcなどに短縮した場合、クラス名もCでなければならない。

case class C(id: Long, name: String)
case class CT(code: String, name: String, region: String)

sql"""
  SELECT
    c.id,
    c.name,
    ct.code,
    ct.name,
    ct.region
  FROM city AS c
  JOIN country AS ct ON c.country_code = ct.code
"""
  .query[(City, Country)]
  .to[List]
  .readOnly(conn)
  .unsafeRunSync()
  .foreach(println)