在用于交互式数据子集分析的脚本中,将查询结果存储到临时表中以进行进一步分析通常很有用。
我的许多分析脚本都包含这种结构:
CREATE TABLE #Results (
a INT NOT NULL,
b INT NOT NULL,
c INT NOT NULL
);
INSERT INTO #Results (a, b, c)
SELECT a, b, c
FROM ...
SELECT *
FROM #Results;
在SQL Server中,临时表是连接范围的,因此查询结果会在初始查询执行后持续存在。当我要分析的数据子集计算成本高昂时,我使用这种方法,而不是使用表变量,因为该子集会持续存在于不同批次的查询之间。
脚本的设置部分仅运行一次,随后的查询(
SELECT * FROM #Results
这里是一个占位符)则根据需要运行多次。偶尔,我希望刷新临时表中的数据子集,因此我再次运行整个脚本。其中一种方法是通过将脚本复制到Management Studio中的新查询窗口来创建新连接,但我发现这样很难管理。
相反,我的常规解决方法是在创建语句之前加上一个条件删除语句,如下所示:
IF OBJECT_ID(N'tempdb.dbo.#Results', 'U') IS NOT NULL
BEGIN
DROP TABLE #Results;
END;
这个语句正确地处理了两种情况:
- 在第一次运行时表不存在:不执行任何操作。
- 在后续运行中表存在:删除表。
我编写的生产脚本总是使用这种方法,因为它对于这两种预期情况都不会引发错误。
我的同事编写的一些等效脚本有时使用异常处理来处理这两种情况:
BEGIN TRY DROP TABLE #Results END TRY BEGIN CATCH END CATCH
我相信在数据库世界里,总是征得许可比寻求原谅更好,所以这种方法让我感到不安。
第二种方法会吞掉错误,而不采取任何处理非异常行为的措施(表不存在)。此外,可能会因为其他原因而引发错误,而不是表不存在。 Wise Owl也对同样的事情提出了警告:
但它没有解释实际风险是什么。在这两种方法中,[
OBJECT_ID
方法] 更难理解,但可能更好:使用[BEGIN TRY
方法],你有可能会陷入错误的陷阱!
在实践中,
BEGIN TRY
方法从未在我维护的系统中导致问题,所以我很高兴它能留在那里。使用
BEGIN TRY
方法管理临时表存在的可能危险是什么?哪些意外错误可能会被空catch块隐藏?