2010-01-14 83 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組裝成一個字符串,然後在存儲過程結束時執行它可能是一條可行的路。