2011-08-11 13 views
5

Estoy escribiendo una consulta a los elementos de la tabla pivotante donde se genera dinámicamente el nombre de la columna.usando tablas temporales en 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 

Esta consulta funciona correctamente en mi base de datos local, pero no funciona en SQL Azure ya que las tablas temporales globales no están permitidas allí.

Ahora si cambio ##FINA L a #FINAL en mi base de datos local, pero me da error como

nombre de objeto no válido '#FINAL'.

¿Cómo puedo resolver este problema?

+0

No creo que su problema específico pueda ser resuelto, ya que está tratando de construir algo (un conjunto de resultados con un número variable de columnas) que SQL no soporta bien. En el caso general, para que esto funcione, debe crear la tabla temporal en el ámbito externo (es decir, antes del 'EJECUTAR'), pero no puede hacer eso cuando no sabe qué columnas está yendo a necesitar. –

+0

En realidad ya lo intenté, creé un temp able y coloqué los nombres de las columnas que están en @. no sirve para nada porque no pude usarlo en la cláusula in. es decir, PARA SUBJECT_ID EN (SELECT cast (subject_id AS NVARCHAR) FROM #SUBJECT_ID_TABLE) –

+0

No, el objetivo era crear la tabla temporal '# Final' antes de' EXECUTE' - esa es la única forma de tener acceso a ella en ambos ámbitos . He mostrado una manera que podría funcionar en mi respuesta. –

Respuesta

10

De acuerdo, después de decir que no creía que se pudiera hacer, podría tener una forma. Es feo sin embargo. Con suerte, se puede jugar con el ejemplo siguiente y adaptarlo a su consulta (sin tener su esquema y los datos, es demasiado complicado para mí para tratar de escribirlo):

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 
clave

ellos es la creación de la tabla temporal en el ámbito externo, y luego los ámbitos internos (código que se ejecuta dentro de las sentencias EXEC) tienen acceso a la misma tabla temporal. Lo anterior funcionó en SQL Server 2008, pero no tengo una instancia de Azure para jugar, por lo que no se prueba allí.

+0

intenté esto, funciona, aunque parece algo sucio es k siempre y cuando obtenga los resultados adecuados. muchas gracias –

1

Si crea una tabla temporal, es visible desde el sql dinámico ejecutado en su spid, si crea la tabla en sql dinámico, no estará visible fuera de esa.

Hay una solución. Puede crear una tabla de resguardo y modificarla en su sql dinámico. Requiere un poco de manipulación de cadenas pero he usado esta técnica para generar datasets dinámicos para 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

Columnas no se conocen de antemano, ¿verdad? –

+0

Eso es solo un código de prueba de concepto para demostrar el principio. Hay muchas maneras de derivar las columnas, pero en el caso del OP, se conocen cols y en '@ cols'. Algún tipo de manipulación sería necesaria para traducir '@ cols' en declaraciones alternas. Damien_The_Unbeliever escribió un ejemplo más completo de este enfoque. –

+0

Lo siento. Tienes razón. –

Cuestiones relacionadas