代码之家  ›  专栏  ›  技术社区  ›  Stefan Mohr

我的存储过程执行是否有问题?

  •  0
  • Stefan Mohr  · 技术社区  · 15 年前

    简史: 我正在编写一个存储过程来支持遗留Web应用程序上的遗留报告系统(使用SQL Server Reporting Services 2000)。 为了与原始实现样式保持一致,每个报表在数据库中都有一个专用的存储过程,该存储过程执行返回“最终”数据集所需的所有查询,该数据集可以由报表服务器简单地呈现。

    由于此报表的业务要求,返回的数据集的列数未知(取决于执行报表的用户,但可能有4-30列)。

    在整个存储过程中,我保留一个列user id来跟踪用户的id以执行其他查询。不过,最后,我会这样做:

    UPDATE #result
    SET Name = ppl.LastName + ', ' + ppl.FirstName
    FROM #result r
    LEFT JOIN Users u ON u.id = r.userID
    LEFT JOIN People ppl ON ppl.id = u.PersonID
    
    ALTER TABLE #result
    DROP COLUMN [UserID]
    
    SELECT * FROM #result r ORDER BY Name
    

    有效地,我将name varchar列(在执行一些透视逻辑时,该列以前为空)设置为纯文本格式的所需名称格式。

    完成后,我希望删除userid列,因为报表用户不应该看到这一点。

    最后,返回的数据集有一列用于用户名,任意数量的int列用于性能合计。由于这个原因,我不能简单地排除userid列,因为SQL不支持“select*except[userid]”等。

    有了这个已知的(任何风格的指针都会被欣赏,但不是这个问题的核心),问题是:

    当我执行此存储过程时,会得到一个执行错误:

    Invalid column name 'userID'.
    

    但是,如果注释掉drop column语句并保留userid,则存储过程将正确执行。

    发生什么事?显然,语句执行的顺序不对,在我可以使用它设置名称字符串之前,它将删除该列!

    [编辑1 ] 我以前定义过userid(整个存储过程大约有200个基本上不相关的逻辑谎言,因此我将粘贴片段:

        CREATE TABLE #result ([Name] NVARCHAR(256), [UserID] INT);
    

    区分大小写不是问题,但确实指出了正确的方向——有一个地方我使用了userid而不是userid。现在我修复了这个案例,错误消息抱怨用户ID。

    我的“中断”存储过程在SQL Server 2008中也能正常工作-这可能是一个2000错误,或者我严重误解了SQL Server过去是如何工作的。

    谢谢大家的参与!

    对于将来搜索此内容的任何人,我添加了一个极其粗糙的解决方案,以便在我们更新生产版本之前与2000兼容:

    DECLARE @workaroundTableName NVARCHAR(256), @workaroundQuery NVARCHAR(2000)
    SET @workaroundQuery = 'SELECT [Name]';
    DECLARE cur_workaround CURSOR FOR
    SELECT COLUMN_NAME FROM [tempdb].INFORMATION_SCHEMA.Columns WHERE TABLE_NAME LIKE '#result%' AND COLUMN_NAME <> 'UserID'
    OPEN cur_workaround;
    FETCH NEXT FROM cur_workaround INTO @workaroundTableName
    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @workaroundQuery = @workaroundQuery + ',[' + @workaroundTableName + ']'
        FETCH NEXT FROM cur_workaround INTO @workaroundTableName
    END
    CLOSE cur_workaround;
    DEALLOCATE cur_workaround;
    SET @workaroundQuery = @workaroundQuery + ' FROM #result ORDER BY Name ASC'
    EXEC(@workaroundQuery);
    

    谢谢大家!

    4 回复  |  直到 15 年前
        1
  •  1
  •   JonH    15 年前

    这对我很有用:

    CREATE TABLE #temp_t
     (
      myInt int,
      myUser varchar(100)
     )
    
    INSERT INTO #temp_t(myInt, myUser) VALUES(1, 'Jon1')
    INSERT INTO #temp_t(myInt, myUser) VALUES(2, 'Jon2')
    INSERT INTO #temp_t(myInt, myUser) VALUES(3, 'Jon3')
    INSERT INTO #temp_t(myInt, myUser) VALUES(4, 'Jon4')
    
    ALTER TABLE #temp_t
    DROP Column myUser
    
    SELECT * FROM #temp_t
    
    DROP TABLE #temp_t
    

    上面写着无效的列。是否检查了拼写并确保临时表中甚至存在该列?

        2
  •  4
  •   Moose    15 年前

    一个更简单的解决方案是不删除列,但不要在最终选择中返回它。

    你不应该回来的原因有很多 select * 不管怎样,从你的程序。

    编辑:现在我知道你必须这样做,因为列的数目未知。

    根据错误消息,数据库是否区分大小写,因此 userID UserID 是吗?

        3
  •  0
  •   MikeW    15 年前

    您可以尝试在begin…commit事务中包装drop列前面的所有内容。

        4
  •  0
  •   John Pick    15 年前

    在编译时,SQL Server可能正在将*扩展到列的完整列表中。因此,在运行时,SQL Server执行“select userid,name,lastname,firstname,…”而不是“select*”。动态地将最终的select组装成一个字符串,然后在存储过程的末尾执行它可能是一种方法。