本日18:30より4共14にて例会があります。部員による講座の内容は"SQL はチューリング完全"です。
— 京大マイコンクラブ (@KMC_JP) 2016年10月20日
今日の KMC の例会講座で、こういう発表をしたので、話したことをざっくりまとめておきます。SQL はチューリング完全なので、 DB 問い合わせだけじゃなくていろいろなコードが書けるよみたいな話です。
使用環境は SQLite3 です。
SQL プログラミングの方法
文字列を出力したい
これはかなり単純で、
SELECT 'Hello, world!';
のようにしてやればよい。
文字列を結合したい
||
演算子で文字列を結合できる。
SELECT 0 || ' is a natural number';
条件分岐をしたい
CASE WHEN を使えば実現できる。
SELECT '5 is ' || CASE WHEN 5 % 2 = 0 THEN 'even' ELSE 'odd' END
繰り返し処理をしたい
たとえば、C++ でいうところの
for (int i = 0; i < 100; ++i) { std::cout << i << std::endl; }
のようなことをしたいときには、WITH 句を使って、次のように記述する。
WITH RECURSIVE cnt(x) AS ( SELECT 0 UNION ALL SELECT x+1 FROM cnt LIMIT 100 ) SELECT x FROM cnt;
関数を定義したい
SQL の本来の意味での関数は(すくなくとも SQLite では)定義できないけど、ここでも WITH 句が使える。
次の例では、10 % 4
を計算して出力する。
WITH args(n, k) AS ( SELECT 10, 4 ), cmod(result) AS ( SELECT (n % k) FROM args ) SELECT n || ' % ' || k || ' = ' || result FROM args, cmod;
cmod
が関数(のようなもの)で、args
がそれに渡される引数である。
そもそも WITH 句は、副問い合わせに別名をつけておくみたいな機能なので、 cmod(result)
の result
は引数じゃなくてカラム名を表している。
そのため、SELECT result FROM cmod
のようにして結果を取得する必要がある。
プログラムを実行したい
cat hoge.sql | sqlite3
のようなコマンドを叩けば実行できる。
また、手元に環境がない場合でも、(Wandbox)http://melpon.org/wandbox/ や (ideone)https://ideone.com/ といったオンラインの実行環境を使うことができる。
SQL プログラムの例
FizzBuzz
WITH RECURSIVE cnt(x) AS ( SELECT 1 UNION ALL SELECT x + 1 FROM cnt LIMIT 100 ), fizzbuzz(x) AS ( SELECT CASE WHEN x % 3 = 0 THEN 'Fizz' ELSE '' END || CASE WHEN x % 5 = 0 THEN 'Buzz' ELSE '' END || CASE WHEN x % 5 != 0 AND x % 3 != 0 THEN x ELSE '' END FROM cnt ) SELECT x FROM fizzbuzz;
自力で書いたのでもっとうまい方法があるかもしれない。行ベースなので勝手に改行してくれて便利。
その他の例
公式のドキュメント にいろいろな例があって、
などが実際に実装されている。
まとめ
SQL はプログラミング言語として使えるし、実際そのように使っている例もある。 また、本来はデータベースに問い合わせるための言語であるので、データベースと連携したプログラミングが、何の外部モジュールもなくても実現できる。
欠点として、見通しが悪いとか、標準入力を受け取る方法が分からないとか、いろいろあるので、その辺りは今後の展望という感じ。やっていきましょう。