2011-08-11 37 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

对不起。你是对的。 –