## What — pre-hook を使うべきではない理由
要するに、処理が `.sql` と `.yml` の2箇所に散るのが問題。重複排除のような前処理は、そのモデルのSQLファイルの中に置いた方が読める。
- **デバッグが困難**: エラーが発生した際に原因の特定が難しい
- **予期しない副作用**: 実行タイミングが分かりにくく、予期しない動作を引き起こす可能性
- **テストが困難**: pre-hookの動作をテストするのが難しい
- **可読性の低下**: SQLファイルを見ただけでは、pre-hookの存在に気づけない
なお `source`(sources.yml)にはそもそも `pre-hook` を定義できない。
## How — 代替3手
重複排除は QUALIFY句と ROW_NUMBER() を使うのがいちばん短い(BigQueryの場合)。処理を切り離したいときは方法3の中間モデルにする。
**方法1: QUALIFY句とROW_NUMBER()を使用(推奨)**
```sql
-- sample_model.sql
SELECT *
FROM {{ source('raw_data', 'raw_data') }}
QUALIFY ROW_NUMBER() OVER (PARTITION BY id ORDER BY _load_ts DESC) = 1
```
**方法2: CTEとウィンドウ関数を使用**
```sql
WITH ranked_data AS (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY _load_ts DESC) AS rn
FROM {{ source('raw_data', 'raw_data') }}
)
SELECT *
FROM ranked_data
WHERE rn = 1
```
**方法3: 中間モデルを作成して処理を分離**
```sql
-- staging/raw_data_deduplicated.sql
SELECT *
FROM {{ source('raw_data', 'raw_data') }}
QUALIFY ROW_NUMBER() OVER (PARTITION BY id ORDER BY _load_ts DESC) = 1
```
```sql
-- staging/sample_model.sql
SELECT *
FROM {{ ref('raw_data_deduplicated') }}
WHERE condition = 1
```
> [!warning] もしpre-hookを使わざるを得ない場合
> 基本的には避けるべきだが、やむを得ない場合のみ。必ずコメントで理由を明記する・ドキュメントに記録する・チームメンバーと相談する。
## 関連
- [[データ基盤]]
- [[dbtのYAMLファイルの書き方手順]] — source と model の使い分け・基本構造
- [[BigQueryのウィンドウ関数]] — 方法1・2で使う `ROW_NUMBER()` の側