【问题标题】:'Invalid column name' from within a stored procedure存储过程中的“无效列名”
【发布时间】:2013-11-12 17:29:19
【问题描述】:

我编写了一个存储过程来将未来的日期(不包括周六和周日)插入到一个永久表中。该例程仅使用一个临时表。这篇文章的目的不是批评存储过程。虽然,我确信它可以改进。然而,这篇文章的目的是分析为什么存储过程在一组情况下调用时会抛出这些错误,而不是在其他情况下。

1 - 这是我收到的错误

Msg 207, Level 16, State 1, Procedure MAKE_FUTURE_DATES, Line 25
Invalid column name 'tdate'.
Msg 207, Level 16, State 1, Procedure MAKE_FUTURE_DATES, Line 31
Invalid column name 'wday'.

2 - 这是存储过程

ALTER PROCEDURE [dbo].[MAKE_FUTURE_DATES] (@STARTDATE DATE)
AS
BEGIN
-- We need to populate FUTURE_DATES (table) with forward looking dates (week days only) 
-- We do not consider/exclude holidays here. We just exclude Sat/Suns

-- Temp table to hold the dates and days of the week
    CREATE TABLE #TMP_DATES(
        [tdate] [date] NULL,
        [wday] [varchar](10) NULL,  
        )

    -- To generate 'enough' future dates loop up to 1199 days in the future
    -- and insert dates that start with the current date and increase with each loop

    DECLARE @Loop INT
    SET @Loop = 0
    WHILE @Loop < 1200
    BEGIN
        INSERT INTO #TMP_DATES (tdate) VALUES (DATEADD(weekday,@Loop,@STARTDATE))   
        SET @Loop = @Loop + 1
    END

    -- Now update the wday column with the weekday name so we can get rid of
    -- Sat/Sun in the next step

    UPDATE #TMP_DATES
    SET wday = UPPER(LEFT(DATENAME(dw,tdate),3))

    -- Get rid of Sat/Sun
    DELETE FROM #TMP_DATES WHERE wday = 'SAT' or wday = 'SUN'

    -- Now clear the final destination table
    TRUNCATE TABLE FUTURE_DATES

    -- Insert the weekday dates into future_dates

    INSERT INTO FUTURE_DATES (fdate,wday)
    SELECT tdate,wday FROM #TMP_DATES

    DROP TABLE #TMP_DATES

3 - 我在另一个存储过程中将上述存储过程作为 SQL Server 任务在后台(通过 SQL Server 作业调度程序)调用了大约 6 个月,没有任何错误或问题。最近,我创建了一个新的存储过程,我们称之为“ABC”,它调用一个调用 MAKE_FUTURE_DATEs 的存储过程。

4 - 这是我要解决的部分。当 ABC 在后台(通过 SQL Server 作业调度程序)作为 SQL Server 任务调用时,它每次(每天)都会抛出错误,并且不会产生结果/它会崩溃。当我第一次启动 SQL Server Management Studio 并运行 ABC 时,它有时会在第一次抛出错误。此序列中的第二次和所有后续时间都不会引发错误。另外,请记住,调用 MAKE_FUTURE_DATES 6 个月的存储过程仍然很满意,没有错误。

我正在寻找有关如何调试或查找内容的建议。特别是它如何有时会抛出错误而不是其他错误?

