2011-08-11 69 views
5

我正在編寫一個查詢來旋轉動態生成列名的表元素。在SQL Azure中使用臨時表

SET @query = N'SELECT STUDENT_ID, ROLL_NO, TITLE, STUDENT_NAME, EXAM_NAME, '+ 
      @cols + 
      ' INTO ##FINAL 
      FROM 
      (
       SELECT * 
       FROM #AVERAGES 
       UNION 
       SELECT * 
       FROM #MARKS 
       UNION 
       SELECT * 
       FROM #GRACEMARKS 
       UNION 
       SELECT * 
       FROM #TOTAL 
       ) p 
       PIVOT 
       (
       MAX([MARKS]) 
       FOR SUBJECT_ID IN 
       ('+ 
       @cols +') 
      ) AS FINAL 
      ORDER BY STUDENT_ID ASC, DISPLAYORDER ASC, EXAM_NAME ASC;' 

EXECUTE(@query) 

select * from ##FINAL 

該查詢在我的本地數據庫中正常工作,但由於全局臨時表不允許在那裏,因此它不適用於SQL Azure。

現在,如果我改變##FINA L到#FINAL在我的本地數據庫,但它給了我錯誤的

無效的對象名稱#FINAL「。

我該如何解決這個問題?

+0

我不認爲你的具體問題可以解決,因爲你試圖構造SQL(SQL Server)不能很好地支持的東西(具有可變列數的結果集)。在一般情況下,要做到這一點,你必須在外部範圍內創建臨時表(即在'EXECUTE'之前),但是當你不知道你的列是什麼時你不能這樣做需要。 –

+0

其實我已經嘗試過了,我創建了一個可以放入temp的列名,並將它放入@中。它不起任何作用,因爲我不能在條款中使用它。即,FOR SUBJECT_ID IN (SELECT cast(subject_id AS NVARCHAR)FROM #SUBJECT_ID_TABLE) –

+0

不,重點是在'EXECUTE'之前創建'#Final'臨時表 - 這是在兩個範圍內訪問它的唯一方法。我已經展示了一種可能適用於我的答案的方法。 –

回答

10

好的,在說我認爲不可能完成之後,我可能會有辦法。雖然這很醜陋。希望你可以與下面的示例播放,使其適應您的查詢(無需您的架構和數據,它太狡猾,我試圖寫它):

declare @cols varchar(max) 
set @cols = 'object_id,schema_id,parent_object_id' 

--Create a temp table with the known columns 
create table #Boris (
    ID int IDENTITY(1,1) not null 
) 
--Alter the temp table to add the varying columns. Thankfully, they're all ints. 
--for unknown types, varchar(max) may be more appropriate, and will hopefully convert 
declare @tempcols varchar(max) 
set @tempcols = @cols 
while LEN(@tempcols) > 0 
begin 
    declare @col varchar(max) 
    set @col = CASE WHEN CHARINDEX(',',@tempcols) > 0 THEN SUBSTRING(@tempcols,1,CHARINDEX(',',@tempcols)-1) ELSE @tempcols END 
    set @tempcols = CASE WHEN LEN(@col) = LEN(@tempcols) THEN '' ELSE SUBSTRING(@tempcols,LEN(@col)+2,10000000) END 
    declare @sql1 varchar(max) 
    set @sql1 = 'alter table #Boris add [' + @col + '] int null' 
    exec (@sql1) 
end 

declare @sql varchar(max) 
set @sql = 'insert into #Boris (' + @cols + ') select ' + @cols + ' from sys.objects' 
exec (@sql) 

select * from #Boris 

drop table #Boris 

他們關鍵是創建臨時表在外部作用域中,然後內部作用域(在EXEC語句中運行的代碼)可以訪問相同的臨時表。上述工作在SQL Server 2008上,但我沒有Azure實例可以使用,所以沒有在那裏測試過。

+0

試過這個,它可以工作,即使它看起來有點髒它只要我得到正確的結果。非常感謝 –

1

如果你創建一個臨時表,它可以從你的spid中執行的動態sql中看到,如果你使用動態sql創建表,那麼它不可見。

有一種解決方法。您可以創建一個存根表並在動態SQL中對其進行修改。它需要一些字符串操作,但我使用這種技術爲tsqlunit生成動態數據集。

CREATE TABLE #t1 
(
    DummyCol int 
) 

EXEC(N'ALTER TABLE #t1 ADD foo INT') 

EXEC ('insert into #t1(DummyCol, foo) 
VALUES(1,2)') 

EXEC ('ALTER TABLE #t1 DROP COLUMN DummyCol') 

select *from #t1 
+0

事先不知道列,對不對? –

+0

這只是驗證概念的代碼來演示原理。有很多方法來派生列,但在OP的情況下,cols是已知的,並且在@ @ cols中。將'@ cols'轉換爲alter語句需要一些操作。 Damien_The_Unbeliever寫了一個更完整的這種方法的例子。 –

+0

對不起。你是對的。 –