1

我有一张这样的桌子:

CREATE TABLE navigation_trees (
    id INT NOT NULL PRIMARY KEY,
    parent_id INT NULL,
    template_id NOT NULL
)

因为有一个外键,parent_id 引用同一个表的 id,所以试图删除另一行的 parent_id 引用的行违反了参照完整性。SQL Server 将不允许 ON DELETE CASCADE 因为循环引用级联的(明显)潜力。

因此,我正在尝试删除具有除 ( 158, 159 ) 之外的模板 ID 的所有行。为了做到这一点,我试图选择所有不是引用目标的行(即没有其他行的 parent_id 是该行的 id),删除它们,然后在循环中重复该过程直到没有更多删除。每次删除批次时,任何具有 parent_id 的批次都将在下一次通过时释放参考行。

最初我是用临时表来做这个的,但它似乎仍然违反了约束。这是一个使用两种方法(使用临时表和直接在表本身上)尝试识别要删除的行的查询:

-- method one: temp table for filtering template IDs
SELECT id, parent_id
INTO #navTrees
FROM navigation_trees
WHERE template_id NOT IN ( 158, 159 )

SELECT DISTINCT tnt1.id
INTO #set1
FROM #navTrees AS tnt1
LEFT OUTER JOIN #navTrees AS tnt2 ON tnt1.id = tnt2.parent_id
WHERE tnt2.parent_id IS NULL

-- method two: filtering template IDs directly in the join
SELECT DISTINCT tnt1.id
INTO #set2
FROM navigation_trees AS tnt1
LEFT OUTER JOIN navigation_trees AS tnt2 ON tnt1.id = tnt2.parent_id
WHERE tnt2.parent_id IS NULL
    AND tnt1.template_id NOT IN ( 158, 159 )

SELECT COUNT(*)
FROM #set1
-- Produces: 106023

SELECT COUNT(*)
FROM #set2
-- Produces: 102575

DROP TABLE #navTrees
DROP TABLE #set1
DROP TABLE #set2

临时表方法似乎捕获了额外的错误行,这就是它未能通过引用完整性检查的原因。为什么它们产生不同数量的行?

4

2 回答 2

2

使用第一种方法将非(158, 159)模板分成临时表后,您将不再查看(158, 159)模板。但是,正如数字所示,一些非(158, 159)模板必须是其中一些模板的(158, 159)级。第一种方法不会过滤掉它们,而第二种方法会过滤掉它们。

您仍然可以使用第一种方法,但您需要使用原始集合作为左连接的右侧。或者只是使用第二种单查询方法。

于 2013-05-11T21:24:59.250 回答
1

不同之处在于,在方法二中,tnt2 数据集仍然包含模板 158 和 159。因此,属于这些模板的一些记录可以加入到 tnt1,从而为您提供比方法 1 更多的记录。这在方法一中不会发生,因为这些模板在加入之前已从两组数据(tnt1 和 tnt2)中删除。尝试将此添加到方法 2 的 WHERE 子句中AND tnt2.template_id NOT IN ( 158, 159 )

于 2013-05-10T16:41:29.403 回答