Snowflakeスクリプトの書き方

に公開

概要

Snowflakeスクリプトの基本的な書き方と実用例を説明します。
SQLは書けるけど、Snowflakeスクリプトは書いたことのない方向けの内容となります。

説明すること

  • Snowflakeスクリプトの全体の構造
  • DECLAREブロックとBEGINブロックの書き方
  • カーソルの概要
  • リザルトセットの概要
  • FOR文(カーソルベース)の書き方

https://docs.snowflake.com/ja/developer-guide/snowflake-scripting/index

Snowflakeスクリプトとは

複数のSQL文を実行し、変数、条件分岐、ループなどのプログラミング的な処理を記述できる機能です。
SQLだけでは表現が難しい複雑なデータ処理やバッチ更新等を実施したいケースで有用です。

まずは全体像をつかむために、簡単な例を紹介します。
詳しい説明は後のセクションでおこないます。

サンプルコード
-- 売上データから条件に応じて処理する完全な例
DECLARE
    total_sales NUMBER DEFAULT 0;
    high_value_count NUMBER DEFAULT 0;
    cur CURSOR FOR SELECT amount FROM sales WHERE sale_date = CURRENT_DATE();
BEGIN
    FOR record IN cur DO
        total_sales := total_sales + record.amount;
        IF (record.amount > 1000) THEN
            high_value_count := high_value_count + 1;
        END IF;
    END FOR;
    
    RETURN '本日の売上合計: ' || total_sales || '円、高額取引: ' || high_value_count || '件';
END;

Snowflakeスクリプトの構造

スクリプトは大きく3つのブロックで構成されています。

  • DECLAREブロック: 変数やカーソルを宣言(省略可能)
  • BEGINブロック: メインの処理を記述(必須)
  • EXCEPTIONブロック: エラー処理を記述(省略可能)
スクリプト構造
DECLARE
  -- 変数やカーソルなどを宣言
BEGIN
  -- メインとなる処理(SQLやスクリプト)を記載
EXCEPTION
  -- 例外処理を記載
END;

https://docs.snowflake.com/ja/developer-guide/snowflake-scripting/blocks

DECLAREブロック

変数やカーソル、リザルトセット等を使用する場合は、このブロックで宣言します。

  • 変数
    変数を使用する前に、宣言をする必要があります。
    変数の宣言
    DECLARE
        update_stmt varchar(2000);          --サンプル1
        profit number(38, 2) DEFAULT 0.0;   --サンプル2
    BEGIN
    ...
    

https://docs.snowflake.com/ja/developer-guide/snowflake-scripting/variables

  • カーソル
    カーソルを使用することで、BEGINブロックのなかでクエリ結果を1行ずつ取り出して反復処理することができます。
    宣言にはクエリが含まれます。
    カーソルの宣言
    DECLARE
        c1 CURSOR FOR SELECT price FROM invoices;                     --サンプル1
        cur CURSOR FOR SELECT col1 from table1 where col2 is null;    --サンプル2
    BEGIN
    ...
    

https://docs.snowflake.com/ja/developer-guide/snowflake-scripting/cursors

  • リザルトセット
    リザルトセット(RESULTSET)はクエリの結果セットを格納するデータ型です。
    カーソルを使用することでリザルトセットを反復処理することができます。
    リザルトセットの宣言
    DECLARE
        res RESULTSET;                                                      --サンプル1
        res RESULTSET DEFAULT (SELECT col1 FROM mytable ORDER BY col1);     --サンプル2
    BEGIN
    ...
    

https://docs.snowflake.com/ja/developer-guide/snowflake-scripting/resultsets

BEGINブロック

BEGIN と END の間のブロックに、SQLやSnowflakeスクリプトを記述します。

BEGINブロックの例
BEGIN
  CREATE TABLE table1 (id INTEGER, ...);
  UPDATE table2 SET col1 = 'value1' WHERE col2 is not NULL;
END;
  • カーソル
    カーソルはOPENコマンドを使用することで、クエリが実行され結果がカーソルに格納されます。
    処理の完了後に、CLOSEコマンドを実行してカーソルを閉じます。

    カーソルの使用例
    DECLARE      
        cur CURSOR FOR SELECT col1 from table1 where col2 is null;
    BEGIN
        OPEN cur;
        -- 処理を記述
        CLOSE cur;
    END;
    
  • リザルトセット
    クエリをリザルトセットに割り当てることで実行することができます。
    リザルトセットや変数の代入では、:= を使用します。

    リザルトセットの使用例
    DECLARE
        res RESULTSET;
    BEGIN
        res := (SELECT col1 FROM mytable ORDER BY col1);
    END;
    

    動的なSQL文字列を作成し実行する場合は、EXECUTE IMMEDIATEオプションを使用します。

    リザルトセット(EXECUTE IMMEDIATE)の使用例
    DECLARE
        res RESULTSET;
        col_name varchar(100);
        update_statement varchar(1000);
    BEGIN
        col_name := 'col1';
        update_statement := 'update table1 set ' || col_name || ' = 1';
        res := (EXECUTE IMMEDIATE :update_statement);
    END;
    
  • FORループ
    FORループの回数は、ユーザーが直接指定するか、カーソルの行数で指定することができます。

    FORループ(回数指定)の使用例
    DECLARE
        sum INTEGER DEFAULT 0;
        maximum_count INTEGER default 10;
    BEGIN
        FOR i IN 1 TO maximum_count DO
            sum := sum + i;
        END FOR;
        RETURN sum;
    END;
    
    FORループ(カーソルベース)の使用例
    DECLARE
        update_stmt varchar(2000);
        res RESULTSET;      
        cur CURSOR FOR SELECT col1 from table1 where col2 is null;
    BEGIN
        OPEN cur;
        FOR each_row IN cur DO
            update_stmt := 'update table1 set col1 = 1 ' ||
                'where col2 = ' || each_row.col1 || ';'
            res := (EXECUTE IMMEDIATE :update_stmt);
        END FOR;
        CLOSE cur;
    END;
    

https://docs.snowflake.com/ja/developer-guide/snowflake-scripting/loops

おわりに

今回はSnowflakeスクリプトの書き方を紹介しました。
ストアドプロシージャやユーザ定義関数のなかで、SQLだけでは処理が困難なケースで利用する機会が多いのかなと感じました。
今回は基本的な書き方を整理しましたが、例外処理等の紹介を省略した内容についても今後理解していきたいと思います。

最後までお読みいただきありがとうございました。

Discussion