none
Recuperar colunas dinamicamente. RRS feed

  • Pergunta

  • Olá pessoal,

    Estou com um problema que não sei como resolver.
    Fiz um pivot dinamico e preciso pegar o resultado de cada coluna e fazer um datediff, mas como minha tabela pode ter  de 1 a N campos, preciso fazer isso dinamicamente.

    Para ficar mais claro, vou mostrar meu problema.
    As colunas de 1 a 8 recuperei dinamicamente de um pivot, mas não sei como fazer para construir essa mesma consulta de forma dinamica, justamente porque pode vir com 1 ou n colunas.

    SELECT 
    [1],[2],[3],[4],[5],[6],[7],[8],
    DATEDIFF(HH,[1],[2]) AS T1,
    DATEDIFF(HH,[2],[3]) AS T2,
    DATEDIFF(HH,[3],[4]) AS T3,
    DATEDIFF(HH,[4],[5]) AS T4,
    DATEDIFF(HH,[5],[6]) AS T5,
    DATEDIFF(HH,[6],[7]) AS T6,
    DATEDIFF(HH,[7],[8]) AS T7,
    DATEDIFF(HH,[1],[2])+DATEDIFF(HH,[2],[3])+DATEDIFF(HH,[3],[4])+DATEDIFF(HH,[4],[5])+DATEDIFF(HH,[5],[6])+DATEDIFF(HH,[6],[7])+DATEDIFF(HH,[7],[8]) AS TOTAL
    FROM tmp_dados_pivot

    Já agradeço pela ajuda.. Eu realmente não faço idéia de como fazer.

    segunda-feira, 15 de agosto de 2016 20:37

Respostas

  • Senhores, obrigado pela ajuda..

    Um amigo me ajudou com essa solução.

    SELECT c AS Coluna INTO #Tabela 
    FROM (VALUES(1),(2),(3),(4),(5)) AS t(c);
    -- Colunas Base
    DECLARE @ColunasBase NVARCHAR(MAX) =
    (SELECT 
    STUFF((
    SELECT QUOTENAME(Coluna)+N','
    FROM #Tabela
    ORDER BY Coluna
    FOR XML PATH('')
    ),1,0,N''));
    -- Datediff Parcial
    DECLARE @DatediffParcial NVARCHAR(MAX) =
    STUFF((
    SELECT QUOTENAME(Coluna)+N') AS T'+CONVERT(VARCHAR,Coluna-1)+
    N',DATEDIFF(HH,'+QUOTENAME(Coluna)+N','
    FROM #Tabela
    ORDER BY Coluna
    FOR XML PATH('')
    ),1,11,N'');
    SET @DatediffParcial = 
    REVERSE(
    SUBSTRING(
    REVERSE(@DatediffParcial),
    CHARINDEX(N'FFIDETAD',REVERSE(@DatediffParcial))+8,
    999999 -- Preguiça msm
    )
    );
    -- Datediff Total
    DECLARE @DatediffTotal NVARCHAR(MAX) =
    STUFF((
    SELECT QUOTENAME(Coluna)+N')+DATEDIFF(HH,'+QUOTENAME(Coluna)+N','
    FROM #Tabela
    ORDER BY Coluna
    FOR XML PATH('')
    ),1,5,N'');
    SET @DatediffTotal = 
    REVERSE(
    SUBSTRING(
    REVERSE(@DatediffTotal),
    CHARINDEX(N'FFIDETAD+',REVERSE(@DatediffTotal))+9,
    999999 -- Preguiça msm
    )
    ) + N' AS TOTAL ';
    SELECT 
    N'SELECT ' + @ColunasBase + @DatediffParcial + @DatediffTotal + 
    N'FROM QualquerCoisa';
    • Marcado como Resposta Daniel_Santos quinta-feira, 18 de agosto de 2016 00:11
    quinta-feira, 18 de agosto de 2016 00:11

