ABEJA Tech Blog

中の人の興味のある情報を発信していきます

よく使うRDBMSのUDF・ストアドプロシージャのまとめ

はじめに

こんにちは。株式会社ABEJAの@Takayoshi_maです。InfoQを見ているとこのようなニュースが掲載されていました。

www.infoq.com

どうやらMySQLでストアドファンクション・ストアドプロシージャを作成する際に新しくJavaScriptを使うことができるようになるそうです。私は普段BigQueryを触っているのですが、その際UDFにJavaScriptを使うことも多く、そう言った面からもこの機能がMySQLに実装されることは結構便利になるのでは?と思っているところです。 そこで、実は今回のブログではこの新しい機能を使ってみた系の話題を書こうかなと思ったのですが、よくよく記事を見てみると「現在プレビュー中で、MySQL Enterprise EditionとMySQL Heatwaveでのみ利用」とのことで、、、 エンタープライズ版は敷居が高そう、一方Heatwaveであれば調査した感じAWSでちょっとだけ試すこともできなくもなさそうですが、Oracle側に課金することになるためそちら側のアカウント作成も必要云々とそれなりに手間がかかりそうだと思ったので、今回は一周回って、それぞれのRDBMSにおいてこの辺どうなってるんだっけ?といった情報をまとめてみようかなと思います。 いきなり企画倒れ感ありますがよろしくお願いします。

まとめ

それぞれを見てく前に先に結論だけ一覧表にしています。

※ 補足 SQLiteでも、直接のUDF作成機能は提供していないが、組み込みを行うアプリケーションのホスト言語を通じてUDFを定義・使用することが可能。そのため多くの言語でudfの登録が可能。SQLエンジンは必要な時点で外部のランタイム(Pythonランタイムや、C/C++コードがコンパイルされたバイナリ)環境にコントロールを渡し、UDFの実行結果を受け取る。対象言語の数自体も多くなってしまうので一覧表からは省略

MySQL PostgreSQL Oracle SQLServer
SQL ◯ (ストアドファンクション)
PL/pgSQL
PL/SQL
T-SQL
JavaScript △ (一部プラン) ◯ (PL/V8)
Python ◯ (PL/Python) ◯ (ML Services)
Perl ◯ (PL/Perl)
Java ◯ (PL/Java)
C
Tcl ◯ (PL/Tcl)
Ruby ◯ (PL/Ruby,非公式?)
PHP ◯ (PL/PHP,非公式?)
Lua ◯ (PL/Lua,非公式?)
R ◯ (ML Services)

ちょっと試してみる

この一覧表を載せただけだと、テックブログとしてあまりにボリュームが無さすぎるので、一応いくつか試してみます。

  • docker composeを使ってローカル環境に各DBのコンテナを起動しています。
  • Oracleはライセンスの関係上、SQLServerはコンテナイメージが思ったより大きい&僕自身が全く触れたことが無いこともあり、試していません。

MySQL

シンプルな関数ですが、以下のように定義することが可能です。

delimiter //
CREATE FUNCTION classify_number(num INT) RETURNS VARCHAR(10)
DETERMINISTIC
BEGIN
    DECLARE result VARCHAR(10);

    IF num < 10 THEN
        SET result = 'Small';
    ELSEIF num < 100 THEN
        SET result = 'Middle';
    ELSE
        SET result = 'Large';
    END IF;

    RETURN result;
END;
//

[実行結果]

PostgreSQL

色々な言語で定義できるのが特徴です。以下のように実行できました。尚、MySQL時に接続を作るのが手間でターミナルから直接ログインしていましたが、それはそれでSQL書くのが面倒だったのでここからはDBeaverをクライアントツールとして使用しています。

CREATE OR REPLACE FUNCTION classify_number(num INT) RETURNS VARCHAR(10)
AS $$
BEGIN
    IF num < 10 THEN
        RETURN 'Small';
    ELSIF num < 100 THEN
        RETURN 'Middle';
    ELSE
        RETURN 'Large';
    END IF;
END;
$$ LANGUAGE plpgsql;

[実行結果]

なお、前述の通りPostgreSQLはPL/hogeを導入することで様々な言語で関数の定義が可能です。

SQLite

前述の通り、SQLiteでは、コマンドラインツールやSQL内で直接作成するのではなく、SQLiteを組み込んだアプリケーション内でプログラミング言語を使用して定義します。

import sqlite3


# データベースに接続
conn = sqlite3.connect('mydatabase.db')

# カーソルの作成
c = conn.cursor()


def classify_number(num):
    if num < 10:
        return 'Small'
    elif num < 100:
        return 'Middle'
    else:
        return 'Large'


# Python関数をSQLiteのUDFとして登録
conn.create_function("classify_number", 1, classify_number)

# UDFを使用するSQLクエリの実行
c.execute("SELECT classify_number(38)")
print(c.fetchone())

# コネクションのクローズ
conn.close()

[実行結果]

さいごに

We Are Hiring! ABEJAは、テクノロジーの社会実装に取り組んでいます。 技術はもちろん、技術をどのようにして社会やビジネスに組み込んでいくかを考えるのが好きな方は、下記採用ページからエントリーください!

careers.abejainc.com