Dica do Mês – Concatenando a relação de municípios por Estados através do uso da função Stuff()

Bom dia, boa tarde, boa noite…. Olá pessoal!

Tudo bem? Estou de volta neste finalzinho de férias de começo de ano, com mais um post da sessão Dica do Mês. Você já está preparado para volta as aulas?

Com certeza, todo meu planejamento de atividades, provas, exercícios, seminários, entre outros estão prontos, dediquei os primeiros dias deste mês de janeiro justamente para isso, gosto de me antecipar justamente para ter tempo hábil caso seja necessário fazer alguma alteração.

A primeira dica do mês de 2020 não se relaciona com volta as aulas, na verdade ela surgiu nos últimos dias devido a um estudo que estou fazendo para minha dissertação de mestrado, algo que ainda se encontra meio nebuloso na minha cabeça.

Venho desde o ano de 2017 acompanhando mudanças climáticas nas regiões, estados e municípios do nosso Brasil, o que me fez em 2018 montar um ambiente de estudo com dados reais e hipotéticos para aplicar alguns modelos matemáticos afim de obter dados que possam ser estudados em relação as queimadas ocorridas em pontos específicos.

Dentre estes dados armazenados tenho uma tabela que contempla um pequeno cadastro de Estado, Municípios e Regiões que utilizo em um outro ambiente de Data Warehouse, com base, na metodologia ROLAP (Relational On Line Analitical Processing), técnica que possibilita construir uma estrutura baseada no conceito relacional aplicada a forma de processamento analítica.

Foi baseado mais uma vez neste cenário, em conjunto com os estudos que constantemente venho fazendo que elaborei a ideia para ser apresentada neste post, o qual tem o objetivo básico de demonstrar como podemos fazer uso da função para trabalhar com caracteres string Stuff() existente no Microsoft SQL Server 2008 como podemos concatenar para cada linha de Estados armazenados em minha respectiva tabela a sua lista de municípios, em adicional a quantidade de municípios existentes nesta relação de acordo com o respectivo estado.

Desta forma, sem mais delongas, espero conseguir mitigar a sua curiosidade e apresentar algo interessante. Seja bem-vindo ao post – Dica do Mês – Concatenando a relação de municípios por Estados através do uso da função Stuff().


Introdução

O Brasil considerado um dos maiores países do mundo, tem atualmente um número aproximado de 5570 municípios distribuídos entre Estados e Distrito Federal, através desta distribuição de terras e suas divisões podemos imaginar o quando de acontecimentos acontecem diariamente em cada um destes pedacinhos do nosso país.

Devido a este grande conjunto de possibilidades que podem ser estudadas, como já destaquei no início deste post, venho de 2017 estudando e criando algoritmos que me ajudam a entender alguns comportamentos e acontecimentos, tendo como elemento principal tentar identificar o porque da ocorrência de tal elemento.

Todavia, estes estudos não apresentam comprovação científica, mas me permitem imaginar e criar novos conhecimentos que para o meu aprendizado, tornando uma grande fonte de conhecimento para elaborar práticas e exercícios em minhas aulas de bancos de dados, ou treinamentos ofertados para empresas.

Dentre estes aprendizados, nos últimos dias tive a necessidade de construir um pequeno dashboard em um exercício que será aplicado neste semestre na minha disciplina de Banco de Dados II, o qual consiste apresentar para cada Estado sua relação de Municípios, mas não cada município separado por linha, ou seja, agrupar e concatenar cada município de acordo com seu respectivo estado em uma única linha, construindo então um resultado similar ao apresentado abaixo através das Figura 1 e 2 respectivamente:

Figura 1 – Relação de Estados e seus respectivos Municípios concatenados.

Figura 2 – Relação de Estados, Municípios concatenas e o total de Municípios por Estado.

Você pode estar pensando: “Nossa o Galvão já apresentou o resultado final do post, que coisa sem graça, vou parar por aqui a leitura….” Vou lhe dizer que você estará muito enganado em pensar isso, bem como, errado em interromper a leitura neste momento, pois como já destaquei anteriormente eu vou demonstrar como iremos chegar neste resultado, o qual será elaborado e atingido através da utilização da função Stuff(), ela é o foco principal do post.

Vamos caminhar mais um pouco, conhecendo um pouquinho sobre a função Stuff(), sou sincero a dizer, durante anos eu não me lembrava que ela existia, e não somente isso, eu não sabia fazer uso da mesma. “kkkkkk”