Todas as Respostas

  • Daniel o primeiro passo para automatizar essa lógica é contar quantas colunas existem na tabela toda vez que executar a query, segue exemplo 

    use <nome do banco> --necessário setar o banco antes da consulta de metadados
    
    Select 
    
    count(1)
    
    from sys.columns a
    
    inner join sys.objects b On (a.object_id = b.object_id)
    
    Where a.object_id = object_id('tmp_dados_pivot') --nome da tabela
    

    Após a consulta do número de colunas você pode guardar o número em uma variável e depois incluir uma a uma, em sequencia, na consulta. Pelo que vi você da um alias com os números então é só seguir na sequencia de acordo com o que a consulta de metadados retornar. 


    terça-feira, 16 de agosto de 2016 13:17
  • Bom dia Daniel,

    Apesar de não ser a melhor opção, provavelmente você terá que fazer uma procedure com cursor para isso.

    Sua procedure terá que ler as tabelas de sistema para saber quantas colunas existem na tabela e carregar essas colunas em cursor, feito isso, monte seu select de forma dinâmica.

    Veja um exemplo bem simples.

    DECLARE @V_CAMPOS VARCHAR(100);
    DECLARE @V_SQL VARCHAR(MAX);
    DECLARE C_FIELDS CURSOR FAST_FORWARD FOR	SELECT COLUMN_NAME 
    											FROM INFORMATION_SCHEMA.COLUMNS
    											WHERE TABLE_NAME = 'SUA_TABELA'
    SET @V_SQL = ''; 
    	OPEN C_FIELDS; 	
    	FETCH C_FIELDS INTO @V_CAMPOS;		
    	WHILE (@@FETCH_STATUS <> -1)
    	BEGIN
    		
    
    				IF (LEN(@V_CAMPOS) > 0)
    				BEGIN			
    					SET @V_SQL = @V_SQL +  @V_CAMPOS + ' , ';					
    				END 
    				ELSE
    				BEGIN
    					SET @V_SQL = @V_SQL + @V_CAMPOS;			
    				END
    							
    		FETCH NEXT FROM C_FIELDS INTO @V_CAMPOS
    		
    	END
    	SELECT @V_SQL = SUBSTRING(@V_SQL,1,LEN(@V_SQL)-1);
    	PRINT @V_SQL
    	CLOSE C_FIELDS
    DEALLOCATE C_FIELDS 
    Não consegui imaginar uma solução sem o cursor, já que ele não é melhor opção.


    Atenciosamente, Ruberlei. www.t-sql.com.br

    • Sugerido como Resposta Ruberlei terça-feira, 16 de agosto de 2016 15:37
    terça-feira, 16 de agosto de 2016 15:37
  • Senhores, obrigado pela ajuda..

    Um amigo me ajudou com essa solução.

    SELECT c AS Coluna INTO #Tabela 
    FROM (VALUES(1),(2),(3),(4),(5)) AS t(c);
    -- Colunas Base
    DECLARE @ColunasBase NVARCHAR(MAX) =
    (SELECT 
    STUFF((
    SELECT QUOTENAME(Coluna)+N','
    FROM #Tabela
    ORDER BY Coluna
    FOR XML PATH('')
    ),1,0,N''));
    -- Datediff Parcial
    DECLARE @DatediffParcial NVARCHAR(MAX) =
    STUFF((
    SELECT QUOTENAME(Coluna)+N') AS T'+CONVERT(VARCHAR,Coluna-1)+
    N',DATEDIFF(HH,'+QUOTENAME(Coluna)+N','
    FROM #Tabela
    ORDER BY Coluna
    FOR XML PATH('')
    ),1,11,N'');
    SET @DatediffParcial = 
    REVERSE(
    SUBSTRING(
    REVERSE(@DatediffParcial),
    CHARINDEX(N'FFIDETAD',REVERSE(@DatediffParcial))+8,
    999999 -- Preguiça msm
    )
    );
    -- Datediff Total
    DECLARE @DatediffTotal NVARCHAR(MAX) =
    STUFF((
    SELECT QUOTENAME(Coluna)+N')+DATEDIFF(HH,'+QUOTENAME(Coluna)+N','
    FROM #Tabela
    ORDER BY Coluna
    FOR XML PATH('')
    ),1,5,N'');
    SET @DatediffTotal = 
    REVERSE(
    SUBSTRING(
    REVERSE(@DatediffTotal),
    CHARINDEX(N'FFIDETAD+',REVERSE(@DatediffTotal))+9,
    999999 -- Preguiça msm
    )
    ) + N' AS TOTAL ';
    SELECT 
    N'SELECT ' + @ColunasBase + @DatediffParcial + @DatediffTotal + 
    N'FROM QualquerCoisa';
    • Marcado como Resposta Daniel_Santos quinta-feira, 18 de agosto de 2016 00:11
    quinta-feira, 18 de agosto de 2016 00:11