【问题讨论】:

    标签: sql sql-server tsql stored-procedures sql-server-2008-r2


    【解决方案1】:

    您发布的代码对我来说看起来不错。这是完整的代码吗?

    唯一想到的是您的“ABC”存储过程还有一个名为#TMP_DATES 的临时表。 ABC 中的临时表也将在被调用的存储过程的范围内可用。

    但是,如果是这种情况,当您在被调用的过程中调用 CREATE TABLE #TMP_DATES 时,您应该会得到一个不同的错误。

    【讨论】:

    • 感谢您的回复。我故意在程序结束时删除#TMP_DATES。如果错了,请纠正我,但这会使桌子和它的列完全失去流通/可见性?如果是,那么这可能是一个不同的问题吗?
    • 如果 ABC 过程调用此过程,并且 ABC 过程也有一个名为 #TMP_DATES 的临时表,您将发生冲突,因为该临时表的范围将与此过程共享。这个冲突会发生在 drop 语句之前。此外,您没有回答这是完整代码还是为了简洁而省略了部分代码的问题。
    • 我发布的是 MAKE_FUTURE_DATES 的完整代码,该存储过程创建 #TMP_DATES 并填充 FUTURE_DATES。我没有发布调用 MAKE_FUTURE_DATES 的存储过程,因为它非常冗长,而且我认为,考虑到调用是如此简单,它并不密切。自从我在这里的最后一次回复以来,我创建了一个重复的 SQL Server 作业,它每天调用 MAKE_FUTURE_DATES,在“ABC”存储过程间接调用它之前的几个小时。现在调用存储过程的更高级别的工作没有错误。调用上面发布的 SPROC 可以解决问题。但我想修复它
    • ABC 过程是否包含名为“#TMP_DATES”的临时表?即使确实如此,我也不知道这如何会因发布的错误而失败,但它至少可以解决可能存在范围冲突的问题。
    • 如上所述,临时表的范围更多的是单个SP,而是当前会话。如果您不希望发生此类崩溃,只需将 MAKE_FUTURE_DATES SP 中的表名称更改为独特的名称(例如#TMP_DATES_REFILL)。其中,如果输入参数@STARTDATE 提供为NULL,您可能会收到半崩溃(表FUTURE_DATES 充满NULL 值) - 不对其进行检查。只需添加 set @STARTDATE = isnull(@STARTDATE, getdate()) 之类的代码部分即可避免此问题。
    【解决方案2】:

    临时表的范围不仅仅是一个过程。

    因此您可以在 uspProc1 中创建一个临时表...如果在 uspProc1 中,您调用 uspProc2,uspProc2 “可以看到”您创建的临时表。

    确保为#temp 表提供唯一名称。

    下面是一个例子来说明这一点。

    IF EXISTS 
        (
        SELECT * FROM INFORMATION_SCHEMA.ROUTINES
        WHERE ROUTINE_TYPE = N'PROCEDURE' and ROUTINE_SCHEMA = N'dbo' and ROUTINE_NAME = N'uspProc001'  
        )
    BEGIN
        DROP PROCEDURE [dbo].[uspProc001]
    END
    
    
    GO
    
    CREATE Procedure dbo.uspProc001 (
    @Param1 int
    )
    AS
    
    BEGIN
    
    
    IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
    begin
            drop table #TableOne
    end
    
    
    CREATE TABLE #TableOne
    ( 
    SurrogateKey int , 
    NameOf varchar(12)
    )
    
    Insert into #TableOne ( SurrogateKey , NameOf ) select 1001, 'uspProc001'
    
    Select * from #TableOne
    
    EXEC dbo.uspProc002 
    
    Select * from #TableOne
    
    IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
    begin
            drop table #TableOne
    end
    
    
    END
    
    
    GO
    
    
    
    
    IF EXISTS 
        (
        SELECT * FROM INFORMATION_SCHEMA.ROUTINES
        WHERE ROUTINE_TYPE = N'PROCEDURE' and ROUTINE_SCHEMA = N'dbo' and ROUTINE_NAME = N'uspProc002'  
        )
    BEGIN
        DROP PROCEDURE [dbo].[uspProc002]
    END
    
    
    GO
    
    CREATE Procedure dbo.uspProc002 
    AS
    
    BEGIN
    
    IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
    begin
        Insert into #TableOne ( SurrogateKey , NameOf ) select 2001, 'uspProc002'
    end
    
    
    
    END
    
    
    GO
    
    
    
    
    
    
    
    
    
    
    exec dbo.uspProc001 0
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-02
      • 2020-03-22
      • 2023-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多