我的存储过程是否按顺序执行?

时间:2010-01-14 19:44:29

标签: sql sql-server stored-procedures

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

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

在整个存储过程中,我保留一列UserID来跟踪用户的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列(在我执行某些透视逻辑时先前保留为NULL)设置为纯文本格式的所需名称格式。

完成后,我想删除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。现在我修复了案例,错误消息抱怨UserID。

我的“破损”存储过程在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 个答案:

答案 0 :(得分:4)

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

有很多理由说明为什么你不应该从程序中返回select *

编辑:我现在看到你必须这样做,因为列数不明。

根据错误消息,数据库区分大小写,因此userIDUserID之间存在差异吗?

答案 1 :(得分:1)

这对我有用:

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 :(得分:0)

您可以尝试在BEGIN ... COMMIT事务中包装DROP COLUMN之前的所有内容。

答案 3 :(得分:0)

在编译时,SQL Server可能会将*扩展为完整的列列表。因此,在运行时,SQL Server执行“SELECT UserID,Name,LastName,FirstName,...”而不是“SELECT *”。将最终的SELECT动态组装成一个字符串,然后在存储过程结束时执行它可能是最佳选择。