1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Kotlinのsplitを使って複数クエリのSQLファイルを実行する方法

Last updated at Posted at 2021-03-08

前回に引き続きKotlinでsqlファイルを実行する実装を模索しています。
またしても学びごとがあったので記しておきます。

こちらの続きでSpringBootを利用しています。

利用してるgradleの設定、Repositoryクラス諸々も、前回の記事と同様のものを使っています。

今回やりたいこと

例えば以下のようなSQLファイルを実行した結果をそれぞれ出力したい。

test.sql
select count(1) from staff; --1件ある
select count(1) from food; --3件ある

つまりファイル中の複数のcountクエリをそれぞれ実行して、結果を取得したい。

やったこと

  • splitの挙動について
  • 正規表現で区切り文字を含む方法

これらを踏まえてやりたいことを叶えていきます。

splitの挙動について

;区切りで文字列を取得する場合、Java同様こんなイメージをしていました。

val list = "aaa;bbb;ccc;".split(";")
println(list)
println(list.size)

出力結果はこうなりました。

[aaa, bbb, ccc, ]
4

一番後ろの;で区切った時の空文字列分の値が入っちゃってますね。

Javaでは

Javaでは第二引数に0を設定すると末尾の空文字列が廃棄されます。
しかし、、

Kotlinでは

when the limit is not specified or specified as 0, this function doesn't drop trailing empty strings from the result.

末尾の空文字列は除去しませんよとご丁寧に書いてありました。

結論:JavaとKotlinのsplitの挙動は違う

ので、手動で空文字列を消すことにしました。
以下末尾の空文字列を根こそぎ消すというもの。

    val list = "aaa;bbb;ccc".split(";")
    println(list.dropLastWhile { it.isBlank() })
    println(list.size)

出力結果

[aaa, bbb, ccc]
3

こんなに簡単に書けるなんて。Kotlinすばら。

正規表現で区切り文字を含む方法

今回はSQLの区切り文字である;を含めたかったので
以下のような正規表現を使うことにしました。

Regex("(?<=;)")

直前に;がある文字列を表す正規表現です。

Regexにもsplit関数が用意されているようなのでこれを使います。

Stringのsplit同様、第二引数で空文字列を除去することはできませんでした。

val reg = Regex("(?<=;)")
print(reg.split("aaa;bbb;ccc;", 0))

出力結果

[aaa;, bbb;, ccc;, ]

まとめて適用して実行する

以下のようにServiceクラスにこれらを実装していきます。

SakuraService.kt
@Service
class SakuraService {

    /**
       SQLファイル内のクエリを実行する
       @param ファイルパス
       @return SQLクエリ文字列のリスト
     */
    fun getSqlQueryList(filepath:String):List<String>{
        val fileString = Files.readString(Paths.get(filepath))

        //区切り文字を含む文字列を取得するための正規表現
        val reg = Regex("(?<=;)")
        
        //Kotlinのsplitは末尾空白列除去オプションがないため手動で削除
        return  reg.split(fileString).dropLastWhile { it.isBlank() }
    }
}

実行するApplicatioクラス、main関数はこんな感じです。

SakuraApplication.kt
package com.example.sakura

import com.example.sakura.repository.SakuraRepository
import com.example.sakura.service.SakuraService
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.jdbc.core.JdbcTemplate
import java.io.File

@SpringBootApplication
class SakuraApplication(val jdbcTemplate: JdbcTemplate) : CommandLineRunner {
    override fun run(vararg args: String?) {
        val service = SakuraService()
        val repository = SakuraRepository(jdbcTemplate)

        //sqlファイルからクエリの一覧を抽出する
        val sqlList = service.getSqlQueryList("src/main/resources/sql/test.sql")

        for (sql in sqlList) {
            println(sql)
            //sql実行結果
            println(repository.count(sql))
        }
    }
}

fun main(args: Array<out String?>) {
	SpringApplication.run(SakuraApplication::class.java, *args)
}

JdbcTemplateについては先の記事に記載してますので参照ください。

実行した出力結果がこちら

select count(1) from staff;
1
select count(1) from food;
3

出来上がり。

最後に

区切り文字の;がなくてもクエリごとに文字列切ってれば実行できたりします。
SQL実行時に区切り文字あった方が安心だよね。っていう気持ちでくっつけてます。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?