我试图像
那样进行查询WITH tmp (parent_id, child_id, parent_val, child_val) AS (
VALUES (...)
),
ins_parent AS (
INSERT INTO parent (parent_id, parent_val)
SELECT DISTINCT parent_id, parent_val FROM tmp
)
INSERT INTO child (child_id, parent_id, child_val)
SELECT child_id, parent_id, child_val FROM tmp
其中有一个从孩子到父母的外键。
我知道CTE不必在主查询之前执行。我担心的是服务器试图在相应的父行之前插入子行。
我认为问题是当FK检查运行时 - 它们是在语句之后运行(在这种情况下应该没问题),还是在每次单独插入之后(在这种情况下这可能会引发错误)?我还没有找到答案。 (我认为FK不是可以推荐的,因为我没有明确地说明这一点。)
如果它可能出错,我认为重写查询以避免它是相当容易的。 (可能会ins_parent
返回parent_id
和... child_val FROM tmp JOIN ins_parent USING (parent_id)
。)但我不应该让它变得比必要的复杂。
答案 0 :(得分:0)
我相信无论CTE执行什么顺序,这都是安全的。我认为我设法让它们无序执行,并且没有看到任何FK错误。
我实际上有两个父表,以及一个看起来更像
的查询WITH tmp (parent1_id, parent2_id, child_id, parents_val, child_val) AS (
VALUES (...)
),
ins_parent1 AS (
INSERT INTO parent1 (parent1_id, parents_val)
SELECT DISTINCT parent1_id, parents_val FROM tmp
)
ins_parent2 AS (
INSERT INTO parent2 (parent2_id, parents_val)
SELECT DISTINCT parent2_id, parents_val FROM tmp
)
INSERT INTO child (child_id, parent1_id, parent2_id, child_val)
SELECT child_id, parent1_id, parent2_id, child_val FROM tmp
当我检查执行计划(EXPLAIN WITH tmp ...
)时,它看起来大致如下:
Insert on child
CTE tmp
-> ...
CTE ins_parent1
-> ...
CTE ins_parent2
-> ...
-> ...
我认为这意味着所有三个CTE都会在插入child
之前执行。
但是我可以重新排序查询以将child
放在CTE中,并parent1
放在外面:
WITH tmp (parent1_id, parent2_id, child_id, parents_val, child_val) AS (
VALUES (...)
),
ins_child AS (
INSERT INTO child (child_id, parent1_id, parent2_id, child_val)
SELECT child_id, parent1_id, parent2_id, child_val FROM tmp
)
ins_parent2 AS (
INSERT INTO parent2 (parent2_id, parents_val)
SELECT DISTINCT parent2_id, parents_val FROM tmp
)
INSERT INTO parent1 (parent1_id, parents_val)
SELECT DISTINCT parent1_id, parents_val FROM tmp
并且执行计划也相应地改变:
Insert on parent1
CTE tmp
-> ...
CTE ins_child
-> ...
CTE ins_parent2
-> ...
-> ...
所以现在我认为child
的CTE会在将任何内容插入parent1
之前执行。
但是我仍然没有得到像这样结构的查询的FK错误,这让我觉得任何执行顺序都是安全的。