SnowflakeのUDFやPROCEDUREでdefaultを使う

 DBManiaです。
 弊社がSnowflake社のData Drivers Awards 2023にて、Data Driver of the Yearを受賞してから初の更新となります。

 Snowflakeに新機能としてUDFとPROCEDUREにオプション引数が実装されました。

 この機能の何が凄いのか、具体例で説明したいと思います。

作成するFUNCTIONの仕様

 日付と経過日数を指定すると、指定した日付から指定した経過日数の「YYYY年MM月DD日」という文字列を返すFUNCTIONを作る。
 ただし、日付を指定しない場合は本日を、日数を指定しなければ当日の文字列を返す。

-- (2023-11-17での)出力例
SELECT GET_JAPANESE_DATE_TEXT('2023-11-01'::DATE,5);
-- 2023年11月06日
SELECT GET_JAPANESE_DATE_TEXT()
-- 2023年11月17日

よくあるFUNCTIONですね。

今までの実装方法

 これを実装しようとすると、今までは以下のようにオーバーロードされた4つのFUNCTIONを作成する必要がありました。

-- 両方の引数を持つGET_JAPANESE_DATE_TEXT(TARGET_DATE DATE,DAY_COUNT INTEGER)を作り、実装する
CREATE FUNCTION GET_JAPANESE_DATE_TEXT
  (TARGET_DATE DATE,DAY_COUNT INTEGER)
RETURNS TEXT
LANGUAGE SQL
AS
$$
  TO_VARCHAR(DATEADD(DAY,DAY_COUNT,TARGET_DATE), 'YYYY年MM月DD日')
$$;
-- 日付の引数を持つGET_JAPANESE_DATE_TEXT(TARGET_DATE DATE)を作り、内部でGET_JAPANESE_DATE_TEXT(TARGET_DATE,0)を呼び出す
CREATE FUNCTION GET_JAPANESE_DATE_TEXT
  (TARGET_DATE DATE)
RETURNS TEXT
LANGUAGE SQL
AS
$$
  GET_JAPANESE_DATE_TEXT(TARGET_DATE,0)
$$;

-- 経過日数の引数を持つGET_JAPANESE_DATE_TEXT(DAY_COUNT INTEGER)を作り、内部でGET_JAPANESE_DATE_TEXT(CURRENT_DATE(),DAY_COUNT)を呼び出す
CREATE FUNCTION GET_JAPANESE_DATE_TEXT

  (DAY_COUNT INTEGER)
RETURNS TEXT
LANGUAGE SQL
AS
$$
  GET_JAPANESE_DATE_TEXT(CURRENT_DATE(),DAY_COUNT)
$$;

-- 引数のないGET_JAPANESE_DATE_TEXT()を作り、内部でGET_JAPANESE_DATE_TEXT(CURRENT_DATE(),0)を呼び出す
CREATE FUNCTION GET_JAPANESE_DATE_TEXT()
RETURNS TEXT
LANGUAGE SQL
AS
$$
  GET_JAPANESE_DATE_TEXT(CURRENT_DATE(),0)
$$;
新機能での書き方

 DEFAULT機能によって、たった1つのFUNCTIONを作れば、すべてが実装できるようになりました。

 実際のコードはこちらです。

CREATE FUNCTION GET_JAPANESE_DATE_TEXT
  (TARGET_DATE DATE DEFAULT CURRENT_DATE(),DAY_COUNT INTEGER DEFAULT 0)
RETURNS TEXT
LANGUAGE SQL
AS
$$
  TO_VARCHAR(DATEADD(DAY,DAY_COUNT,TARGET_DATE), 'YYYY年MM月DD日')
$$;

 とてつもなくシンプルになりました。
 元のコードで引数が2つのFUNCTIONとの違いは、引数にキーワードDEFAULTと、そのときの値が記述されているだけです。
 これにより、引数を渡さなかった場合はDEFAULTで指定された値(日付ならCURRENT_DATE(),経過日数なら0)が自動的に使用されます。

-- (2023-11-17での)出力例
SELECT GET_JAPANESE_DATE_TEXT('2023-11-01'::DATE,5);
-- 2023年11月06日
SELECT GET_JAPANESE_DATE_TEXT()
-- 2023年11月17日

 ただし、経過日数だけを指定したいというケースでは若干の注意が必要です。
 単純に

SELECT GET_JAPANESE_DATE_TEXT(5);

と記述した場合、”無効な関数「GET_JAPANESE_DATE_TEXT」の引数型: (NUMBER(1,0))”というようなエラーが出ます。
 これはFUNCTION上、第一引数の日付のほうに5を入れようとした、とみなされたためです。
 これを避ける機能も、実は少し前にSnowflakeに実装されています。
 それが、引数のアロー指定です。
 アロー指定では、”引数名 => 値"という記述をすることで、PROCEDUREやFUNCTIONの特定の引数に値を代入できる機能です。
 これを使うと

SELECT GET_JAPANESE_DATE_TEXT
  (DAY_COUNT =>5, TARGET_DATE =>'2023-11-01'::DATE);

という具合にFUNCTIONやPROCEDUREで定義された引数の順番どおりに値を入れなくて済むようになったのですが、この機能自体はあまり使い道がありませんでした。
 しかし、今回の機能拡張と組み合わせると

-- (2023-11-17での)出力例
SELECT GET_JAPANESE_DATE_TEXT(DAY_COUNT =>5);
-- 2023年11月22日

と、第2引数だけを指定できるようになり、やっとその効果を発揮できるようになりました。

まとめ

  • FUNCTIONやPROCEDUREの引数にデフォルト値を指定することで、引数指定を省略できるようになり、オーバーロードを減らすことができるようになりました。
  • 第2引数のみ指定して実行したいといったときは引数のアロー指定で行います。