A Função Stuff()

Adicionada ao Microsoft SQL Server a partir da versão 2008, a função Stuff(), tornando-se uma das funções mais dinâmicas e flexíveis, tem como objetivo único possibilitar adicionar em um valor ou expressão string, um outro valor string, fazendo com que o atual venha a ser preenchido, concatenado ou complementando recebendo em seu conteúdo outro conteúdo string. De forma resumida, insere uma cadeia de caracteres em outra cadeia de caracteres. Ela exclui um comprimento especificado de caracteres da primeira cadeia na posição inicial e, em seguida, insere a segunda cadeia na primeira, na posição inicial. Como eu gosto de dizer para meus alunos, a função Stuff() vai estufar: “crescer, tufar, intumescer, tumefazer, empapuçar-se, refogar

Bom, sou sincero em dizer que demorei algum tempo para entender como é possível fazer uso desta função, em qual cenário ou situação a mesma poderia ser aplicada, ainda mais levando-se em consideração a quantidade de parâmetros que ele possui, no caso 4 (quatro) utilizados de forma obrigatória como entrada de valores, definidos da seguinte forma segundo sua documentação oficial:

character_expression (Expressão caractere ou string atual)

É uma expression de dados de caractere. O character_expression pode ser uma constante, uma variável ou uma coluna de dados binários ou de caracteres.

Start (Posição Inicial)

É um valor de inteiro que especifica o local para iniciar a exclusão e a inserção. Se start for negativo ou zero, uma cadeia de caracteres nula será retornada. Se start for maior que a primeira character_expression, uma cadeia de caracteres nula será retornada. Start pode ser do tipo bigint.

Length (Tamanho ou quantidade de caracteres a serem removidos)

É um inteiro que especifica o número de caracteres a serem excluídos. Se length for negativo, uma cadeia de caracteres nula será retornada. Se length for maior que a primeira character_expression, a exclusão ocorrerá até o último caractere da última character_expression. Se length for zero, a inserção ocorrerá no local start e nenhum caractere será excluído. Length pode ser do tipo bigint.

replaceWith_expression (Valor caractere que será adicionado de acordo com o start e length)

É uma expression de dados de caractere. O character_expression pode ser uma constante, uma variável ou uma coluna de dados binários ou de caracteres. Essa expressão substitui os caracteres de length da character_expression começando em start. Fornecer NULL como a replaceWith_expression remove os caracteres sem inserir nada.

Estes são os parâmetros, ou como alguns gostam de dizer argumentos de entrada de dados, que nos permitem utilizar a função Stuff() para retornar um novo valor string, compatível com as combinações realizadas ao longo de seu processamento. Caso os valores informados em cada parâmetro não sejam compatíveis, poderá ser apresentar uma mensagem de erro ou apresentação incorreta do resultado esperado.

Exemplo:

Select 1234589 As Coluna1,

Stuff(1234589,6,2,67) As Coluna2, — Removendo a partir da posição 6, excluindo duas posições, os números 8 e 9, adicionando 6 e 7 —

Stuff(1234589,2,3,910) As Coluna3 — Removendo a partir da posição 2, excluindo três posições, os números 2, 3 e 4 adiconando os número 9 e 10, mantendo 5, 8 e 9

Go

Avançando mais um pouco, temos uma ideia de como a função Stuff() deve ser construida, seus argumentos e suas características. Em adicional apresentei um simples exemplo de como podemos trocar, substituir ou completar valores afim de gerar um novo resultado. Vamos agora aplicar o uso da função Stuff() para obter os resultados apresentados no começo deste post através das Figura 1 e 2.

Chegou a hora de conhecer nosso cenário e fazer uso dele….

Nosso cenário

Para esta dica, você vai se deparar com um cenário bem simples, o que se consiste na utilização de uma tabela denominada MunicipiciosQueimadas, contendo uma relação de nomes reais e também hipotéticos de Estados, Municípios, Regiões e UFs (Unidades Federativas) que contemplam um total de 5577 linhas de registros lógicos.

Para que você não ficar preocupar em ter a necessidade de pesquisar a relação de estados e seus municípios, estou disponibilizando neste post,  o conteúdo desta tabela através do arquivo denominado Tabela-MunicipiosQueimadas.txt, disponível no tradicional forma de arquivo texto.

