Snowflakeのタスクって？

# はじめに
Snowflakeのタスクについて勉強したメモです
この記事を読めばSnowflakeのタスクを使いこなせるようになるはず

# タスクとは
何かをトリガーにSQLを実行する機能の1つ
例えばスケジュールをトリガーに設定すれば、毎日AM10:00に処理を実行したいという要望も叶えられる

>タスクは、次に挙げる型の SQL コードのいずれかを実行できます。
・単一の SQL ステートメント
・ストアドプロシージャへの呼び出し
・Snowflakeスクリプト を使用した手続き型ロジック


https://docs.snowflake.com/ja/user-guide/tasks-intro

# 検証してみること

時間起動のタスクが終了したことをトリガーに2つのタスクを起動できるか

▼タスクの関係性
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/0589912c-a420-f42d-311d-bae100e54bb0.png)

## タスクの作成にむけた準備
今回はタスクでプロシージャを呼び出そうと思います。

メインである顧客テーブル(customers)から、IDと項目を取得するプロシージャを用意します。イメージは以下（PRC=プロシージャ）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/c048dcc7-f7da-88f5-c3d6-8eeb55a8f31f.png)

### 事前準備

0\. 検証するために必要なものを揃えます

```sql
--データベース、スキーマ作成
CREATE DATABASE tdb;
CREATE SCHEMA tsc;
--テーブル作成
CREATE TABLE tdb.tsc.customers (
    customer_id INT AUTOINCREMENT PRIMARY KEY,
    first_name STRING,
    last_name STRING,
    email STRING,
    created_at TIMESTAMP
);
--ダミーデータ挿入
INSERT INTO tdb.tsc.customers (first_name, last_name, email, created_at)
VALUES
    ('John', 'Doe', 'john.doe@example.com', CURRENT_TIMESTAMP),
    ('Jane', 'Smith', 'jane.smith@example.com', CURRENT_TIMESTAMP),
    ('Michael', 'Johnson', 'michael.johnson@example.com', CURRENT_TIMESTAMP),
    ('Emily', 'Davis', 'emily.davis@example.com', CURRENT_TIMESTAMP),
    ('David', 'Brown', 'david.brown@example.com', CURRENT_TIMESTAMP);
--テーブルの準備が出来たことを確認
SELECT * from tdb.tsc.customers;
```

1\. テーブル作成
```sql
CREATE TABLE tdb.tsc.getname (customer_id INT,first_name STRING);
CREATE TABLE tdb.tsc.getemail (customer_id INT,email STRING);
CREATE TABLE tdb.tsc.getcreated (customer_id INT,created_at TIMESTAMP);
```
2\.プロシージャの作成

サンプルPRC1のコードが以下です、これを参考にプロシージャを3つ作成します。

```sql
CREATE PROCEDURE tdb.tsc.p_getname()
RETURNS STRING
LANGUAGE SQL
AS
$$
BEGIN
    INSERT INTO tdb.tsc.getname (customer_id, first_name)
    SELECT customer_id, first_name
    FROM tdb.tsc.customers;
    RETURN 'Data inserted into getname table successfully!';
END;
$$;
```
## タスク作成
今回は **時間起動** と **依存関係** の2種類のタスクを用意します。


### 時間起動
起動時間は``SCHEDULE``で設定します。
タスク1は日本時間19:55にPRC1()を呼び出すようにしました。

```sql:
CREATE OR REPLACE TASK tdb.tsc.task1
WAREHOUSE = COMPUTE_WH
SCHEDULE = 'USING CRON 55 19 * * * Asia/Tokyo' 
AS
CALL tdb.tsc.p_getname()
```
スケジュールについては、時間だけでなく週の曜日や月・日を設定する事も可能
```
# __________ minute (0-59)
# | ________ hour (0-23)
# | | ______ day of month (1-31, or L)
# | | | ____ month (1-12, JAN-DEC)
# | | | | _ day of week (0-6, SUN-SAT, or L)
# | | | | |
# | | | | |
  * * * * *
```
https://docs.snowflake.com/ja/sql-reference/sql/create-task

:::note warn
ルートタスク（タスク1）にはスケジュール設定が必要。
逆にタスクグラフの子タスク（タスク2,タスク3）にはスケジュールは設定できない。
:::

### 依存関係
依存関係は``AFTER``で設定します。
タスク2はタスク1が終了したら起動するようにしました。
```sql
CREATE OR REPLACE TASK tdb.tsc.task2
WAREHOUSE = COMPUTE_WH
AFTER tdb.tsc.task1
AS
CALL tdb.tsc.p_getemail()
```

## タスクの状態を確認
```sql
SHOW TASKS;
```
時間起動のタスク1にはスケジュールした日時
依存関係のタスク2,3には先行タスクであるタスク1が設定されていることを確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/62aeb755-03a4-5097-aff9-00ff338a478b.png)


タスクを実行する為には、タスクを有効化する必要がある

::: note warn
※作成しただけでは無効化(suspended)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/5b443461-9ca0-a541-8dbe-0e25d0ad42e8.png)
:::

以下を実行し有効化する
```sql
ALTER TASK tdb.tsc.task3 RESUME;
ALTER TASK tdb.tsc.task2 RESUME;
ALTER TASK tdb.tsc.task1 RESUME;
```
:::note warn
依存関係を持つ場合
タスクの有効化はタスクグラフの子タスク（タスク2,タスク3）から
:::

タスクの状態を確認し状態が`started`になっていることを確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/b8649cc6-4729-1c26-f4e8-2fed71935e70.png)

## タスクの実行
ルートタスクであるタスク1が起動する時間を待ち、時間になったら結果を確認する。

1\. Snowflake画面から確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/b2a844b2-5bc6-0f11-acee-7031a7b313e2.png)

2\.　TASK_HISTORYから確認

予めタイムゾーンを変更しておく

```sql
--アカウントのタイムゾーンを変更する
alter account set timezone = 'Asia/Tokyo';
```

タスクヒストリーを使用し履歴を追います。以下を実行し確認

```sql
SELECT 
    *
FROM 
    TABLE(INFORMATION_SCHEMA.TASK_HISTORY(
        SCHEDULED_TIME_RANGE_START => TO_TIMESTAMP_LTZ('2024-09-04 00:00:00.000 -0000'),
        SCHEDULED_TIME_RANGE_END => TO_TIMESTAMP_LTZ('2024-09-04 23:59:00.000 -0700')
    ));
```
3つのタスク全てが **成功** 
タスク1が完了した後にタスク2、タスク3が起動していることを確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/021ed01f-b665-d8af-4af0-d7e5bfde5762.png)

# 最後に

時間起動のタスクが終了したことをトリガーに2つのタスクを起動できた！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586761/0589912c-a420-f42d-311d-bae100e54bb0.png)

とても便利な機能ですが、タスクに親と子の依存関係を持たせるときは少し複雑になるので注意が必要です！

この記事が誰かの役に立てれば幸いです。