Como posso simplesmente alternar colunas com linhas no SQL? Existe algum comando simples para transpor?
ou seja, vire este resultado:
Paul | John | Tim | Eric
Red 1 5 1 3
Green 8 4 3 5
Blue 2 2 9 1
nisso:
Red | Green | Blue
Paul 1 8 2
John 5 4 2
Tim 1 3 9
Eric 3 5 1
PIVOT
parece muito complexo para este cenário.
sql
sql-server
tsql
pivot
Edezzie
fonte
fonte
Respostas:
Existem várias maneiras de transformar esses dados. Em sua postagem original, você afirmou que
PIVOT
parece muito complexo para este cenário, mas pode ser aplicado facilmente usando oUNPIVOT
ePIVOT
funções do SQL Server.No entanto, se você não tiver acesso a essas funções, isso pode ser replicado usando
UNION ALL
paraUNPIVOT
e, em seguida, uma função agregada com umaCASE
instrução paraPIVOT
:Criar a tabela:
Versão de união de todos, agregado e CASE:
Vejo SQL Fiddle com Demo
O
UNION ALL
executa a eliminaçãoUNPIVOT
dos dados transformando as colunasPaul, John, Tim, Eric
em linhas separadas. Em seguida, você aplica a função de agregaçãosum()
com acase
instrução para obter as novas colunas para cadacolor
.Versão Estática Unpivot e Pivot:
As funções
UNPIVOT
ePIVOT
no servidor SQL tornam essa transformação muito mais fácil. Se você conhece todos os valores que deseja transformar, pode codificá-los em uma versão estática para obter o resultado:Vejo SQL Fiddle com Demo
A consulta interna com
UNPIVOT
executa a mesma função queUNION ALL
. Ele pega a lista de colunas e a transforma em linhas, oPIVOT
então realiza a transformação final em colunas.Versão dinâmica do pivô:
Se você tiver um número desconhecido de colunas (
Paul, John, Tim, Eric
em seu exemplo) e, em seguida, um número desconhecido de cores para transformar, você pode usar sql dinâmico para gerar a lista paraUNPIVOT
e entãoPIVOT
:Vejo SQL Fiddle com Demo
A versão dinâmica consulta ambos
yourtable
e asys.columns
tabela para gerar a lista de itens paraUNPIVOT
ePIVOT
. Isso é então adicionado a uma string de consulta a ser executada. A vantagem da versão dinâmica é se você tem uma lista de alteração decolors
e / ounames
isso irá gerar a lista em tempo de execução.Todas as três consultas produzirão o mesmo resultado:
fonte
Isso normalmente requer que você conheça TODOS os rótulos de coluna E linha de antemão. Como você pode ver na consulta abaixo, os rótulos estão todos listados inteiramente nas operações UNPIVOT e (re) PIVOT.
Configuração do esquema do MS SQL Server 2012 :
Consulta 1 :
Resultados :
Notas Adicionais:
fonte
Eu gostaria de apontar mais algumas soluções para transpor colunas e linhas em SQL.
O primeiro é - usando o CURSOR. Embora o consenso geral na comunidade profissional seja ficar longe dos cursores do SQL Server, ainda há casos em que o uso de cursores é recomendado. De qualquer forma, os cursores nos apresentam outra opção para transpor linhas em colunas.
Expansão vertical
Semelhante ao PIVOT, o cursor tem a capacidade dinâmica de anexar mais linhas à medida que seu conjunto de dados se expande para incluir mais números de política.
Expansão horizontal
Ao contrário do PIVOT, o cursor se destaca nesta área, pois é capaz de se expandir para incluir o documento recém-adicionado, sem alterar o script.
Análise de desempenho
A principal limitação de transpor linhas em colunas usando CURSOR é uma desvantagem associada ao uso de cursores em geral - eles têm um custo de desempenho significativo. Isso ocorre porque o Cursor gera uma consulta separada para cada operação FETCH NEXT.
Outra solução para transpor linhas em colunas é usar XML.
A solução XML para transpor linhas em colunas é basicamente uma versão ideal do PIVOT, pois trata da limitação da coluna dinâmica.
A versão XML do script aborda essa limitação usando uma combinação de Caminho XML, T-SQL dinâmico e algumas funções embutidas (isto é, STUFF, QUOTENAME).
Expansão vertical
Semelhante ao PIVOT e ao Cursor, as políticas recém-adicionadas podem ser recuperadas na versão XML do script sem alterar o script original.
Expansão horizontal
Ao contrário do PIVOT, os documentos recém-adicionados podem ser exibidos sem alterar o script.
Análise de desempenho
Em termos de IO, as estatísticas da versão XML do script são quase semelhantes às do PIVOT - a única diferença é que o XML tem uma segunda varredura da tabela dtTranspose, mas desta vez de um cache lógico de leitura de dados.
Você pode encontrar mais informações sobre essas soluções (incluindo alguns exemplos reais de T-SQL) neste artigo: https://www.sqlshack.com/multiple-options-to-transposing-rows-into-columns/
fonte
Com base nesta solução do bluefeet, aqui está um procedimento armazenado que usa sql dinâmico para gerar a tabela transposta. Exige que todos os campos sejam numéricos, exceto para a coluna transposta (a coluna que será o cabeçalho da tabela resultante):
Você pode testá-lo com a tabela fornecida com este comando:
fonte
Estou fazendo
UnPivot
primeiro e armazenando os resultadosCTE
e usando oCTE
emPivot
operação .Demo
fonte
Acrescentando à excelente resposta de @Paco Zarate acima, se você quiser transpor uma tabela que tem vários tipos de colunas, adicione isso ao final da linha 39, para que transponha apenas
int
colunas:Aqui está a consulta completa que está sendo alterada:
Para encontrar outros
system_type_id
, execute este:fonte
Gosto de compartilhar o código que estou usando para transpor um texto dividido com base na resposta do + bluefeet. Nesta abordagem, estou implementado como um procedimento no MS SQL 2005
Estou misturando esta solução com as informações sobre como ordenar as linhas sem ordenar por ( SQLAuthority.com ) e a função de divisão no MSDN ( social.msdn.microsoft.com )
Quando você executa o produto
você obtém o próximo resultado
fonte
Desta forma, converta todos os dados de Filelds (colunas) na tabela para registro (linha).
fonte
Consegui usar a solução de Paco Zarate e ela funciona perfeitamente. Tive de adicionar uma linha ("SET ANSI_WARNINGS ON"), mas pode ser algo exclusivo da maneira como usei ou chamei. Há um problema com meu uso e espero que alguém possa me ajudar com isso:
A solução funciona apenas com uma tabela SQL real. Eu tentei com uma tabela temporária e também uma tabela na memória (declarada), mas não funciona com elas. Portanto, em meu código de chamada, crio uma tabela em meu banco de dados SQL e chamo SQLTranspose. Novamente, funciona muito bem. É exatamente o que eu quero. Aqui está o meu problema:
Para que a solução geral seja realmente dinâmica, preciso criar aquela tabela onde armazeno temporariamente as informações preparadas que estou enviando para SQLTranspose "em tempo real" e, em seguida, excluo essa tabela quando SQLTranspose é chamado. A exclusão da tabela está apresentando um problema com meu plano de implementação final. O código precisa ser executado a partir de um aplicativo de usuário final (um botão em um formulário / menu do Microsoft Access). Quando eu uso este processo SQL (criar uma tabela SQL, chamar SQLTranspose, excluir tabela SQL), o aplicativo do usuário final atinge um erro porque a conta SQL usada não tem o direito de eliminar uma tabela.
Portanto, acho que existem algumas soluções possíveis:
Encontre uma maneira de fazer SQLTranspose funcionar com uma tabela temporária ou uma variável de tabela declarada.
Descubra outro método para a transposição de linhas e colunas que não exija uma tabela SQL real.
Descobrir um método apropriado para permitir que a conta SQL usada por meus usuários finais elimine uma tabela. É uma única conta SQL compartilhada codificada em meu aplicativo Access. Parece que a permissão é um privilégio do tipo dbo que não pode ser concedido.
Reconheço que parte disso pode justificar outro tópico e pergunta separados. Porém, como existe a possibilidade de que uma solução possa ser simplesmente uma maneira diferente de fazer a transposição de linhas e colunas, farei meu primeiro post aqui neste tópico.
EDIT: Eu também substituí sum (valor) por max (valor) na 6ª linha do final, como Paco sugeriu.
EDITAR:
Eu descobri algo que funciona para mim. Não sei se é a melhor resposta ou não.
Tenho uma conta de usuário somente leitura que é usada para executar procedimentos armazenados e, portanto, gerar saída de relatório de um banco de dados. Como a função SQLTranspose que criei só funcionará com uma tabela "legítima" (não uma tabela declarada e não uma tabela temporária), tive que descobrir uma maneira de uma conta de usuário somente leitura criar (e depois excluir) uma tabela .
Concluí que, para meus objetivos, não há problema em que a conta do usuário tenha permissão para criar uma tabela. O usuário ainda não conseguiu excluir a tabela. Minha solução foi criar um esquema onde a conta do usuário é autorizada. Então, sempre que eu criar, usar ou excluir essa tabela, refiro-a com o esquema especificado.
Emiti primeiro este comando de uma conta 'sa' ou 'sysadmin': CREATE SCHEMA ro AUTHORIZATION
Sempre que me refiro à minha tabela "tmpoutput", eu a especifico como este exemplo:
drop table ro.tmpoutput
fonte