servidor SQL: linhas converter para colunas
-
03-07-2019 - |
Pergunta
Eu tenho uma tabela com colunas sales(int)
, month(int)
. Quero recuperar soma das vendas correspondentes a cada mês. Preciso ouput em forma de 12 colunas correspondentes a cada mês em que haverá um único registro contendo vendas para para cada coluna (meses).
Solução
Você deve dar uma olhada PIVOT para comutação de linhas por colunas . Isso evita que uma instrução SELECT para cada mês. Algo parecido com isto:
DECLARE @salesTable TABLE
(
[month] INT,
sales INT
)
-- Note that I use SQL Server 2008 INSERT syntax here for inserting
-- multiple rows in one statement!
INSERT INTO @salesTable
VALUES (0, 2) ,(0, 2) ,(1, 2) ,(1, 2) ,(2, 2)
,(3, 2) ,(3, 2) ,(4, 2) ,(4, 2) ,(5, 2)
,(6, 2) ,(6, 2) ,(7, 2) ,(8, 2) ,(8, 2)
,(9, 2) ,(10, 2) ,(10, 2) ,(11, 2) ,(11, 2)
SELECT [0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11]
FROM
(
SELECT [month], sales
FROM @salesTable
) AS SourceTable
PIVOT
(
SUM(sales)
FOR [month] IN ([0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11])
) AS PivotTable
Outras dicas
Não é bonito ... mas isso funciona bem
SELECT
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 1) [Sales1],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 2) [Sales2],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 3) [Sales3],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 4) [Sales4],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 5) [Sales5],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 6) [Sales6],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 7) [Sales7],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 8) [Sales8],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 9) [Sales9],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 10) [Sales10],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 11) [Sales11],
(SELECT SUM(Sales) FROM SalesTable WHERE [Month] = 12) [Sales12]
Aqui está uma forma alternativa de escrever o pivô que lhe dá um pouco mais de controle (especialmente sobre os nomes das colunas). É também um pouco mais fácil para gerar SQL dinâmico para.
É semelhante a resposta de Robin, mas tem a vantagem de apenas bater a mesa uma vez:
select
Sales1 = sum( case when Month = 1 then Sales end )
, Sales2 = sum( case when Month = 2 then Sales end )
, Sales3 = sum( case when Month = 3 then Sales end )
-- etc..
from SalesTable;
Eu fiz algumas investigações, e parece que o novo operador de pivô é apenas açúcar sintaxe para este tipo de consulta. Os planos de consulta acabam procurando idênticas.
Como um aparte interessante, o operador UNPIVOT parece também ser apenas açúcar sintaxe. Por exemplo:
Se você tem uma tabela como:
Create Table Sales ( JanSales int, FebSales int, MarchSales int...)
Você pode escrever:
select unpivoted.monthName, unpivoted.sales
from Sales s
outer apply (
select 'Jan', JanSales union all
select 'Feb', FebSales union all
select 'March', MarchSales
) unpivoted( monthName, sales );
E obter os dados não dinamizados ...
Você pode fazê-lo com OLAP . Aqui é um outro link para a documentação MSDN sobre o tema .
Com OLAP, você pode criar um cubo com as informações que você tem, com o layout que você precisa.
Se você não quer ir por esse caminho, você terá que criar tabelas de resumo com .NET, Java, TransacSQL, ou seu idioma preferido para manipular dados SQLServer.
Para colunas facilmente transpor para linhas com seus nomes que você deve usar XML. No meu blog eu estava descrito isso com exemplo: link