2010-01-14 30 views
0

历史简介: 我正在写一个存储过程,以支持旧版报告系统上的遗留Web应用程序(使用SQL Server报表服务2000)。 在与原来的执行风格保持一致,每个报告都有在执行所有查询必须返回一个可以简单地通过报表服务器呈现“最终”数据集中的数据库专用存储过程。我的存储过程是否按顺序执行?

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

在整个存储过程,我保持柱用户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 

切实我设定的名称VARCHAR列(以前留下空,而我是执行一些支点逻辑)为所需的名称格式在纯文本。

完成后,我要删除的用户ID列报表用户不应该看到这一点。

最后,返回的数据集具有作为用户名一个栏,以及INT列的与性能总数的任意数量。出于这个原因,我不能简单地排除UserID列,因为SQL不支持“SELECT * EXCEPT [UserID]”等。

该已知的(任何风格指针赞赏,但没有中央对这个问题),这里的问题:

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

Invalid column name 'userID'. 

然而,如果我注释掉我的DROP COLUMN语句并保留UserID,则存储过程将正确执行。

发生了什么事?它看起来像是语句不按顺序执行,并且在我可以使用它来设置名称字符串之前就删除列!

[编辑1] 我定义用户ID先前(整个存储过程是约200主要取决于不相干逻辑的,所以我将粘贴片段:

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

区分大小写是没有问题的但没有指向我的权利 - 有一个地方,我有userID而不是UserID。现在我修复了这个情况,错误信息抱怨UserID。

我的“破损”的存储过程也能正常工作SQL Server 2008 - 这是一个2000年的错误,或者我是严重misu了解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); 

谢谢大家!

+0

完整的存储过程以及如何调用它将会很有用 – 2010-01-14 19:56:59

+0

不幸的是,任何阅读此内容的人都必须使用SELECT *。所以建议不要这样做...... – JonH 2010-01-14 20:16:10

+0

向我们展示如何在临时表内定义用户标识字段。 看起来这个领域根本不存在。 – JonH 2010-01-14 20:18:09

回答

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 

它说对你无效列。您是否检查拼写并确保在临时表中甚至存在该列。

+0

感谢JonH--我认为这是我需要的关键。您的声明在我的SQL Server 2000实例上也是如此(这是生产中的)。 当我尝试它对SQL Server 2008它成功! – 2010-01-14 20:40:43

+0

这也适用于sql server 2005. – JonH 2010-01-14 20:52:02

4

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

有各种各样的原因,你不应该从你的程序返回select *

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

根据错误消息,数据库是否区分大小写,因此userIDUserID之间有区别?

+0

只是想告诉你,我almsot犯了同样的错误,声明他不应该使用SELECT *。不幸的是,解决方案必须有点脏...... – JonH 2010-01-14 20:15:40

0

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

0

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