DatabricksジョブにおけるSQLタスク実行結果の動的参照

こちらのアップデートです。

https://docs.databricks.com/aws/en/release-notes/product/2025/april#reference-sql-output-in-downstream-tasks-of-a-job

> **ジョブにおける下流タスクでのSQL出力の参照**
>
> 同じジョブの下流タスクで、SQLタスクの出力を参照するために動的な値を使えるようになりました。For eachタスクでは、出力のデータの行に対してイテレーションを行うことができます。
>
> [動的値参照とは](https://docs.databricks.com/aws/ja/jobs/dynamic-value-references)をご覧ください。 

マニュアルの当該箇所はこちらの**SQL出力オプション**です。

https://docs.databricks.com/aws/ja/jobs/dynamic-value-references#sql-%E5%87%BA%E5%8A%9B%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3

# SQLタスクの作成

この機能の肝は、動的参照する先のタスクは**SQLタスク**である必要があることです。SQLノートブックのタスクの場合、動的参照はできません。

以下のようなクエリーを作成して、SQLタスクとしてジョブに追加します。

```sql
-- 例データを生成
CREATE OR REPLACE TEMP VIEW example_sales AS
SELECT * FROM VALUES
  (2020, 12),
  (2021, 23),
  (2022, 47),
  (2023, 15),
  (2024, 22)
AS example_sales(sales_year, num_sales);

-- 例データをクエリ
SELECT sales_year, num_sales FROM example_sales;
```

![Screenshot 2025-04-17 at 13.26.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/e8007486-ff07-4066-a875-db3958b33716.png)

# 後段のタスクの作成

Pythonノートブックから参照してみます。SQLタスクの実行結果は以下のような**文字列**となります。

```
'[{"sales_year":"2020","num_sales":"12"},{"sales_year":"2021","num_sales":"23"},{"sales_year":"2022","num_sales":"47"},{"sales_year":"2023","num_sales":"15"},{"sales_year":"2024","num_sales":"22"}]'
```

このままではリストとしてアクセスできないので、以下のように`eval`を入れています。

```py
result = eval(dbutils.widgets.get("sql_result"))
display(result)
```

これを後段のタスクとして設定すると、前段のSQLタスク`sales_by_year`の動的参照のリストに`output`が含まれています。これらがSQLタスクの結果にアクセスするための動的参照となります。ここでは、`tasks.sales_by_year.output.rows`をキー`sql_result`で参照できるようにします。

![Screenshot 2025-04-17 at 12.58.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/7cab59f4-3aab-4a4a-8603-853f5f6b22dc.png)

![Screenshot 2025-04-17 at 13.30.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/8c382527-41e6-49ab-8b25-31ed1477b599.png)

これで、SQLタスクの結果にアクセスできました。

![Screenshot 2025-04-17 at 13.31.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/73f4718a-68a5-4988-b239-950d46a44ae4.png)

# For eachタスクからのアクセス

> `For each`タスクでは、行はネストされたタスクに繰り返し送信されます。この例では、For each **タスクの入力** を `{{tasks.sales_by_year.output.rows}}` に設定すると、ネストされたタスクで、構文 `{{input.<column_alias>}}` を使用して、行の値をパラメーターとして繰り返し送信できます。ネストされたタスク構成では、キーと値のペア `year:{{input.sales_year}}` と `sales:{{input.num_sales}}` を使用して 2 つのパラメーターを作成できます。 ネストされたタスクが SQL タスクであると仮定すると、次のようなクエリを使用してコード内の値を参照できます。

言葉だけだと理解が難しいので、実際に設定してみます。

## クエリーの設定

SQLタスクの出力の各行を読み込むクエリーを作成します。

```sql
-- 例: 前のクエリからデータにアクセスする:
SELECT concat(:year, ' 年の売り上げは ', :sales, ' でした。')
```

## タスクの設定

`それぞれ(For Each)`タスクを選択し、パラメータとして`{{tasks.sales_by_year.output.rows}}`を設定します。

![Screenshot 2025-04-17 at 13.18.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/2b322d6f-7c54-46ae-beb8-b9f340d75cc7.png)

繰り返すタスクとして上のクエリーを選択したSQLタスクを作成し、クエリーで参照しているパラメータを以下のように設定します:

- **year**: `{{input.sales_year}}`
- **sales** `{{input.num_sales}}`

![Screenshot 2025-04-17 at 13.19.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/e4945aef-ee32-430f-9610-656d8c7392d2.png)

これでFor Eachタスクが追加されました。

![Screenshot 2025-04-17 at 13.19.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/d20b8c73-d929-49c0-8ce4-a99d87e8426d.png)

実行すると、ループごとの結果が正しく表示されていることを確認できます。

![Screenshot 2025-04-17 at 13.20.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/f1691082-dddb-413a-9613-88d09e995a91.png)
![Screenshot 2025-04-17 at 13.20.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/45c980bf-65bf-44d4-8eb8-e28382d666ad.png)
![Screenshot 2025-04-17 at 13.58.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/6a0dc953-d369-43a2-aac2-5866c8a6d1d9.png)

このように、クエリーの結果をテーブルに永続化させることなく後段のタスクで参照できます。ご活用ください！

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)