Em meu artigo anterior sobre o operador pivô básico, vimos como o operador pivô pode ser usado para converter linhas em colunas, resultando em tabelas dinâmicas. Vimos que havia três etapas principais para criar uma tabela dinâmica. O primeiro passo foi selecionar os dados da base. A segunda etapa foi converter os dados base em uma expressão com valor de tabela e a etapa final envolveu a aplicação de um operador pivô aos dados temporários, o que resultou na tabela dinâmica.
Dê uma olhada no exemplo abaixo.
USE schooldb SELECT * FROM (SELECT city, total_score FROM student ) AS StudentTable PIVOT( AVG(total_score) FOR city IN ([London],[Liverpool],[Leeds],[Manchester]) ) AS StudentPivotTable
Observação: Para criar o banco de dados e os dados fictícios, consulte o artigo anterior sobre o Pivot Operator.
Limitações do Operador de Pivô
No entanto, existem certas limitações do operador pivô. Dentro do operador pivô, temos que especificar o campo agregado e as colunas nas quais queremos dinamizar nossos dados. Finalmente, também temos que definir os valores individuais para os títulos das colunas que queremos criar.
Se executássemos o script da seção anterior, obteríamos o seguinte resultado:
[ID da tabela=35 /]
Os títulos das colunas são os valores individuais dentro da coluna da cidade. Especificamos esses valores dentro do operador pivô em nossa consulta.
A parte mais tediosa da criação de tabelas dinâmicas é especificar manualmente os valores para os títulos das colunas. Essa é a parte mais propensa a erros, principalmente se os dados em sua fonte de dados online forem alterados. Não podemos ter certeza de que os valores especificados no operador pivô permanecerão no banco de dados até que criemos essa tabela dinâmica na próxima vez.
Por exemplo, em nosso script, especificamos Londres, Liverpool, Leeds e Manchester como valores para títulos de nossa tabela dinâmica. Esses valores existiam na coluna Сity da tabela do aluno. E se de alguma forma um ou mais desses valores forem excluídos ou atualizados? Nesses casos, null será retornado.
Uma abordagem melhor seria criar uma consulta dinâmica que retornaria um conjunto completo de valores da coluna da qual você está tentando gerar sua tabela dinâmica.
Criando uma tabela dinâmica dinâmica
Nesta seção, veremos como criar uma tabela dinâmica dinâmica.
Isso significa que não precisaremos especificar manualmente os valores para a coluna da qual estamos tentando gerar nossa tabela dinâmica. Em vez disso, definiremos esses valores dinamicamente. Para isso, usaremos a função “QUOTENAME”.
Como sempre, certifique-se de ter um backup completo antes de experimentar um novo código. Consulte este artigo sobre como fazer backup de bancos de dados MS SQL se não tiver certeza.
Função QUOTENAME
A função “QUOTENAME” formata os resultados selecionados. Antes de explicar o pivô dinâmico, vale a pena dar uma olhada em um exemplo de trabalho rápido da função “QUOTENAME”.
Dê uma olhada na consulta a seguir.
USE schooldb SELECT QUOTENAME(city)+ ',' FROM student
Por padrão, a função “QUOTENAME” envolve os itens selecionados com colchetes. A saída da consulta acima é assim:
[ID da tabela=36 /]
Armazenando nomes de colunas em uma variável
Embora tenhamos colocado os valores da coluna entre colchetes, precisamos especificar os valores no operador pivô neste formato:
“[Leeds], [Liverpool], [Londres], [Manchester]”
Para fazer isso, vamos precisar de uma variável.
USE schooldb DECLARE @CityNames NVARCHAR(MAX) = '' SELECT @CityNames += QUOTENAME(city)+ ',' FROM ( SELECT DISTINCT city FROM student ) AS CITIES PRINT @CityNames
Na consulta acima, declaramos uma variável “@CityNames” e a inicializamos com uma string vazia. Em seguida, usamos uma instrução SELECT para selecionar nomes de cidades distintos da coluna city e armazená-los iterativamente na variável “@CityNames”. Em cada iteração, um valor distinto na coluna cidade junto com uma vírgula será adicionado à variável “@CityNames”.
Em seguida, imprimimos o valor armazenado nesta variável. O resultado da consulta acima ficará assim:
“[Leeds], [Liverpool], [Londres], [Manchester],”
Se você observar a saída, há uma vírgula após o último valor. Nós não precisamos disso.
Removendo uma vírgula final
Para remover uma vírgula à direita, usaremos uma função LEFT que recebe uma string como seu primeiro argumento. O segundo argumento é o número de caracteres a serem retornados dessa string a partir do primeiro caractere. Dê uma olhada na seguinte consulta:
USE schooldb DECLARE @CityNames NVARCHAR(MAX) = '' SELECT @CityNames += QUOTENAME(city)+ ',' FROM ( SELECT DISTINCT city FROM student ) AS CITIES SET @CityNames = LEFT(@CityNames, LEN(@CityNames)-1) PRINT @CityNames
Aqui preste atenção nesta linha do script:
SET @CityNames = LEFT(@CityNames, LEN(@CityNames)-1)
Nesta linha do script, usamos a função LEFT para obter todos os caracteres do lado esquerdo do valor armazenado na variável “@CityNames”, a partir do primeiro elemento. No segundo argumento, usamos a função LEN para calcular o número de elementos de valor armazenados na função “@CityNames” e, por fim, subtraímos 1 dela. Isso remove a vírgula à direita da string. A saída ficará assim:
[Leeds],[Liverpool],[Londres],[Manchester]
Conversão de consulta SQL em string
Agora, esperamos, podemos usar a variável “@CityNames” dentro do nosso operador pivô assim:
PIVOT( AVG(total_score) FOR city IN ( @CityNames )
No entanto, não podemos usar uma variável dentro do nosso operador pivô. A abordagem alternativa é converter nossa consulta SQL completa em uma string. Dentro desta string, vamos ligar nossa variável “@CityNames”.
USE schooldb DECLARE @CityNames NVARCHAR(MAX) = '' DECLARE @Query NVARCHAR(MAX) = '' SELECT @CityNames += QUOTENAME(city)+ ',' FROM ( SELECT DISTINCT city FROM student ) AS CITIES SET @CityNames = LEFT(@CityNames, LEN(@CityNames)-1) SET @Query = 'SELECT * FROM (SELECT city, total_score FROM student ) AS StudentTable PIVOT( AVG(total_score) FOR city IN (' + @CityNames +') ) AS StudentPivotTable' PRINT @Query
Aqui declaramos uma variável “@Query” e armazenamos nossa consulta SQL nesta variável. Dentro do operador pivô, concatenamos o valor armazenado dentro da variável “@CityNames”. Para ver a aparência da consulta executada, imprimimos o valor da variável “@Query”. A consulta resultante ficará assim na saída:
SELECT * FROM (SELECT city, total_score FROM student ) AS StudentTable PIVOT( AVG(total_score) FOR city IN ([Leeds],[Liverpool],[London],[Manchester]) ) AS StudentPivotTable
Este é exatamente o tipo de consulta que queremos executar. No entanto, isso está no formato String. A etapa final é executar essa consulta SQL armazenada como uma string de texto. Para fazer isso, usaremos o SQL dinâmico.
Executando SQL dinâmico
Usamos o procedimento interno “sp_executesql” para executar SQL dinâmico. Usaremos este procedimento armazenado para executar a consulta armazenada na variável @Query. Nossa consulta final que cria uma tabela dinâmica dinâmica é assim:
USE schooldb DECLARE @CityNames NVARCHAR(MAX) = '' DECLARE @Query NVARCHAR(MAX) = '' SELECT @CityNames += QUOTENAME(city)+ ',' FROM ( SELECT DISTINCT city FROM student ) AS CITIES SET @CityNames = LEFT(@CityNames, LEN(@CityNames)-1) SET @Query = 'SELECT * FROM (SELECT city, total_score FROM student ) AS StudentTable PIVOT( AVG(total_score) FOR city IN (' + @CityNames +') ) AS StudentPivotTable' EXECUTE sp_executesql @Query
Ao executar a consulta acima, você deverá ver o seguinte resultado:
[ID da tabela=37 /]
No entanto, desta vez, não especificamos manualmente os valores para os títulos da tabela dinâmica. Em vez disso, os títulos foram calculados dinamicamente, resultando em uma tabela dinâmica dinâmica.