Logo após você realizar o download, importar os dados para esta nova tabela, deverá obter um conjunto de registros lógicos, similar ao apresentado na Figura 3 abaixo:

Figura 3 – Conteúdo de registros lógicos existentes na tabela MunicipiosQueimadas.

Quero destacar e reforçar que esta tabela foi criada com base em um cenário hipotéticos, o qual é utilizado como forma de estudos, não está sendo considerada regras de normalização, relacionamentos, cardinalidades ou redundância dos dados, principalmente se os nomes dos municípios aqui listados estão corretos.

Neste momento temos nossa tabela importada, com uma pequena massa de dados para trabalharmos, começaremos a construir nosso resultado, imagine que você deseja através de um comando Select retornar os nomes Estados e seus respectivos Municípios, algo bem simples e tradicional, conforme o Bloco de Código 1 apresenta a seguir:

— Bloco de Código 1 – Relação de Estados e Municípios –

Select EstadoMunicipio, NomeMunicipio

From MunicipiosQueimadas

Group By EstadoMunicipio, NomeMunicipio

Go

Ao processar o Bloco de Código 1, você terá o retorno de cada município apresentado em usa respectiva linha, organizado por estado, tudo bem, correto, os dados foram apresentado no forma de relatório, uma listagem.

Mas e se quisermos pensar de uma forma mais analítica, ou seja, sintetizada, resumida, concentrar em cada linha de estado, seu conjunto de município, formando uma estrutura mais agrupado de valores, transformando o seu relatório que era uma longo listagem, em um elemento mais resumido, tendo provavelmente uma quantidade menor de páginas a serem impressas, bem como, uma melhor organização.

Esta pode ser uma das mais diversas possibilidades, uma outra que tive a necessidade de usar, foi baseada no conjunto de Matriz, criando uma matriz de estados, sumarizando e agrupando para cada estado o conjunto de estados em linhas únicas, algo que pode ser muito interessante de ser aplicada no Microsoft Excel ou Power BI.

Este é o ponto central deste post, que entra definitivamente na utilização de função Stuff(), como podemos estabelecer o conceito de concatenação de diversas linhas em uma de acordo com um agrupamento de dados, o que pode ser entendido como uma Matriz de resultados.

Você pode estar pensando, Galvão, se você dize que a função Stuff() nos permite colocar dentro de um outra string um outro conjunto de valores, vamos então fazer uso dela para justamente acrescentar os nomes de municípios na mesma linha. Sim, é isso, mas não será nada tão trivial, e um pouco fora do comum em ser utilizado, mas vamos por partes para entender o que podemos fazer.

Para tentar facilitar nosso caminhada, vou dividir toda estrutura do código que iremos utilizar em partes, explicando cada uma delas até chegarmos no resultado final, antecipo que estaremos fazendo uso de uma técnica conhecida como BlackBox XML (XML Caixa preta), método que recebe este nome, por uma similaridade ao conceito na área de Engenharia de Softwares conhecido como caixa preta, sendo este um trecho ou parte de código que por diversas vezes fazemos uso, ou realizamos uma chamada dele sem conhecer ou ter a certeza de como ele funciona, e ao final o resultado é obtido.

Parte 1 – Utilizando a função Stuff() dentro do comando Select:

Select EstadoMunicipio, Stuff(‘ | ‘,1,0,NomeMunicipio) As ‘Relação de Municípios’

From MunicipiosQueimadas

Group By EstadoMunicipio, NomeMunicipio

Go

 

Ao executarmos a parte 1, você poderá notar que logo após o nome do município é apresentado uma barra vertical, conhecida como pipe (utilizado como delimitador de strings), temos diversas possibilidades de caracteres que podem ser utilizados, para este exemplo, o nome do município foi formado separado por este caractere.

Bom o primeiro passo foi dado, mas ainda não é isso que queremos, precisamos acontecer os outros nomes de municípios, e como vamos fazer? Podemos pensar em usar um Cursor para varrer a tabela, ir armazenando em outra tabela e depois fazermos um select trazendo tudo.

 

A resposta é não, não e não, precisamos fazer isso em um único select e de preferência dentro da função Stuff(). Então a resposta é fácil, vamos fazer uma subquery, sim vamos fazer, mas como? Sabemos que uma subquery é um select dentro do outro, e seu resultado tem que ser bem condicionado para não retornar a tradicional mensagem de erro que informa que a subquery retornou mais de uma linha de resultado.

 

