SQL Server 临时表已存在?

3
这很奇怪,我在这段SQL中声明了一个临时表,但基于if else逻辑,我只声明了一次。在运行下面的查询之前,我会删除临时表,但仍然出现相同的问题。 然而,当我将ReportType设置为2并尝试运行查询时,SQL Server会报告“数据库中已经存在名为'#ManifestTrackingBranches'的对象。” 我是否遗漏了什么? T-SQL
declare @ReportType int 
declare @CustomerNumber int 
declare @StartDate datetime
declare @EndDate datetime 

set @ReportType = 2
set @CustomerNumber = 81 
set @StartDate = '2014-04-27'
set @EndDate = '2014-05-04'

if @CustomerNumber = 81
begin
    if @ReportType = 1 -- roll up by location
    begin 
        select  InboundData.Tracking,
                InboundData.NegotiatedRate 
        into    #ManifestTrackingBranches
        from    InboundData
        where   Injected >= @StartDate and Injected <= @EndDate

        -- Match tracking numbers against Ebill Data 
        select      #ManifestTrackingBranches.Tracking,
                    SUM(isnull(cast(#ManifestTrackingBranches.NegotiatedRate as decimal(18,2)),0)) as ManifestAmount
        from        EBillData 
        group by    #ManifestTrackingBranches.Branch
    end

    else if  @ReportType = 2 -- Line Item Reports
    begin 
        select  InboundData.Tracking,
                InboundData.NegotiatedRate 
        into    #ManifestTrackingBranches
        from    InboundData
        where   Injected >= @StartDate and Injected <= @EndDate

        -- Match tracking numbers against Ebill Data 
        select      #ManifestTrackingBranches.Tracking,
                    SUM(isnull(cast(#ManifestTrackingBranches.NegotiatedRate as decimal(18,2)),0)) as ManifestAmount
        from        EBillData 
    end
end

出错发生在第二个if语句中,当ReportType被设置为2时,我试图选择同一个临时表。


3
在开始时创建临时表或使用不同的表名。T-SQL在确定批处理中已声明哪些名称时不会关注控制流。 - Damien_The_Unbeliever
1
@Damien_The_Unbeliever 这个方法行得通,先在逻辑之前创建临时表。谢谢解释!如果你将这写成答案,我很乐意接受它。 - mituw16
你也可以使用表变量。 - podiluska
2个回答

9
在任何变量声明之前添加这行代码。
IF OBJECT_ID('tempdb..#ManifestTrackingBranches') IS NOT NULL 
DROP TABLE #ManifestTrackingBranches
GO

只有在单独的批处理中使用GO关键字时,此语句才会生效。当您编写存储过程并通过多次执行代码来测试它时,这已足够好。
在您的存储过程内,您不能添加GO关键字,也没有必要在从应用程序调用此存储过程时删除表。每次对此存储过程的调用都将拥有自己的连接,并创建仅限于该连接范围的临时表。 编辑SQL Server 2016和更高版本以来,您还可以使用以下语法:
DROP TABLE IF EXISTS #ManifestTrackingBranches
GO

根据语法,如果存在表,则它将删除该表,否则什么也不做,但该命令不会报错,代码执行将转移到下一行。这是一种更简洁、更简单的方法。

DROP IF EXISTS 还适用于其他 SQL Server 对象,比如视图、索引、触发器和函数等。


2
经过测试,这并没有帮助...... 我认为@Damien_The_Unbeliever是正确的。 Tsql不关心控制流。 - Darka
是的,我在发布的代码中没有包含那部分,但我在脚本顶部有。这不会改变任何东西。 - mituw16
需要在单独的批处理中进行操作,测试时需要添加关键字 GO。但是在过程内部无法添加 GO。但当从应用程序调用此过程时,这将不会成为任何问题。您甚至不需要添加删除表语句,因为对该过程的每次调用都将拥有自己的连接,并且将创建仅限于该连接范围的临时表。 - M.Ali

2

SQL会在每个连接中保留临时表,除非您将其删除。因此,一旦使用完毕,最好删除临时表。

添加DROP TABLE语句。

declare @ReportType int 
declare @CustomerNumber int 
declare @StartDate datetime
declare @EndDate datetime 

set @ReportType = 2
set @CustomerNumber = 81 
set @StartDate = '2014-04-27'
set @EndDate = '2014-05-04'

if @CustomerNumber = 81
begin
  if @ReportType = 1 -- roll up by location
  begin 
    select  InboundData.Tracking,
            InboundData.NegotiatedRate 
    into    #ManifestTrackingBranches
    from    InboundData
    where   Injected >= @StartDate and Injected <= @EndDate

    -- Match tracking numbers against Ebill Data 
    select      #ManifestTrackingBranches.Tracking,
                SUM(isnull(cast(#ManifestTrackingBranches.NegotiatedRate as decimal(18,2)),0)) as ManifestAmount
    from        EBillData 
    group by    #ManifestTrackingBranches.Branch;

    --clean up after yourself
    drop table #ManifestTrackingBranches
  end

  else if  @ReportType = 2 -- Line Item Reports
  begin 
    select  InboundData.Tracking,
            InboundData.NegotiatedRate 
    into    #ManifestTrackingBranches
    from    InboundData
    where   Injected >= @StartDate and Injected <= @EndDate

    -- Match tracking numbers against Ebill Data 
    select      #ManifestTrackingBranches.Tracking,
                SUM(isnull(cast(#ManifestTrackingBranches.NegotiatedRate as decimal(18,2)),0)) as ManifestAmount
    from        EBillData 

    --clean up after yourself
    drop table #ManifestTrackingBranches
  end
end

不幸的是,这并没有起作用。它仍然显示相同的错误。 - mituw16
没错,Damien说得对。不过,明确地删除临时表仍然是一个好主意。通常情况下没关系,但之前我被这个问题困扰过。尤其是在调试时。 - tgolisch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接