49963


お世話になります。

scala + scalikejdbc を使っていますが、次のようなSQLをQueryDSLに直す場合の  
処理がいまいちわかりません。

[code]

    SELECT
        a.id, a.date, a.code, b.score
    FROM
        source as a
    LEFT JOIN
        data as b 
        ON b.code = a.code 
        AND b.date = (
            select date from data where code = a.code order by date desc limit 1
        )
    
[/code]

のような書き方になった場合、最後の３行の

[code]

        AND b.date = (
            select date from data where code = a.code order by date desc limit 1
        )
    
[/code]

部分がどのように表現したらよいかわかりません。

[code]

    select(a.result.id, a.result.date, a.result.code, b.result.score)
        .from(source as a)
        .leftJoin(data as b).on(
             sqls.eq(b.code, a.code).and.eq(b.date, ？？？？？)
        )
    
[/code]

という感じのようになるとおもうのですが、？？？？ の部分を記述しようとおもったところ  
ここで分からなくなってしまっています。

初心者すぎる質問で申し訳ないのですが、どなたか教えていただけないでしょうか？

よろしくお願いいたします。


CC BY-SA 4.0
2018-11-04T09:13:21.303
49950
2018-11-04T18:02:28.687
30835
question
scala scalikejdbc
scalikejdbcでサブクエリの書き方


ご存知の通り、Join句のonを指定するメソッドは2つ用意されていて、複数の条件を書く場合は、`on(onClause:
SQLSyntax)`の方を使用する必要があります。

[scalikejdbc/QueryDSLFeature.scala#L412-L420](https://github.com/scalikejdbc/scalikejdbc/blob/3.3.1/scalikejdbc-
interpolation/src/main/scala/scalikejdbc/QueryDSLFeature.scala#L412-L420)

[code]

    def on(onClause: SQLSyntax): SelectSQLBuilder[A] = {
      if (ignoreOnClause) this.copy(ignoreOnClause = false)
      else this.copy(sql = sqls"${sql} on ${onClause}", ignoreOnClause = false)
    }
    
    def on(left: SQLSyntax, right: SQLSyntax): SelectSQLBuilder[A] = {
      if (ignoreOnClause) this.copy(ignoreOnClause = false)
      else this.copy(sql = sqls"${sql} on ${left} = ${right}", ignoreOnClause = false)
    }
    
[/code]

`sqls.eq()`のvalueにサブクエリを渡す場合は`SQLSyntax`を渡す必要があり、QueryDSL(`SQLBuilder`)をそのままは渡せません。

[scalikejdbc/interpolation/SQLSyntax.scala#L291](https://github.com/scalikejdbc/scalikejdbc/blob/3.3.1/scalikejdbc-
core/src/main/scala/scalikejdbc/interpolation/SQLSyntax.scala#L291)

[code]

      def eq[A: ParameterBinderFactory](column: SQLSyntax, value: A): SQLSyntax = SQLSyntax.empty.eq(column, value)
    
[/code]

[scalikejdbc/ParameterBinderFactory.scala#L99](https://github.com/scalikejdbc/scalikejdbc/blob/3.3.1/scalikejdbc-
core/src/main/scala/scalikejdbc/ParameterBinderFactory.scala#L99)

[code]

      implicit val sqlSyntaxParameterBinderFactory: ParameterBinderFactory[SQLSyntax] = new ParameterBinderFactory[SQLSyntax] { def apply(value: SQLSyntax) = SQLSyntaxParameterBinder(value) }
    
[/code]

ただし`SQLBuilder`は`.sql`メソッドで`SQLSyntax`に変換できます。

`sqls.eq()`に書いたサブクエリ(`SQLSyntax`)は括弧で囲まれないので、`sqls.roundBracket()`を使って括弧で囲まれるようにしておくのが良いかと思います。

[code]

    select(
        a.result.id,
        a.result.date,
        a.result.code,
        b.result.score
    )
        .from(source as a)
        .leftJoin(data as b).on(
            sqls.eq(b.code, a.code).and
                .eq(
                     b.date,
                     sqls.roundBracket(
                         select(b.date)
                             .from(data as b)
                             .where.eq(b.code, a.code)
                             .orderBy(b.date).desc
                             .limit(1)
                             .sql
                     )
                )
        )
    
[/code]

また、[SQLInterpolation](http://scalikejdbc.org/documentation/sql-
interpolation.html)で書いてしまう方法もあります。

[code]

    select(
        a.result.id,
        a.result.date,
        a.result.code,
        b.result.score
    )
        .from(source as a)
        .leftJoin(data as b).on(
             sqls"""${b.code} = ${a.code} AND
                   |${b.date} = (
                   |  SELECT ${b.date}
                   |  FROM ${data as b}
                   |  WHERE ${b.code} = ${a.code}
                   |  ORDER BY ${b.date} DESC
                   |  LIMIT 1
                   |)""".stripMargin
        )
    
[/code]


CC BY-SA 4.0
2018-11-04T15:41:57.043
49963
2018-11-04T18:02:28.687
2018-11-04T18:02:28.687
3068
3068
49950
answer