Este pode ser realmente nosso caminho, sendo justamente a solução que teremos que adotar a partir do momento que vamos trabalhar com a função Stuff(), fazer uso de uma subquery que vai retornar internamente os dados no formato XML, e através do uso da instrução Type vamos converter o resultado para um formato compatível com a função Stuff() mais especificamente o tipo de dados Varchar() e apresentarmos o resultado em tela. Parece coisa de louco, não é mesmo? Eu acho, pois é este o conceito BlackBox XML.

 

Por isso, tomei a decisão de quebrar a estrutura do código utilizado para esta dica em partes, com intuito de facilitar o seu entendimento, vamos então conhecer a Parte 2, que apresenta o Select principal:

 

Parte 2 – Select trazendo o nome do Estado de forma agrupada e ordenada:

Select EstadoMunicipio

From MunicipiosQueimadas M2

Group By M2.EstadoMunicipio

Order By M2.EstadoMunicipio

Go

 

Note que estou dando um apelido em tempo de execução para Tabela MunicipiosQueimadas de M2, o qual será importante no momento em que formos utilizar a função Stuff(). Você vai observar que será retornada em tela as 27 linhas que representam os estados e distrito federal.

 

Avançamos para Parte 3, ela é o core do nosso negócio, quanto a magia se torna tecnlogia, é aqui que vai acontecer toda transformação dos dados e posteriormente repassada para o select principal, apresentando anteriormente.

 

Parte 3 – Aplicando o conceito de BlackBox XML, para concatenar as linhas de municípios formando uma para cada estado:

Stuff((Select ‘ | ‘+NomeMunicipio

From MunicipiosQueimadas M1

Where M1.EstadoMunicipio = M2.EstadoMunicipio

Order By M1.EstadoMunicipio

for xml path(”), TYPE).value(‘.’, ‘varchar(max)’),1,2,”) As ‘Relação de Municípios’

 

Olha que loucura este trecho de código, inicialmente a função Stuff() já havíamos utilizado para trazer o Pipe combinado com o nome do Município, tranquilo até aqui. Então vou enumerar os pontos importantes para que você possa entender toda técnica utilizada:

  1. Utilizei a cláusula Where que estabelece uma condição de junção entre a Tabela MunicipiosQueimadas apelidada de M1 utilizadaa na SubQuery em comunicação direta com a M2 utilizada no Select Principal;

 

  1. Cláusula Order By para estabelecer a ordenação dos nomes dos munícipios;

 

  1. Opção For XML Path(‘’), opa, mas porque vamos utilizar um formato XML, devido a necessidade de estabelecer esta concatenação, temos que fazer uso deste formato para eu a função Stuff() possa varrer todos os valores da subquery e agrupar para cada linha;

 

  1. Note que utilize a opção TYPE) que nos permite estabelecer que será o tipo de retorno para os valores XML, pois a função Stuff() não reconhece o datatype XML, somente valores caracteres;

 

  1. É neste ponto que entra a instrução que nos permite passar o value, ou seja, o formato para ser reconhecido como elemento que vai converter o XML em varchar(), no caso varchar(Max) para suportar e garantir o retorno e apresentação completa de todos os dados, tendo como base o sinal de ponto que estabelece o valor de inicio para leitura dos dados, baseado em TYPE).value(‘.’, ‘varchar(max)’); e

 

  1. Por fim outros três parâmetros que a Stuff() necessita, a posição inicial, sendo informado o valor de 1, a quantidade de caracteres que serão suprimidos no caso valor de 2, e o último que representa qual valor ou caractere será colocado no lugar, estou passando aspas simples sem informar qualquer valor para dizer que ele não irá trocar nenhum valor, ao invés de informar Null.

 

Viu, como era melhor ter dividido em partes este código, acredito que ficou bem mais fácil para o nosso entendimento, desta maneira, apresento abaixo o código completo utilizado com a função Stuff() e mais alguns complementos, dentre eles a função LTrim() para remover o espaço inicial do lado esquerdo de cada linha, gerado pela concatenação dos nomes de municípios.

Em suma, apresento o Bloco de Código 2, que contem o código completo idealizado para esta dica:

