T-SQL Tips - Convertendo linhas em colunas com o operador PIVOT

/* Olá Caros Amigos dos Dados!

      Mais um operador interessante que deveria estar na ToolBox de todo DBA/Desenvolvedor SQL Server. O Operador PIVOT.

      Disponivel a partir da versão 2005/2008 para converter linhas em colunas (e vice versa), o Pivot é um só um pouco dificil de entender, mas depois que voce
pega o jeito percebe que é bem facil e eficiente nas suas consultas.

      Então mãos a obra!
 

      Em uma base de dados de um sistema de e-commerce, temos a tabela Fluxo_Pedido que armazena as datas em que cada processo de um pedido foi realizado conforme Figura 1 
*/


/*
      Nosso cliente deseja a seguinte visualização dessa informação
*/



/* Agora dê uma olhada na syntax padrão do operador PIVOT */


SELECT <Coluna non-pivoted >,

    [Primeira coluna pivoted] AS <alias da coluna>,
    [Segunda coluna pivoted] AS <alias da coluna>,
    ...
    [Ultima coluna pivoted] AS <alias da coluna>
FROM
    (<Consulta fonte>)  AS <alias da consulta fonte>

PIVOT --<< AQUI ESTÁ O OPERADOR!

(
    <Valor agregado>
FOR
    [Coluna do cabeçalho]
    IN (
        [Primeira coluna pivoted],
        [Segunda coluna pivoted]...
        [Ultima coluna pivoted]
       )
) AS <alias da tabela pivot>


/*
  Agora dando nomes ao bois!

  A coluna non pivoted é a coluna que agrupa as linhas. No nosso caso é o Numero do Pedido, pois teremos uma linha para cada pedido

As colunas pivoted são os valores que passarão a ser colunas da tabela.Aqui colocamos a coluna Etapa e criaremos uma coluna para cada etapa (Solicitacao, Pagamento, Transportadora,Finalizacao)

  Veja como ficou:
*/ 

SELECT
     NumeroPedido,
    [Solicitação],
    [Pagamento],
    [Transportadora],
    [Finalizacao]
FROM
    (<Consulta fonte>)  AS <alias da consulta fonte>
PIVOT
(
    <Valor agregado>
FOR
    [Coluna do cabeçalho]
    IN (
         [Primeira coluna pivoted],
         [Segunda coluna pivoted]
         ...
         [Ultima coluna pivoted])
) AS <alias da tabela pivot>

 /*
      Nossa consulta fonte é um SELECT dos dados da tabela Fluxo_Pedido.

      Devemos incluir no select a coluna non-pivoted, a coluna que possui os valores pivoted e o campo que será exibido nas células (DataEtapa)

      ou seja:

      SELECT NumeroPedido,Etapa  ,DataEtapa  FROM Fluxo_Pedido
*/   

           

SELECT
      NumeroPedido,
    [Solicitação],
    [Pagamento],
    [Transportadora],
    [Finalizacao]
FROM
    (SELECT NumeroPedido,Etapa  ,DataEtapa  FROM Fluxo_Pedido)  AS Consulta_Fonte

PIVOT
(
    <Valor agregado>
FOR
    [Coluna do cabeçalho]
    IN (
        [Primeira coluna pivoted],
        [Segunda coluna pivoted]
        ...
        [Ultima coluna pivoted]
       )
) AS <alias da tabela pivot>


/*
      E por fim vamos dar os parametros do operador PIVOT.

      O valor agregado deve ser uma função de agrupamento (MAX(), MIN(),COUNT(),etc...) e a coluna que vamos no nosso "miolo".

      Como vamos exibir a data em que foi executada cada etapa vamos usar MIN(DataEtapa)

      Após o FOR indicamos a coluna cabeçalho (Etapa) e repetimos as colunas pivoted.
*/

SELECT
    NumeroPedido,
    [Solicitação],
    [Pagamento],
    [Transportadora],
    [Finalizacao]
FROM
    (SELECT NumeroPedido,Etapa  ,DataEtapa  FROM Fluxo_Pedido)  AS Consulta_Fonte
PIVOT
(
   MAX(DataEtapa)
FOR
      Etapa
    IN (
        [Solicitação],
        [Pagamento],
        [Transportadora],
        [Finalizacao]
       )
) AS TabelaPivot
 

/* E pronto!! Temos uma PIVOT novinha em folha!

  Obrigado pela leitura e espero ter ajudado você em seu dia a dia

Comente abaixo, sugira na nossa caixinha de sugestõe e se tiver duvidas me mande um email: fjantunes@gmail.com.br

Abraços!
*/

TroubleShooting - Msg 952, Level 16, State 1 Database 'MinhaBase' is in transition. Try the statement later

/*
  Olá amigos!
 
  Ja falei que a vida de DBAs é cheia de aventura? Essa semana o caso abaixo elevou o nível da minha adrenalina. Sem aviso e no meio do dia uma base de produção critica ficou inacessível sem razão aparente.

      Ao tentar acessa-la com o Use Database recebia a seguinte mensagem
*/   

Msg 952, Level 16, State 1, Line 1
Database 'MinhaBase' is in transition. Try the statement later.

-- ou na tradução do SQL

Msg 952, Level 16, State 1, Line 1
Banco de dados 'MinhaBase' em transição. Tente a instrução mais tarde.  


/*
      E nunca mais voltava!
     
      Após alguns minutos de desespero, descobrimos que o erro foi causado por um comando ALTER DATABASE MinhaBase SET OFFLINE. ( meu colega DBA que originou o comando jura de pé junto que só tinha acabado de fazer um backup e eu acredito nele)
      Como o banco estava cheio de usuários o SQL estava aguardando que todos se desconectassem da base para concluir o comando e ao mesmo tempo bloqueou todos os novos usuários de se conectarem naquela base.

      Para solucionar tivemos que encontrar o session id do comando com a sys.dm_exec_requests
*/   

select session_id, command, wait_resource 
from sys.dm_exec_requests
WHERE
      command = 'ALTER DATABASE'
     
-- No wait_ressource está a indicação do banco de dados que está sendo alvo do comando
-- E  matar o session id que obtemos
     
kill 59

-- E tudo volta ao normal como mágica.... ufa...