【dbt】dbt ~ 更新 / DROP + CTAS ~

■ はじめに

https://dk521123.hatenablog.com/entry/2023/12/07/060129

の続き。

今回は、DROP + CTAS(CREATE TABLE AS SELECT)
について、深堀っていく

目次

【1】DROP & CTAS
【2】構文
【3】Tips
 1)load_relation
【4】実際には何を行なっているのか?
 1)処理フロー・概要

【1】DROP & CTAS

* DROP + CTAS(CREATE TABLE AS SELECT)
 => 俗言う「洗い替え」
 => 実際には、DROP+CREATEしているわけではなく
  CREATE -> BACKUP -> RENAME -> DROP BACKUP
  (詳細は、「【4】実際には何を行なっているのか?」を参照)

【2】構文

{{
    config(
        materialized='table'
    )
}}

【3】Tips

1)load_relation

* materialized='incremental' の時に、
 初回か初回じゃないかを判定するために is_incremental()を使ったが、
 materialized='table'では、load_relation() を使うといい

dbt Macro ~ load_relation ~
https://dk521123.hatenablog.com/entry/2025/09/02/000214

* 以下の関連記事でサンプルがある

dbt ~ materialized='incremental'で前データを使用したい場合 ~
https://dk521123.hatenablog.com/entry/2025/09/04/000906

【4】実際には何を行なっているのか?

https://dk521123.hatenablog.com/entry/2025/09/04/000906

のサンプルコードに対して、
dbt run 実行時に、DEBUGログにして、
dbtが裏で何を行なっているのか確認する

 => 実際には、DROP+CREATEしているわけではなく
  CREATE -> BACKUP -> RENAME -> DROP BACKUP

dbt 〜 生成されるSQL文を確認する 〜
https://dk521123.hatenablog.com/entry/2024/08/25/002741

# dbt run --log-level DEBUG
dbt run --log-level DEBUG > output.txt

1)処理フロー・概要

Step1: TMPテーブル(user_full__dbt_tmp)で作る
Step2: 元テーブル(user_full)を
 バックアップ(user_full__dbt_backup)としてリネームする
Step3: TMPテーブル(user_full__dbt_tmp)を
 対象テーブル(user_full)としてリネームする
Step4: コミット
Step5: バックアップ(user_full__dbt_backup)をDrop

Debug log

[0m12:17:44  On model.my_project.user_full: BEGIN
[0m12:17:44  Opening a new connection, currently in state closed
[0m12:17:44  SQL status: BEGIN in 0.021 seconds
[0m12:17:44  Using postgres connection "model.my_project.user_full"
[0m12:17:44  On model.my_project.user_full: /* {"app": "dbt", "dbt_version": "1.9.0", "profile_name": "my_project", "target_name": "dev", "node_id": "model.my_project.user_full"} */

★Step1: TMPテーブル(user_full__dbt_tmp)で作る
create  table "dbt_db"."public"."user_full__dbt_tmp"
    as  
  (
WITH
FULL_TABLE AS (
        SELECT * FROM "dbt_db"."public"."user_full"    
),
USER_TABLE AS (
    SELECT * FROM "dbt_db"."public"."user"
),
USER_PII AS (
    SELECT * FROM "dbt_db"."public"."user_pii"
),
FINAL_TABLE AS (
    SELECT
    COALESCE(u.user_id, pi.user_id) AS user_id,
    COALESCE(pi.name, f.name) AS name,
    COALESCE(u.gender, f.gender) AS gender,
    COALESCE(pi.email, f.email) AS email,
    COALESCE(u.remarks, f.remarks) AS remarks
    FROM
    USER_TABLE AS u
    FULL OUTER JOIN
    USER_PII AS pi
    ON
    u.user_id = pi.user_id
    LEFT OUTER JOIN
    FULL_TABLE AS f
    ON
    u.user_id = f.user_id
    OR pi.user_id = f.user_id
)

SELECT * FROM FINAL_TABLE
  );
  
[0m12:17:44  SQL status: SELECT 7 in 0.034 seconds
[0m12:17:44  Using postgres connection "model.my_project.user_full"
★Step2: 元テーブル(user_full)を
 バックアップ(user_full__dbt_backup)としてリネームする
[0m12:17:44  On model.my_project.user_full: /* {"app": "dbt", "dbt_version": "1.9.0", "profile_name": "my_project", "target_name": "dev", "node_id": "model.my_project.user_full"} */
alter table "dbt_db"."public"."user_full" rename to "user_full__dbt_backup"
[0m12:17:44  SQL status: ALTER TABLE in 0.001 seconds
[0m12:17:44  Using postgres connection "model.my_project.user_full"
★Step3: TMPテーブル(user_full__dbt_tmp)を
 対象テーブル(user_full)としてリネームする
[0m12:17:44  On model.my_project.user_full: /* {"app": "dbt", "dbt_version": "1.9.0", "profile_name": "my_project", "target_name": "dev", "node_id": "model.my_project.user_full"} */
alter table "dbt_db"."public"."user_full__dbt_tmp" rename to "user_full"
[0m12:17:44  SQL status: ALTER TABLE in 0.000 seconds
★Step4: コミット
[0m12:17:44  On model.my_project.user_full: COMMIT
[0m12:17:44  Using postgres connection "model.my_project.user_full"
[0m12:17:44  On model.my_project.user_full: COMMIT
[0m12:17:44  SQL status: COMMIT in 0.001 seconds
★Step5: バックアップ(user_full__dbt_backup)をDrop
[0m12:17:44  Applying DROP to: "dbt_db"."public"."user_full__dbt_backup"
[0m12:17:44  Using postgres connection "model.my_project.user_full"
[0m12:17:44  On model.my_project.user_full: /* {"app": "dbt", "dbt_version": "1.9.0", "profile_name": "my_project", "target_name": "dev", "node_id": "model.my_project.user_full"} */
drop table if exists "dbt_db"."public"."user_full__dbt_backup" cascade
[0m12:17:44  SQL status: DROP TABLE in 0.003 seconds
[0m12:17:44  On model.my_project.user_full: Close

関連記事

dbt ~ 基礎知識編 ~
https://dk521123.hatenablog.com/entry/2023/06/30/000000
dbt ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/05/30/151003
dbt ~ 基本編 / Source ~
https://dk521123.hatenablog.com/entry/2023/12/08/111012
dbt ~ 更新 / 基礎知識編 ~
https://dk521123.hatenablog.com/entry/2023/12/07/060129
dbt ~ 更新 / Update or Insert ~ / Insert
https://dk521123.hatenablog.com/entry/2023/12/19/224453
dbt ~ 更新 / Delete and Insert ~
https://dk521123.hatenablog.com/entry/2023/12/20/000104
dbt ~ materialized='incremental'で更新前データを使用したい場合 ~
https://dk521123.hatenablog.com/entry/2025/09/04/000906
dbt Macro ~ load_relation ~
https://dk521123.hatenablog.com/entry/2025/09/02/000214