— Bloco de Código 2 – Utilizando a Função Stuff() para concatenar as linhas –

Select EstadoMunicipio,

Ltrim(Stuff((Select ‘ | ‘+NomeMunicipio

From MunicipiosQueimadas M1

Where M1.EstadoMunicipio = M2.EstadoMunicipio

Order By M1.EstadoMunicipio

for xml path(”), TYPE).value(‘.’, ‘varchar(max)’),1,2,”)) As ‘Relação de Municípios’

From MunicipiosQueimadas M2

Group By M2.EstadoMunicipio

Order By EstadoMunicipio Asc

Go

Por fim, o Bloco de Código 3, que apresenta mais uma adicional, que consiste na quantidade de municípios existentes para cada Estado:

— Bloco de Código 3 – Quantidade de Municípios por Estado —

— Apresentando a quantidade de municípios por Estado —

Select EstadoMunicipio,

Ltrim(Stuff((Select ‘ | ‘+NomeMunicipio

From MunicipiosQueimadas M1

Where M1.EstadoMunicipio = M2.EstadoMunicipio

Order By M1.EstadoMunicipio

for xml path(”), TYPE).value(‘.’, ‘varchar(max)’),1,2,”)) As ‘Relação de Municípios’,

Count(M2.NomeMunicipio) As ‘Total de Municípios Por Estado’

From MunicipiosQueimadas M2

Group By M2.EstadoMunicipio

Order By EstadoMunicipio Asc

Go

Observação: Ressalto que a partir do momento que você executar o Bloco de Código 3 solicitando a apresentação do plano de execução, será apresentando um Warning, alertando sobre a ocorrência de uma transação implícita, sendo esta, necessária para que possa ser possível utilizar o BlackBox XML como elemento de concatenação e união dos dados. Em nenhum momento este post foi idealizado pensando em tratar este tipo de comportamento.

Pronto, agora você já conhece um pouco mais sobre a função Stuff(), em adicional ao conceito BlackBox XML e todo seu potencial, com certeza é algo muito além de uma simples substituição ou troca de caracteres.

Antes de finalizarmos, gostaria de antecipar que em meus ambientes de estudo, pensei em fazer uso da função String_Agg() adicionada a partir do SQL Server 2017, mas uma limitação de sua utilização consiste no tamanho das linhas retornadas, as quais estão ultrapassando a quantidade de 8000 caracteres, limite imposto para retorno de dados na String_Agg().

Seguindo a tradição dos posts anteriores publicados nesta sessão, antes de encerrarmos, gostaria de contar com a sua participação, respondendo a enquete abaixo:

Com isso chegamos ao final de mais um post da sessão Dica do Mês, espero que você tenha gostado, eu como de costume gostei muito.


REFERÊNCIAS

https://docs.microsoft.com/pt-br/sql/t-sql/xml/nodes-method-xml-data-type?view=sql-server-ver15

https://docs.microsoft.com/pt-br/sql/t-sql/xml/binding-relational-data-inside-xml-data?view=sql-server-ver15

https://docs.microsoft.com/pt-br/sql/t-sql/xml/guidelines-for-using-xml-data-type-methods?view=sql-server-ver15

https://docs.microsoft.com/pt-br/sql/t-sql/xml/value-method-xml-data-type?view=sql-server-ver15

https://docs.microsoft.com/pt-br/sql/t-sql/xml/query-method-xml-data-type?view=sql-server-ver15

https://docs.microsoft.com/pt-br/sql/t-sql/functions/stuff-transact-sql

https://docs.microsoft.com/pt-br/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-ver15

https://docs.microsoft.com/pt-br/sql/t-sql/functions/ltrim-transact-sql?view=sql-server-ver15

POSTS ANTERIORES

https://pedrogalvaojunior.wordpress.com/2019/09/29/dica-do-mes-identificando-os-numeros-ausentes-em-uma-sequencia-numerica/

https://pedrogalvaojunior.wordpress.com/2019/05/28/dica-do-mes-analisando-o-comportamento-do-comando-dbcc-clean-table/

https://pedrogalvaojunior.wordpress.com/2019/03/27/dica-do-mes-aplicando-analise-combinatoria-no-microsoft-sql-server/

https://pedrogalvaojunior.wordpress.com/2019/01/22/dica-do-mes-temporal-table-e-o-calor-uma-combinacao-muito-quente/

