- Resumidamente sobre tabelas dinâmicas
- Pivotando dados por meio de ferramentas (dbForge Studio para MySQL)
- Pivotando dados por meio de SQL
- Exemplo baseado em T-SQL para SQL Server
- Exemplo para MySQL
- Automatizando a dinamização de dados, criando consultas dinamicamente
Resumidamente sobre tabelas dinâmicas
Este artigo trata da transformação dos dados da tabela de linhas para colunas. Essa transformação é chamada de tabelas dinâmicas. Muitas vezes, o resultado do pivô é uma tabela de resumo na qual os dados estatísticos são apresentados na forma adequada ou necessária para um relatório.
Além disso, tal transformação de dados pode ser útil se um banco de dados não estiver normalizado e as informações nele forem armazenadas de forma não ideal. Portanto, ao reorganizar o banco de dados e transferir dados para novas tabelas ou gerar uma representação de dados necessária, o pivô de dados pode ser útil, ou seja, mover valores de linhas para colunas resultantes.
Abaixo está um exemplo da antiga tabela de produtos – ProductsOld e a nova – ProductsNew. É através da transformação de linhas em colunas que tal resultado pode ser facilmente alcançado.
Aqui está um exemplo de tabela dinâmica.
Pivotando dados por meio de ferramentas (dbForge Studio para MySQL)
Existem aplicativos que possuem ferramentas que permitem implementar o pivô de dados em um ambiente gráfico conveniente. Por exemplo, o dbForge Studio para MySQL inclui a funcionalidade de Tabelas Dinâmicas que fornece o resultado desejado em apenas algumas etapas.
Vejamos o exemplo com uma tabela simplificada de pedidos – PurchaseOrderHeader .
CREATE TABLE PurchaseOrderHeader ( PurchaseOrderID INT(11) NOT NULL, EmployeeID INT(11) NOT NULL, VendorID INT(11) NOT NULL, PRIMARY KEY (PurchaseOrderID));INSERT PurchaseOrderHeader(PurchaseOrderID, EmployeeID, VendorID) VALUES (1 , 258, 1580);INSERT PurchaseOrderHeader(PurchaseOrderID, EmployeeID, VendorID) VALUES (2, 254, 1496);INSERT PurchaseOrderHeader(PurchaseOrderID, EmployeeID, VendorID) VALUES (3, 257, 1494);INSERT PurchaseOrderID(PurchaseOrderID, EmployeeID, VendorID) ) VALUES (4, 261, 1650);INSERT PurchaseOrderHeader(PurchaseOrderID, EmployeeID, VendorID) VALUES (5, 251, 1654);INSERT PurchaseOrderHeader(PurchaseOrderID, EmployeeID, VendorID) VALUES (6, 253, 1664);INSERT PurchaseOrderHeader(PurchaseOrderID , EmployeeID, VendorID) VALUES (7, 255, 1678);INSERT PurchaseOrderHeader(PurchaseOrderID, EmployeeID, VendorID) VALUES (8, 256, 1616);INSERT PurchaseOrderHeader(PurchaseOrderID, EmployeeID, VendorID) VALUES (9, 259, 1492); INSERT PurchaseOrderHeader(PurchaseOrderID, EmployeeID, VendorID) VALUES (10, 250, 1602);INSERT PurchaseOrderHeader(PurchaseOrderID, EmployeeID, VendorID) VALUES (11, 258, 1540);...
Suponha que precisamos fazer uma seleção na tabela e determinar o número de pedidos feitos por determinados funcionários de fornecedores específicos. A lista de funcionários, para os quais são necessárias informações – 250, 251, 252, 253, 254.
Uma visualização preferencial para o relatório é a seguinte.
A coluna da esquerda VendorID mostra os IDs dos fornecedores; colunas Emp250 , Emp251 , Emp252 , Emp253 , e Emp254 exibir o número de pedidos.
Para conseguir isso no dbForge Studio para MySQL, você precisa:
- Adicione a tabela como fonte de dados para a representação "Tabela Dinâmica" do documento. No Database Explorer, clique com o botão direito do mouse em PurchaseOrderHeader tabela e selecione Enviar para e, em seguida, Tabela Dinâmica no menu pop-up.
- Especifique uma coluna cujos valores serão linhas. Arraste o VendorID coluna para a caixa "Soltar campos de linhas aqui".
- Especifique uma coluna cujos valores serão colunas. Arraste o EmployeeID coluna para a caixa 'Soltar campos de coluna aqui'. Você também pode definir um filtro para os funcionários necessários (250, 251, 252, 253, 254).
- Especifique uma coluna, cujos valores serão os dados. Arraste o PurchaseOrderID coluna para a caixa "Soltar itens de dados aqui".
- Nas propriedades do PurchaseOrderID coluna, especifique o tipo de agregação – Contagem de valores .
Rapidamente obtivemos o resultado que precisávamos.
Pivotar dados por meio de SQL
Obviamente, a transformação de dados pode ser realizada por meio de um banco de dados escrevendo uma consulta SQL. Mas há um pequeno problema, o MySQL não possui uma instrução específica que permita fazer isso.
Exemplo baseado em T-SQL para SQL Server
Por exemplo, SqlServer e Oracle possuem o operador PIVOT que permite fazer essa transformação de dados. Se trabalhássemos com SqlServer, nossa consulta ficaria assim.
SELECT VendorID ,[250] AS Emp1 ,[251] AS Emp2 ,[252] AS Emp3 ,[253] AS Emp4 ,[254] AS Emp5FROM (SELECT PurchaseOrderID ,EmployeeID ,VendorID FROM Purchasing.PurchaseOrderHeader) pPIVOT( COUNT (PurchaseOrderID) FOR EmployeeID IN ([250], [251], [252], [253], [254])) AS tORDER BY t.VendorID;
Exemplo para MySQL
No MySQL, teremos que usar os meios do SQL. Os dados devem ser agrupados pela coluna do fornecedor – VendorID , e para cada funcionário necessário (EmployeeID ), você precisa criar uma coluna separada com uma função agregada.
No nosso caso, precisamos calcular o número de pedidos, então usaremos a função agregada COUNT.
Na tabela de origem, as informações de todos os funcionários são armazenadas em uma coluna EmployeeID , e precisamos calcular o número de pedidos para um determinado funcionário, portanto, precisamos ensinar nossa função de agregação a processar apenas determinadas linhas.
A função agregada não leva em consideração valores NULL, e usamos essa peculiaridade para nossos propósitos.
Você pode usar o operador condicional IF ou CASE que retornará um valor específico para o funcionário desejado, caso contrário simplesmente retornará NULL; como resultado, a função COUNT contará apenas valores não NULL.
A consulta resultante é a seguinte:
SELECT VendorID, COUNT(IF(EmployeeID =250, PurchaseOrderID, NULL)) AS Emp250, COUNT(IF(EmployeeID =251, PurchaseOrderID, NULL)) AS Emp251, COUNT(IF(EmployeeID =252, PurchaseOrderID, NULL) ) AS Emp252, COUNT(IF(EmployeeID =253, PurchaseOrderID, NULL)) AS Emp253, COUNT(IF(EmployeeID =254, PurchaseOrderID, NULL)) AS Emp254FROM PurchaseOrderHeader pWHERE p.EmployeeID BETWEEN 250 AND 254GROUP BY VendorID;
Ou ainda assim:
VendorID, COUNT(IF(EmployeeID =250, 1, NULL)) AS Emp250, COUNT(IF(EmployeeID =251, 1, NULL)) AS Emp251, COUNT(IF(EmployeeID =252, 1, NULL)) AS Emp252, COUNT(IF(EmployeeID =253, 1, NULL)) AS Emp253, COUNT(IF(EmployeeID =254, 1, NULL)) AS Emp254FROM PurchaseOrderHeader pWHERE p.EmployeeID BETWEEN 250 AND 254GROUP BY VendorID;
Quando executado, um resultado familiar é obtido.
Automatizando o pivô de dados, criando consultas dinamicamente
Como pode ser visto, a consulta tem uma certa consistência, ou seja, todas as colunas transformadas são formadas de maneira semelhante e, para escrever a consulta, é necessário conhecer os valores específicos da tabela. Para formar uma consulta dinâmica, você precisa revisar todos os valores possíveis e só então deve escrever a consulta. Alternativamente, você pode passar essa tarefa para um servidor fazendo com que ele obtenha esses valores e execute dinamicamente a tarefa de rotina.
Vamos voltar ao primeiro exemplo, no qual formamos a nova tabela ProductsNew dos Produtos Antigos tabela. Lá, os valores das propriedades são limitados, e nem podemos conhecer todos os valores possíveis; temos apenas a informação de onde estão armazenados os nomes das propriedades e seu valor. Estas são as Propriedade e Valor colunas, respectivamente.
Todo o algoritmo de criação da consulta SQL se resume a obter os valores, a partir dos quais serão formadas novas colunas e concatenações de partes imutáveis da consulta.
SELECT GROUP_CONCAT( CONCAT( ' MAX(IF(Property =''', t.Property, ''', Value, NULL)) AS ', t.Property ) ) INTO @PivotQueryFROM (SELECT Property FROM ProductOld GROUP BY Property) t;SET @PivotQuery =CONCAT('SELECT ProductID,', @PivotQuery, ' FROM ProductOld GROUP BY ProductID');
A variável @PivotQuery armazenará nossa consulta, o texto foi formatado para maior clareza.
SELECT ProductID, MAX(IF(Property ='Color', Value, NULL)) AS Color, MAX(IF(Property ='Name', Value, NULL)) AS Name, MAX(IF(Property ='ProductNumber) ', Value, NULL)) AS ProductNumber, MAX(IF(Property ='Size', Value, NULL)) AS Size, MAX(IF(Property ='SizeUnitMeasureCode', Value, NULL)) AS SizeUnitMeasureCodeFROM ProductOldGROUP BY ProductID
Após executá-lo, obteremos o resultado desejado correspondente ao esquema da tabela ProductsNew.
Além disso, a consulta da variável @PivotQuery pode ser executada no script usando a instrução EXECUTE do MySQL.
instrução PREPARE FROM @PivotQuery;instrução EXECUTE;instrução DEALLOCATE PREPARE;