两个SELECT之间的区别

时间:2013-05-10 16:26:47

标签: sql-server tsql

我有一张这样的表:

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。

所以,我正在尝试删除模板ID不是(158,159)的所有行。为了做到这一点,我试图选择所有不是引用目标的行(即没有其他行的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

临时表方法似乎捕获了额外的错误行,这就是它无法进行参照完整性检查的原因。为什么他们会产生不同数量的行?

2 个答案:

答案 0 :(得分:2)

使用第一种方法将非(158, 159)模板分隔为临时表后,您不再需要查看(158, 159)模板了。但是,正如数据所示,某些非(158, 159)模板必须是某些(158, 159)的父项。第一种方法不会过滤掉它们,而第二种方法则会过滤掉它们。

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

答案 1 :(得分:1)

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

的WHERE子句中