CONCLUSÃO

Como de costume, tenho um imenso prazer em poder compartilhar um pouco das minhas experiências, estudos e conhecimentos que estou diariamente formando sobre este fantástico Sistema Gerenciador de Banco de Dados chamado Microsoft SQL Server.

Olha este post inicialmente se mostrava ser bem simples e de fácil elaboração, mas no decorrer do mesmo isso não aconteceu, destacar como uma função existente dentro do SQL Server funciona não é nada fácil, ainda mais a função Stuff() que possui quatro parâmetro.

No decorrer deste post, você pode conhecer um pouco mais sobre o nosso país, a quantidade de municípios, estados, regiões, o quanto tudo isso é importante e pode nos possibilitar realizar os mais variados estudos.

Além disso, demonstrei como podemos fazer uso desta função, aplicando o seu conceito de BlackBox XML, transformando o resultado no formato XML em algo reconhecível e tratável pela função Stuff(), fazendo uso da opção Type() que nos permite estabelecer qual será o tipo de dados retornado.

Conhecemos também uma outra possibilidade de combinar dados em uma estrutura baseada no conceito de Data Warehouse, aplicável para um processamento transacional, em adicional evidenciamos as alternativas para se criar uma Matriz de resultados e valores que pode ser aplicada nas mais tracionais análises e ferramentas de tecnologia.

Desta forma chegamos ao final deste desafiador post e mais uma vez saimos vencedores.

Este é o fantástico Microsoft SQL Server, produto tão fascinante que a cada dia eu não consigo deixar de querer estudar, que nos possibilita aprender sempre, transformando conceitos e conhecimentos bem difundidos em fontes de sabedoria e alternativas modernas para a solução de problemas.

Agradecimentos

Agradeço a você por sua atenção e visita ao meu blog. Fique à vontade para enviar suas críticas, sugestões, observações e comentários.

Nos encontramos no próximo post da sessão Dica do Mês a ser publicado em breve.

Um forte abraço.

Até mais.

Autor: Junior Galvão - MVP

Profissional com vasta experiência na área de Tecnologia da Informação e soluções Microsoft. Pós-Graduado no Curso de Gestão e Engenharia de Processos para Desenvolvimento de Software com RUP na Faculdade FIAP – Faculdade de Informática e Administração Paulista de São Paulo. Graduado no Curso Superior em Gestão da Tecnologia de Sistemas de Informação pela Uninove – Campus São Roque. Formação MCDBA Microsoft, autor de artigos acadêmicos e profissionais postados em Revistas, Instituições de Ensino e WebSistes. Meu primeiro contato com tecnologia ocorreu em 1994 após meus pais comprarem nosso primeiro computador, ano em que as portas para este fantástico mundo se abriram. Neste mesmo ano, comecei o de Processamento de Dados, naquele momento a palavra TI não existia, na verdade a Tecnologia da Informação era conhecida como Computação ou Informática, foi assim que tudo começou e desde então não parei mais, continuando nesta longa estrada até hoje. Desde 2001 tenho atuado como Database Administrator – Administrador de Banco de Dados – SQL Server em tarefas de Administração, Gerenciamento, Migração de Servidores e Bancos de Dados, Estratégias de Backup/Restauração, Replicação, LogShipping, Implantação de ERPs que utilizam bancos SQL Server, Desenvolvimento de Funções, Stored Procedure, entre outros recursos. Desde 2008 exerço a função de Professor Universitário, para as disciplinas de Banco de Dados, Administração, Modelagem de Banco de Dados, Programação em Banco de Dados, Sistemas Operacionais, Análise e Projetos de Sistemas, entre outras. Experiência na Coordenação de Projetos de Alta Disponibilidade de Dados, utilizando Database Mirroring, Replicação Transacional e Merge, Log Shipping, etc. Trabalhei entre 2011 e 2017 como Administrador de Banco de Dados e Coordenador de TI no FIT – Instituto de Tecnologia da Flextronics, atualmente exerço a função de Professor Universitário na FATEC São Roque. CTO da Galvão Tecnologia, consultoria especializada em Gestão de TI, Administração de Servidores Windows Server, Bancos de Dados Microsoft SQL Server e Virtualização. Possuo titulação Oficial Microsoft MVP e reconhecimentos: MCC, MSTC, MIE e MTAC.