I'm attempting to perform a migration to split a "questions" table into two tables: "campaigns" and "campaign_actions" where the campaign contains the question title and the campaign action references the question id via a question_id column and then newly created campaign via a campaign_id column.
I've tried returning the fields from the initial select using the as
keyword and also into
. All the examples I'm seeing are inserting into multiple tables with values. I'm having trouble correlating the newly created campaign id with the existing question id for insert into the "campaign_actions" table. I've tried several things but here's my most recent attempt:
WITH campaign_questions AS (
INSERT INTO "campaigns" (name, tenant_id)
SELECT
q.title as name,
q.tenant_id as tenant_id
FROM "questions" as q
RETURNING
id into campaign_id,
q.id into question_id,
q.app_area_id into app_area_id
)
INSERT INTO "campaign_actions" (campaign_id, question_id, app_area_id)
SELECT campaign_id, question_id, app_area_id,
FROM campaign_questions
Some other thing's I've thought about doing: adding a temporary column on campaigns to hold the question_id and the app_area_id so I can return them from the insert and then use them to populate the campaign_actions table and then drop the columns.
Here are the DBML of the questions, campaigns, and campaign actions tables:
table questions {
id uuid [pk, unique, default: `uuid_generate_v4()`]
app_area_id uuid [ref: > app_areas.id]
tenant_id text [not null]
title text [not null]
subtitle text
type text [not null]
data jsonb
// Timestamps
created_at timestamp [not null, default: `now()`]
updated_at timestamp [not null, default: `now()`]
deleted_at timestamp
indexes {
tenant_id [type: btree]
}
}
table campaigns {
id uuid [pk, unique, default: `uuid_generate_v4()`]
tenant_id text [not null]
name text [not null]
description text
start_at timestamp
end_at timestamp
paused_at timestamp
closed_at timestamp
published_at timestamp
// Timestamps
created_at timestamp [not null, default: `now()`]
updated_at timestamp [not null, default: `now()`]
deleted_at timestamp
indexes {
tenant_id [type: btree]
}
}
table campaign_actions {
id uuid [pk, unique, default: `uuid_generate_v4()`]
tenant_id text [not null]
campaign_id uuid [not null, ref: > campaigns.id]
type text [not null, default: "question"]
question_id uuid [ref: > questions.id]
display_type text
app_area_id uuid [ref: > app_areas.id]
// Timestamps
created_at timestamp [not null, default: `now()`]
updated_at timestamp [not null, default: `now()`]
deleted_at timestamp
indexes {
tenant_id [type: btree]
campaign_id [type: btree]
question_id [type: btree]
}
}
I assume there is a better way or I'm missing something. Any help is appreciated!
The following query associates the campaign and question IDs by generating the campaign IDs prior to performing the insert:
WITH id_pairs AS
(SELECT uuid_generate_v4() AS campaign_id,
id AS question_id
FROM questions),
campaign_inserts AS
(INSERT INTO campaigns (id, name, tenant_id)
SELECT id_pairs.campaign_id, questions.title, tenant_id
FROM questions
JOIN id_pairs
ON questions.id = id_pairs.question_id)
INSERT
INTO campaign_actions (campaign_id, question_id, app_area_id)
SELECT id_pairs.campaign_id, questions.id, questions.app_area_id
FROM questions
JOIN id_pairs
ON questions.id = id_pairs.question_id;
The campaign_inserts CTE is basically a label for the insert into campaigns: it's never used.