iMaster Developers

Wagner Crivelini

Wagner Crivelini

Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.
  • Publicou
    83
    Artigo(s)
    book
  • Visualizados
    688900
    Vezes
    eye
  • Desde
    2010
    clock
awardArtigos Publicados
Wagner Crivelini
SQL Server
Azure SQL DB: trabalhando com listas e arrays (Parte 1)

Listas, arrays, matrizes, vetores. Independente do nome que você prefira usar, cedo ou tarde vai ter que lidar com estes tipos de estrutura de dados. Estas não são estruturas comuns no mundo relacional, porém temos que ter em mente que hoje a diversidade de formatos e estruturas é uma regra no mundo corporativo. Mais que…

Wagner Crivelini
SQL Server
Tabelas Temporais Particionadas - Criando Auditoria de Dados em Tabelas Grandes

Desde a versão 2016 do SQL Server está disponível o recurso para auditoria automática de dados através das Tabelas Temporais.

Wagner Crivelini
Data
Entendendo os Recursos de Criptografia do AZURE SQL Database

Recentemente precisei apresentar para um cliente um material com noções básicas dos recursos de criptografia disponíveis no AZURE SQL Database.

Wagner Crivelini
SQL Server
Bate-bola com Grafos e SQL Server Parte 3 – Visualizando Dados

Desta vez o enfoque é na análise de dados, mais especificamente a visualização dos grafos que foram criados. Eu prefiro começar a conversa com o porquê e depois falo do como. Ou seja, começo mostrando para que serve a visualização dos grafos e, na sequência, apresento como construir um dashboard simples destes grafos. Analisando Dados…

Wagner Crivelini
SQL Server
Bate-bola com Grafos e SQL Server Parte 2 – Implementando o Modelo

Neste artigo dou sequência no estudo de grafos usando a base de dados European Soccer Database, publicada por Hugo Mathien no KAGGLE. Desta vez vou tratar da implementação do modelo de grafos definido no artigo anterior usando o SQL Server 2019. Apresento também algumas consultas e análises sobre estes grafos. Criando as Tabelas Definido o…

Wagner Crivelini
SQL Server
Bate-bola com Grafos e SQL Server Parte 1 – Definindo o Modelo

É espantosa a popularização que as novas tecnologias de dados alcançaram. A utilização de Grafos para análise de dados e o SQL Server…

Wagner Crivelini
SQL Server
Agrupando Dados com GROUPING SETS

SQL Server: Chega ser estranho pensar que trabalhemos com tanta frequência com sumarização de dados e ainda assim a opção GROUPING SETS seja desconhecida

Wagner Crivelini
Banco de Dados
Consultando arquivos JSON no SQL Server

No seguinte artigo, Wagner Crivelini mostra como consultar arquivos JSON no SQL Server e apresenta exemplos.

Wagner Crivelini
Banco de Dados
Melhorando a Experiência do Usuário com Azure Search - Parte 05: apresentando resultados

Continuando a sua série de artigos sobre o Azure Search, o autor apresenta exemplos elementares para os principais recursos de navegação e apresentação disponíveis neste serviço.

Wagner Crivelini
Banco de Dados
Melhorando a Experiência do Usuário com Azure Search - Parte 04: recursos avançados

Dando continuidade a sua série de artigos sobre o Azure Search, neste artigo o autor apresenta algumas funcionalidades mais sofisticadas da plataforma.

visualizando 10 de 83
Publicidade
\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003C\u002Ftbody\u003E\r\n\u003C\u002Ftable\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003EO output que vai gerar para a leitura do arquivo JSON apresentado na Tabela 1 é:\u003C\u002Fspan\u003E\r\n\u003Ctable\u003E\r\n\u003Ctbody\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cb\u003Ekey\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003Evalue\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003Etype\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EOrderNumber\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E1\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECustomer\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E1\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAdress\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E[           {      \"Name\": \"Casa\",            \"Street\": \"Rua 5, no 42\",   ...  }      ]\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E4\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EProductID\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E[ \"AAF\",\"AAR\",\"AAS\",\"AAT\",\"AAV\",\"AAW\" ]\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E4\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003C\u002Ftbody\u003E\r\n\u003C\u002Ftable\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003ECaso se deseje lidar com o esquema interno do JSON, substituímos o SELECT da linha 24 por uma declaração que reflita este esquema, como vemos a seguir.\u003C\u002Fspan\u003E\r\n\u003Ctable\u003E\r\n\u003Ctbody\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E01\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E02\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E03\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E04\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E05\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E06\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E07\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E08\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E09\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E10\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E11\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E12\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E13\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E14\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E15\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E16\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E17\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESELECT\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E J\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EOrderNumber\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E J\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECustomer\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E P\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003Evalue\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E ProductID\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E A\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EName\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E A\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EStreet\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E A\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECity\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E A\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EState\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EFROM\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E  \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EOPENJSON \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E @json\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E' window.__SERVER_VARS__ = {"applicationRestUrl":"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-json","applicationBaseUrl":"https:\u002F\u002Fimasters.com.br"} \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EWITH \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E  OrderNumber\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.OrderNumber'\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E Customer   \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.Customer'\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E Adress     \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003ENVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EMAX\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E'$.Adress'\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EJSON\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E ProductID  \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003ENVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EMAX\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E'$.ProductID'\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EJSON\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E J\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003ECROSS\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAPPLY\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EOPENJSON \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJ\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EProductID\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E' window.__SERVER_VARS__ = {"applicationRestUrl":"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-json","applicationBaseUrl":"https:\u002F\u002Fimasters.com.br"} \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E  P\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003ECROSS\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAPPLY\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EOPENJSON \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJ\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAdress\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E  \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EWITH \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E  \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EName\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E         \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.Name'\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E Street       \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.Street'\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E City         \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.City'\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EState\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E        \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.State'\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E A\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003C\u002Ftbody\u003E\r\n\u003C\u002Ftable\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003EObserve que a primeira chamada OPENJSON define a estrutura principal do arquivo, estabelece as colunas OrderNumber, Customer, Adress e ProductID. Nessa definição, as duas últimas colunas foram classificadas como novos JSONs, de modo que se pudesse expandir seu conteúdo.\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EAcontece que o tratamento dessas duas colunas “JSON” ocorre de forma distinta. Apesar de ambas invocarem o operador OPENJSON, a primeira delas, Adress, é uma lista de JSONs e por isso foi expandida em novas colunas, do mesmo modo que se tratou a estrutura principal.\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003ENo caso da coluna ProductID, trata-se de uma lista de valores associada à marcação “ProductID”. Isto requer um tratamento diferenciado, embora tenha solução simples e elegante. Aqui basta usar o operador OPENJSON e na cláusula SELECT apontar para a lista de valores usando a sintaxe “\u003C\u002Fspan\u003E\u003Ci\u003E\u003Cspan style=\"font-weight: 400;\"\u003EMeuAlias.value\u003C\u002Fspan\u003E\u003C\u002Fi\u003E\u003Cspan style=\"font-weight: 400;\"\u003E”. No exemplo acima, usei o alias “P”.\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EO output dessa nova consulta é uma tabela de valores.\u003C\u002Fspan\u003E\r\n\u003Ctable\u003E\r\n\u003Ctbody\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cb\u003EOrderNumber\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003ECustomer\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003EProductID\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003EName\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003EStreet\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003ECity\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cb\u003EState\u003C\u002Fb\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAF\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECasa\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua 5, no 42\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESão Paulo\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESP\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAF\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EEscritorio\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua D Pedro, no 500\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERio de Janeiro\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERJ\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAR\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECasa\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua 5, no 42\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESão Paulo\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESP\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAR\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EEscritorio\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua D Pedro, no 500\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERio de Janeiro\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERJ\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAS\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECasa\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua 5, no 42\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESão Paulo\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESP\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAS\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EEscritorio\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua D Pedro, no 500\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERio de Janeiro\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERJ\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAT\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECasa\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua 5, no 42\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESão Paulo\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESP\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAT\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EEscritorio\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua D Pedro, no 500\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERio de Janeiro\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERJ\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAV\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECasa\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua 5, no 42\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESão Paulo\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESP\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAV\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EEscritorio\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua D Pedro, no 500\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERio de Janeiro\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERJ\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAW\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECasa\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua 5, no 42\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESão Paulo\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESP\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E574895677\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJohn Doe\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EAAW\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003EEscritorio\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERua D Pedro, no 500\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERio de Janeiro\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ERJ\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003C\u002Ftbody\u003E\r\n\u003C\u002Ftable\u003E\r\n\u003Ch3\u003E\u003Cb\u003EAvaliando a Performance\u003C\u002Fb\u003E\u003C\u002Fh3\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003EDe modo geral, a performance das operações envolvendo operador OPENJSON não é boa. Para entender melhor este impacto, vamos avaliar três situações diferentes. \u003C\u002Fspan\u003E\r\n\u003Ch3\u003E\u003Cb\u003ECaso 1\u003C\u002Fb\u003E\u003C\u002Fh3\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003EAqui consideramos o plano de execução da consulta que gerou a listagem apresentada acima. O procedimento envolve duas consultas, sendo que a segunda, que trata da formatação do JSON, responde por 96% de todo custo do processo: 0,6605. O tempo de execução foi de 01 segundo.\u003C\u002Fspan\u003E\r\n\u003Ch3\u003E\u003Cimg class=\"alignnone size-full wp-image-156777\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2022\u002F01\u002Fcaso1.png\" alt=\"\" width=\"585\" height=\"435\" \u002F\u003E\u003C\u002Fh3\u003E\r\n\u003Ch3\u003E\u003Cb\u003ECaso 2\u003C\u002Fb\u003E\u003C\u002Fh3\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003EDesta vez vamos consultar o mesmo arquivo JSON, mas vamos desconsiderar a lista de JSONs da marcação “Adress”. A primeira parte do procedimento continua idêntica, mas segunda vai usar a seguinte declaração:\u003C\u002Fspan\u003E\r\n\u003Ctable\u003E\r\n\u003Ctbody\u003E\r\n\u003Ctr\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003E01\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E02\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E03\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E04\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E05\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E06\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E07\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E08\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E09\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003Ctd\u003E\u003Cspan style=\"font-weight: 400;\"\u003ESELECT\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E J\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EOrderNumber\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E J\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003ECustomer\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E P\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003Evalue\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E ProductID\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EFROM\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E  \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EOPENJSON \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E @json\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E' window.__SERVER_VARS__ = {"applicationRestUrl":"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-json","applicationBaseUrl":"https:\u002F\u002Fimasters.com.br"} \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EWITH \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E  OrderNumber\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.OrderNumber'\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E Customer   \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E200\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003E'$.Customer'\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E Adress     \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003ENVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EMAX\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E'$.Adress'\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EJSON\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E ProductID  \u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003ENVARCHAR\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EMAX\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E'$.ProductID'\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EJSON\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAS\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E J\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003ECROSS\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EAPPLY\u003C\u002Fspan\u003E \u003Cspan style=\"font-weight: 400;\"\u003EOPENJSON \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E(\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EJ\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E.\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003EProductID\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E,\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E' window.__SERVER_VARS__ = {"applicationRestUrl":"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-json","applicationBaseUrl":"https:\u002F\u002Fimasters.com.br"} \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E)\u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E  P\u003C\u002Fspan\u003E\u003C\u002Ftd\u003E\r\n\u003C\u002Ftr\u003E\r\n\u003C\u002Ftbody\u003E\r\n\u003C\u002Ftable\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003ENeste caso, vamos converter em tabela a lista de valores da coluna ProductID. O custo da primeira consulta é exatamente o mesmo do caso anterior, porém a segunda consulta roda 50 vezes mais rápido, tendo seu custo reduzido para 0.0130 (contra 0,6605 no Caso1)!!! O tempo de execução praticamente não mudou (01 seg).\u003C\u002Fspan\u003E\r\n\r\n\u003Cimg class=\"alignnone size-full wp-image-156778\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2022\u002F01\u002Fcaso2.png\" alt=\"\" width=\"587\" height=\"441\" \u002F\u003E\r\n\r\n\u003Cb\u003ECaso 3\u003C\u002Fb\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EAgora vamos avaliar uma expansão do Caso 2. Usaremos outro arquivo JSON com mesmo esquema, porém dessa vez o campo ProductID tratará uma lista com 100 mil valores ao invés de apenas 6.\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EA única alteração no procedimento é reapontar o script para ler o arquivo “exemplo2.json”, cujo tamanho é de 811 Kb, ao invés do arquivo “exemplo1.json”, de 445 bytes.\u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EObserve no plano de execução abaixo que, apesar de estar lendo um arquivo quase 2 mil vezes maior, os custos da primeira e segunda consultas são exatamente os mesmos que observamos no Caso 2! O tempo de execução subiu, mas muito pouco: apenas 06 segundos.\u003C\u002Fspan\u003E\r\n\r\n\u003Cb\u003E\u003Cimg class=\"alignnone size-full wp-image-156779\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2022\u002F01\u002Fcaso3.png\" alt=\"\" width=\"588\" height=\"439\" \u002F\u003E\r\nComentários Finais\u003C\u002Fb\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EComo vimos neste estudo, a preparação para acesso a arquivos JSON armazenados em contas de armazenamento requer alguns cuidados especiais. Porém, uma vez configurados, a leitura desses arquivos no Azure SQL DB funciona muito bem. \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003ESobre a leitura de listas de valores em formato JSON, os dois pontos que se destacam são:\u003C\u002Fspan\u003E\r\n\u003Col\u003E\r\n \t\u003Cli style=\"font-weight: 400;\" aria-level=\"1\"\u003E\u003Cspan style=\"font-weight: 400;\"\u003EA sintaxe usada para leitura dessas estruturas é bastante simples. Basta definir a coluna como JSON, abri-la com o operador OPENJSON e apontar para seus valores com a expressão \u003C\u002Fspan\u003E\u003Cspan style=\"font-weight: 400;\"\u003E“\u003C\u002Fspan\u003E\u003Ci\u003E\u003Cspan style=\"font-weight: 400;\"\u003EMeuAlias.value\u003C\u002Fspan\u003E\u003C\u002Fi\u003E\u003Cspan style=\"font-weight: 400;\"\u003E”.\u003C\u002Fspan\u003E\u003C\u002Fli\u003E\r\n \t\u003Cli style=\"font-weight: 400;\" aria-level=\"1\"\u003E\u003Cspan style=\"font-weight: 400;\"\u003EO custo de execução de consultas envolvendo listas de valores é praticamente invariável. O impacto do tamanho da lista na performance da operação é muito menor do que se poderia esperar.\u003C\u002Fspan\u003E\u003C\u002Fli\u003E\r\n\u003C\u002Fol\u003E\r\n\u003Cspan style=\"font-weight: 400;\"\u003ENo próximo artigo, a conversa é sobre o uso de listas em arquivos CSV. \u003C\u002Fspan\u003E\r\n\r\n\u003Cspan style=\"font-weight: 400;\"\u003EAté lá!\u003C\u002Fspan\u003E","excerpt":"\u003Cp\u003EListas, arrays, matrizes, vetores. Independente do nome que você prefira usar, cedo ou tarde vai ter que lidar com estes tipos de estrutura de dados. Estas não são estruturas comuns no mundo relacional, porém temos que ter em mente que hoje a diversidade de formatos e estruturas é uma regra no mundo corporativo. Mais que…\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server\u002Fazure-sql-db-trabalhando-com-listas-e-arrays-parte-1","date":"11 jan, 2022","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2022\u002F01\u002F11075531\u002FNews-Blog-Graphic.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":83,"views_count":688900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"SQL Server","slug":"sql-server","id":7212,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server"}],"tags":[{"title":"AZURE SQL DB","slug":"azure-sql-db","id":8875,"link":"https:\u002F\u002Fimasters.com.br\u002Fazure-sql-db"},{"title":"sql server","slug":"sql-server-2","id":324,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server-2"}],"relateds":[],"seo":[],"type":"post"},{"id":155851,"title":"Tabelas Temporais Particionadas - Criando Auditoria de Dados em Tabelas Grandes","content":"Desde a versão 2016 do SQL Server está disponível o recurso para auditoria automática de dados através das Tabelas Temporais.\r\n\r\nEu mesmo publiquei em 2018 aqui no iMasters \u003Ca href=\"https:\u002F\u002Fimasters.com.br\u002Fdata\u002Fsql-server-auditando-dados-com-tabelas-temporais\"\u003Eum artigo tratando deste recurso\u003C\u002Fa\u003E que, além de útil, é muito fácil de implementar.\r\n\r\nRecentemente precisei implementar este recurso em um cliente. Porém, neste caso, tratava-se de uma tabela com mais de 2 bilhões de registros, o que exigiu alguns cuidados especiais, como descrevo a seguir.\r\n\u003Ch2\u003E\u003Cstrong\u003EComo Lidar com Tabelas Grandes\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nUma solução muito usada para melhorar performance de tabelas com muitos registros é o uso de particionamento. Também tratei deste tema aqui no iMasters, em \u003Ca href=\"https:\u002F\u002Fimasters.com.br\u002Fdata\u002Ftrabalhando-com-tabelas-particionadas\"\u003Eum artigo de 2017\u003C\u002Fa\u003E.\r\n\r\nA ideia é subdividir a tabela em inúmeros “blocos” menores. Na prática, vemos a tabela como um só componente e a tratamos como se fosse uma tabela normal. Mas fisicamente ela está segmentada em N partes, sendo que os dados serão alocados em cada partição segundo o valor de uma coluna que chamamos de chave de particionamento.\r\n\r\nNão é preciso dizer que o bom ou mau desempenho das operações com estas tabelas depende muito da escolha da chave de particionamento.\r\n\r\nÉ comum considerar colunas com datas como candidatas para chave de particionamento. Assim, datas próximas tenderão a ser agrupadas na mesma partição.\r\n\r\nUm efeito desta escolha é que novos dados tenderão a ser escritos na mesma partição. Em função disso, neste caso teremos uma partição “quente” para escrita, enquanto todas as demais só terão acesso de leitura.\r\n\u003Ch2\u003EComo Implementar Auditoria de Dados\u003C\u002Fh2\u003E\r\nApesar de simples, a auditoria oferecida pelas tabelas temporais é bastante eficiente e, além de tudo, ocorre automaticamente.\r\n\r\nAo se criar uma tabela temporal, é automaticamente gerada uma tabela histórica com as mesmas colunas que a original.\r\n\r\nQuando ocorre uma atualização ou exclusão de dados da tabela principal (a tabela temporal), o registro antigo é movido para a tabela secundária (chamada tabela histórica).\r\n\r\nAli veremos que este registro terá uma data de validade inicial: \u003Cstrong\u003ESysStartTime\u003C\u002Fstrong\u003E. Esta data informa quando aquele registro sofreu sua ação, seja ela uma inserção ou alteração. Existe também a data em que aquela versão do registro foi “eliminada”: \u003Cstrong\u003ESysEndTime\u003C\u002Fstrong\u003E, que trata de quando o registro foi alterado ou excluído da tabela\r\ntemporal.\r\n\r\nQuando o registro é inserido, ele é escrito na tabela temporal tendo como \u003Cstrong\u003ESysStartTime\u003C\u002Fstrong\u003E a data em que ocorreu este evento. E, como se poderia prever, a coluna \u003Cstrong\u003ESysEndTime\u003C\u002Fstrong\u003E terá o valor NULO. Porém, nada acontece na tabela histórica, visto que esta é a primeira versão do registro.\r\n\r\nQuando tal registro for alterado ou excluído, a versão antiga é movida para a tabela histórica, informando em \u003Cstrong\u003ESysEndTime\u003C\u002Fstrong\u003E a data em que esta versão foi “eliminada”. E tudo isso é controlado automaticamente pelo mecanismo do SQL Server.\r\n\u003Ch2\u003ETabela Temporal Particionada\u003C\u002Fh2\u003E\r\nQual problema pode acontecer ao se criar uma tabela temporal particionada? Normalmente, se estamos particionando uma tabela por ser muito grande, provavelmente a tabela histórica associada a ela também será muito grande. Consequentemente, é altamente recomendável que a tabela histórica também seja\r\nparticionada.\r\n\r\nPorém, se executarmos o processo normal de criação de uma tabela temporal, será gerada uma tabela histórica sem partições. Não importa que seu script esteja particionando a tabela temporal. A histórica não será convertida automaticamente em tabela particionada.\r\n\r\nSendo assim, é necessária uma pequena adaptação do processo, criando primeiramente a tabela histórica com as partições. E depois se cria a tabela temporal particionada que irá apontar para a tabela histórica que já se criou.\r\nÍndices adicionais que sejam criados para a tabela temporal e\u002Fou tabela histórica devem igualmente ser particionados.\r\n\r\nDesta maneira, seu ambiente estará adequado às necessidades e à escala do seu banco de dados.\r\n\u003Ch2\u003ECriando os Objetos\u003C\u002Fh2\u003E\r\n\u003Cp id=\"E495\" class=\"x-scope qowt-word-para-1\"\u003E\u003Cspan id=\"E496\" class=\"qowt-font10-Arial\"\u003EO que dá mais trabalho na criação dessa solução é a \u003C\u002Fspan\u003E\u003Cspan id=\"E497\" class=\"qowt-font10-Arial\"\u003Esequência\u003C\u002Fspan\u003E\u003Cspan id=\"E498\" class=\"qowt-font10-Arial\"\u003E de tarefas a serem executadas.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E499\" class=\"x-scope qowt-word-para-1\"\u003E\u003Cspan id=\"E500\" class=\"qowt-font10-Arial\"\u003EEm primeiro lugar, é preciso criar o \u003C\u002Fspan\u003E\u003Cspan id=\"E501\" class=\"qowt-font10-Arial\"\u003Efilegroups\u003C\u002Fspan\u003E\u003Cspan id=\"E502\" class=\"qowt-font10-Arial\"\u003E que serão usados.\u003C\u002Fspan\u003E\u003Cspan id=\"E503\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003Cspan id=\"E504\" class=\"qowt-font10-Arial\"\u003EQuando se trabalha com o SQL Server nativo, é\u003C\u002Fspan\u003E\u003Cspan id=\"E505\" class=\"qowt-font10-Arial\"\u003E altamente recomendável que se use um \u003C\u002Fspan\u003E\u003Cspan id=\"E506\" class=\"qowt-font10-Arial\"\u003Efilegroup\u003C\u002Fspan\u003E\u003Cspan id=\"E507\" class=\"qowt-font10-Arial\"\u003E para cada partição para garantir melhor gerenciamento do banco de dados.\u003C\u002Fspan\u003E\u003Cspan id=\"E508\" class=\"qowt-font10-Arial\"\u003E (No caso d\u003C\u002Fspan\u003E\u003Cspan id=\"E509\" class=\"qowt-font10-Arial\"\u003Eo\u003C\u002Fspan\u003E\u003Cspan id=\"E510\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003Cspan id=\"E511\" class=\"qowt-font10-Arial\"\u003EAzure SQL Database\u003C\u002Fspan\u003E\u003Cspan id=\"E512\" class=\"qowt-font10-Arial\"\u003E, que é \u003C\u002Fspan\u003E\u003Cspan id=\"E513\" class=\"qowt-font10-Arial\"\u003Eum serviço PAAS\u003C\u002Fspan\u003E\u003Cspan id=\"E514\" class=\"qowt-font10-Arial\"\u003E, não temos controle sobre \u003C\u002Fspan\u003E\u003Cspan id=\"E515\" class=\"qowt-font10-Arial\"\u003Eos \u003C\u002Fspan\u003E\u003Cspan id=\"E516\" class=\"qowt-font10-Arial\"\u003Edatafiles\u003C\u002Fspan\u003E\u003Cspan id=\"E517\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003Cspan id=\"E518\" class=\"qowt-font10-Arial\"\u003Eusados, por isso normalmente usamos o \u003C\u002Fspan\u003E\u003Cspan id=\"E519\" class=\"qowt-font10-Arial\"\u003Efilegroup\u003C\u002Fspan\u003E\u003Cspan id=\"E520\" class=\"qowt-font10-Arial\"\u003E padrão, o PRIMARY)\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\r\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E--Criando filegroups\r\n\r\nUSE MASTER\r\n\r\nGO\r\n\r\n\r\n\r\nALTER DATABASE MeuBD ADD FILEGROUP fg2018 ;\r\n\r\nALTER DATABASE MeuBD ADD FILEGROUP fg2019 ;\r\n\r\nALTER DATABASE MeuBD ADD FILEGROUP fg2020 ;\r\n\r\nALTER DATABASE MeuBD ADD FILEGROUP fg2021 ;\r\n\r\nALTER DATABASE MeuBD ADD FILEGROUP fg2022 ;\r\n\r\nALTER DATABASE MeuBD ADD FILEGROUP fg2023 ;\r\n\r\nGO\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\nNo passo seguinte, criamos os datafiles usados por cada partição.\r\n\r\n \r\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E-- define 1 or more datafile per partition\r\n\r\nUSE MASTER\r\n\r\nGO\r\n\r\n\r\n\r\nALTER DATABASE meuBD ADD FILE ( NAME = N'part2018_1', \r\n\r\n FILENAME = N'C:\\Data\\meuDB_part2018_1.ndf' , \r\n\r\n SIZE = 100MB , MAXSIZE = 100GB , FILEGROWTH = 100MB \r\n\r\n) TO FILEGROUP [fg2018];\r\n\r\n\r\n\r\nALTER DATABASE meuBD ADD FILE ( NAME = N'part2019_1', \r\n\r\n FILENAME = N'C:\\Data\\meuBD_part2019_1.ndf' , \r\n\r\n SIZE = 100MB , MAXSIZE = 100GB , FILEGROWTH = 100MB \r\n\r\n) TO FILEGROUP [fg2019];\r\n\r\n\r\n\r\nALTER DATABASE meuBD ADD FILE ( NAME = N'part2020_1', \r\n\r\n FILENAME = N'C:\\Data\\meuBD_part2020_1.ndf' , \r\n\r\n SIZE = 100MB , MAXSIZE = 100GB , FILEGROWTH = 100MB \r\n\r\n) TO FILEGROUP [fg2020];\r\n\r\n\r\n\r\nALTER DATABASE meuBD ADD FILE ( NAME = N'part2021_1', \r\n\r\n FILENAME = N'C:\\Data\\meuBD_part2021_1.ndf' , \r\n\r\n SIZE = 100MB , MAXSIZE = 100GB , FILEGROWTH = 100MB \r\n\r\n) TO FILEGROUP [fg2021];\r\n\r\n\r\n\r\nALTER DATABASE meuBD ADD FILE ( NAME = N'part2022_1', \r\n\r\n FILENAME = N'C:\\Data\\meuBD_part2022_1.ndf' , \r\n\r\n SIZE = 100MB , MAXSIZE = 100GB , FILEGROWTH = 100MB \r\n\r\n) TO FILEGROUP [fg2022] ;\r\n\r\n\r\n\r\nALTER DATABASE meuBD ADD FILE ( NAME = N'part2023_1', \r\n\r\n FILENAME = N'C:\\Data\\meuBD_part2023_1.ndf' , \r\n\r\n SIZE = 100MB , MAXSIZE = 100GB , FILEGROWTH = 100MB \r\n\r\n) TO FILEGROUP [fg2023];\r\n\r\nGO\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n \r\n\r\n\u003Cspan id=\"E926\" class=\"qowt-font10-Arial\"\u003ENo passo 3, se define \u003C\u002Fspan\u003E\u003Cspan id=\"E927\" class=\"qowt-font10-Arial\"\u003Ea função de particionamento.\u003C\u002Fspan\u003E\r\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E--Funcao de particionamento\r\n\r\nUSE meuBD\r\n\r\nGO\r\n\r\n\r\n\r\nCREATE PARTITION FUNCTION [fnPartitioningByYear](DATETIME) AS RANGE RIGHT FOR VALUES \r\n\r\n\t(\r\n\r\n\t -- tipo de particionamento: “RANGE RIGHT”\r\n\r\n\t --NAO INFORMAR o primeiro intervalo (01\u002Fjan a 31\u002Fdez\u002F2018) \r\n\r\n\t --dados anteriores a 01\u002Fjan\u002F2019 serao gravados naquela particao\r\n\r\n\t '20190101 00:00:00'\r\n\r\n\t, '20200101 00:00:00'\r\n\r\n\t, '20210101 00:00:00'\r\n\r\n\t, '20220101 00:00:00'\r\n\r\n\t, '20230101 00:00:00'\r\n\r\n\t)\r\n\r\nGO\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n \r\n\r\nAgora é a vez de criar o esquema de particionamento dos dados.\r\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E-- Esquema de particionamento \r\n\r\nUSE meuBD\r\n\r\nGO\r\n\r\n\r\n\r\nCREATE PARTITION SCHEME [schPartitioningByYear]\r\n\r\nAS PARTITION [fnPartitioningByYear]\r\n\r\nTO ( fg2018, fg2019, fg2020, fg2021, fg2022, fg2023)\r\n\r\nGO\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n \r\n\r\n\u003Cspan id=\"E1052\" class=\"qowt-font10-Arial\"\u003EFinalmente podemos criar a primeira tabela, que\u003C\u002Fspan\u003E\u003Cspan id=\"E1053\" class=\"qowt-font10-Arial\"\u003E no nosso caso\u003C\u002Fspan\u003E\u003Cspan id=\"E1054\" class=\"qowt-font10-Arial\"\u003E dever ser\u003C\u002Fspan\u003E\u003Cspan id=\"E1055\" class=\"qowt-font10-Arial\"\u003E necessariamente a tabela histórica. Como esta será também uma tabela particionada, é \u003C\u002Fspan\u003E\u003Cspan id=\"E1056\" class=\"qowt-font10-Arial\"\u003Erequerido que a chave de particionamento faça parte de um índice clusterizado ou chave primária.\u003C\u002Fspan\u003E\r\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E-- Criar tabela historica\r\n\r\nUSE meuBD\r\n\r\nGO\r\n\r\n\r\n\r\nCREATE TABLE test_temporal_HISTORY(\r\n\r\n id bigint NOT NULL,\r\n\r\n initdate datetime NOT NULL,\r\n\r\n SysStartTime datetime2(7) NOT NULL,\r\n\r\n SysEndTime datetime2(7) NOT NULL\r\n\r\n) ON [schPartitioningByYear](initdate)\r\n\r\n\r\n\r\nGO\r\n\r\n\r\n\r\nCREATE CLUSTERED INDEX ix_test_temporal_History \r\n\r\nON test_temporal_HISTORY (id , initdate)\r\n\r\nGO\r\n\r\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n\u003Cspan id=\"E1142\" class=\"qowt-font10-Arial\"\u003EAgora, finalmente, definimos a tabela temporal, com sua sintaxe especial. Note que estamos apontando para uma tabela que já existe\u003C\u002Fspan\u003E\u003Cspan id=\"E1144\" class=\"qowt-font10-Arial\"\u003E (e que usa o mesmo modelo de colunas e tipos de dados). Além disso, ela também está associada a um\u003C\u002Fspan\u003E\u003Cspan id=\"E1145\" class=\"qowt-font10-Arial\"\u003E esquema de particionamento.\u003C\u002Fspan\u003E\r\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E-- Criar tabela temporal\r\n\r\nUSE meuBD\r\n\r\nGO\r\n\r\n\r\n\r\nCREATE TABLE dbo.test_temporal(\r\n\r\n id bigint NOT NULL,\r\n\r\n initdate datetime NOT NULL,\r\n\r\n SysStartTime datetime2(7) GENERATED ALWAYS AS ROW START NOT NULL,\r\n\r\n SysEndTime datetime2(7) GENERATED ALWAYS AS ROW END NOT NULL,\r\n\r\nCONSTRAINT PK_test PRIMARY KEY CLUSTERED \r\n\r\n(\r\n\r\n id ASC,\r\n\r\n initdate\r\n\r\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ,\r\n\r\n PERIOD FOR SYSTEM_TIME ([SysStartTime], [SysEndTime])\r\n\r\n) ON [schPartitioningByYear](initdate)\r\n\r\nWITH\r\n\r\n(\r\n\r\nSYSTEM_VERSIONING = ON ( HISTORY_TABLE = dbo.test_temporal_HISTORY )\r\n\r\n)\r\n\r\nGO\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n\u003Cspan id=\"E1335\" class=\"qowt-font10-Arial\"\u003EFinalmente temos o ambiente pronto para uso. A consulta a seguir verifica \u003C\u002Fspan\u003E\u003Cspan id=\"E1336\" class=\"qowt-font10-Arial\"\u003Equal o tipo de cada tabela e \u003C\u002Fspan\u003E\u003Cspan id=\"E1337\" class=\"qowt-font10-Arial\"\u003Ese \u003C\u002Fspan\u003E\u003Cspan id=\"E1338\" class=\"qowt-font10-Arial\"\u003Eelas são particionadas ou não.\u003C\u002Fspan\u003E\r\n\u003Cpre\u003E\u003Ccode class=\"language-sql\"\u003E--verificacao\r\n\r\nUSE meuBD\r\n\r\nGO\r\n\r\n\r\n\r\nSELECT db_name() + '.' + OBJECT_SCHEMA_NAME(i.object_id) + '.' + OBJECT_NAME(i.object_id) AS TAB\r\n\r\n\t, MIN(temporal_type_desc) AS temporal_type_desc, CASE WHEN MAX(pstat.partition_number) > 1 THEN 'PARTITIONED' ELSE 'REGULAR' END AS Partition_Type, MAX(pstat.partition_number) AS Partition_count \r\n\r\nFROM sys.dm_db_partition_stats pstat\r\n\r\n\tINNER JOIN sys.indexes i ON pstat.object_id = i.object_id AND pstat.index_id = i.index_id\r\n\r\n\tLEFT JOIN sys.partition_schemes ps on ps.data_space_id = i.data_space_id \r\n\r\n\tLEFT JOIN sys.partition_range_values rv on rv.function_id = ps.function_id AND rv.boundary_id = pstat.partition_number\r\n\r\n\tLEFT JOIN sys.tables t on i.object_id = t.object_id \r\n\r\nWHERE OBJECT_SCHEMA_NAME(i.object_id) <> 'sys' \r\n\r\nGROUP BY i.object_id\r\n\r\nHAVING MAX(pstat.partition_number) > 1\r\n\r\nGO\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F12\u002FTABELAa.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-155855\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F12\u002FTABELAa.jpg.jpg\" alt=\"\" width=\"588\" height=\"111\" \u002F\u003E\u003C\u002Fa\u003E\r\n\u003Ch2 id=\"E1618\" class=\"qowt-stl-Heading3 x-scope qowt-word-para-3\"\u003E\u003Cstrong\u003E\u003Cspan id=\"E1619\"\u003ECo\u003C\u002Fspan\u003E\u003Cspan id=\"E1620\"\u003Ementários Finais\u003C\u002Fspan\u003E\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\n\u003Cp id=\"E1621\" class=\"x-scope qowt-word-para-1\"\u003E\u003Cspan id=\"E1622\" class=\"qowt-font10-Arial\"\u003EA implementação de tabelas temporais particionadas, como se pode ver, é simples\u003C\u002Fspan\u003E\u003Cspan id=\"E1623\" class=\"qowt-font10-Arial\"\u003E.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E1624\" class=\"x-scope qowt-word-para-1\"\u003E\u003Cspan id=\"E1625\" class=\"qowt-font10-Arial\"\u003EA questão principal aqui é se dar conta da necessidade de particionamento da tabela histórica\u003C\u002Fspan\u003E\u003Cspan id=\"E1626\" class=\"qowt-font10-Arial\"\u003E. Se não tomarmos providências esta\u003C\u002Fspan\u003E\u003Cspan id=\"E1627\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003Cspan id=\"E1628\" class=\"qowt-font10-Arial\"\u003Etabela\u003C\u002Fspan\u003E\u003Cspan id=\"E1629\" class=\"qowt-font10-Arial\"\u003E ser\u003C\u002Fspan\u003E\u003Cspan id=\"E1630\" class=\"qowt-font10-Arial\"\u003Eá\u003C\u002Fspan\u003E\u003Cspan id=\"E1631\" class=\"qowt-font10-Arial\"\u003E criada automaticamente sem partição nenhuma\u003C\u002Fspan\u003E\u003Cspan id=\"E1632\" class=\"qowt-font10-Arial\"\u003E e muito provavelmente o assunto será esquecido.\u003C\u002Fspan\u003E\u003Cspan id=\"E1633\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E1634\" class=\"x-scope qowt-word-para-1\"\u003E\u003Cspan id=\"E1635\" class=\"qowt-font10-Arial\"\u003ENeste cenário, o\u003C\u002Fspan\u003E\u003Cspan id=\"E1636\" class=\"qowt-font10-Arial\"\u003E problema só ser\u003C\u002Fspan\u003E\u003Cspan id=\"E1637\" class=\"qowt-font10-Arial\"\u003Eá\u003C\u002Fspan\u003E\u003Cspan id=\"E1638\" class=\"qowt-font10-Arial\"\u003E descoberto quando a solução já estive\u003C\u002Fspan\u003E\u003Cspan id=\"E1639\" class=\"qowt-font10-Arial\"\u003Er\u003C\u002Fspan\u003E\u003Cspan id=\"E1640\" class=\"qowt-font10-Arial\"\u003E em produção\u003C\u002Fspan\u003E\u003Cspan id=\"E1641\" class=\"qowt-font10-Arial\"\u003E e começar a haver problemas de performance para consultas da tabela histórica.\u003C\u002Fspan\u003E\u003Cspan id=\"E1642\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003Cspan id=\"E1643\" class=\"qowt-font10-Arial\"\u003EE então os esforços necessários para correção serão muito maiores e mais impactantes.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E","excerpt":"\u003Cp\u003EDesde a versão 2016 do SQL Server está disponível o recurso para auditoria automática de dados através das Tabelas Temporais.\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server\u002Ftabelas-temporais-particionadas-criando-auditoria-de-dados-em-tabelas-grandes","date":"5 jan, 2021","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F08\u002F24172315\u002F1768.sql_logob.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":83,"views_count":688900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"SQL Server","slug":"sql-server","id":7212,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server"}],"tags":[{"title":"sql","slug":"sql","id":706,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql"},{"title":"sql server","slug":"sql-server-2","id":324,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server-2"},{"title":"Tabelas temporais","slug":"tabelas-temporais","id":8793,"link":"https:\u002F\u002Fimasters.com.br\u002Ftabelas-temporais"}],"relateds":[],"seo":[],"type":"post"},{"id":155290,"title":"Entendendo os Recursos de Criptografia do AZURE SQL Database","content":"Recentemente precisei apresentar para um cliente um material com noções básicas dos recursos de criptografia disponíveis no AZURE SQL Database.\r\n\r\nSe você já entende os recursos disponíveis no SQL Server 2016 ou superior, aviso que este artigo não vai muito além disso, a não ser talvez pela integração do SQL DATABASE com o KEY VAULT.\r\n\r\nSe esse não é o seu caso, apresento a seguir cada um desses recursos, assim como exemplos de implementação.\r\n\u003Ch2\u003E\u003Cstrong\u003EEncriptação Default dos Serviços Azure\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nTodos os dados gravados em AZURE, seja em qual serviço for, já dispõem de um nível básico de proteção através da Encriptação em Repouso.\r\n\r\nNo caso, estamos falando de discos encriptados. Ela usa chaves simétricas, o que significa que tanto a escrita do dado (encriptação) como a leitura dele (decriptação) são feitas usando a mesma chave.\r\n\r\nEste tipo de encriptação oferece proteção contra ataques físicos ao hardware (isto é: aos datacenters que proveem os serviços de AZURE).\r\n\r\nPara qualquer efeito prático, eu diria que este é o último nível de proteção esperado para os seus dados. Obviamente é muito mais importante para a sua empresa se proteger contra os ataques feitos pela rede. E aí entram os recursos de encriptação para o seu banco de dados.\r\n\u003Ch2\u003E\u003Cstrong\u003EEncriptação ao Nível de Banco de Dados\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nAssim como o SQL Server on-premises, o serviço do AZURE SQL DATABASE usa basicamente 03 tipos de criptografia:\r\n\u003Cul\u003E\r\n \t\u003Cli\u003ECriptografia de Dados Transparente (TDE)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EALWAYS ENCRYPTED\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EMáscara de Dados Dinâmica (DDM)\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\nEstes métodos são completamente diferentes entre si, pois TDE é uma criptografia aplicada à base de dados inteira, ALWAYS ENCRYPTED trabalha com encriptação ao nível de coluna e DDM, finalmente, não é de fato uma encriptação, mas sim um mascaramento lógico dos dados.\r\n\r\nA seguir, apresento mais detalhes de cada método e exemplos de implementação.\r\n\u003Ch2\u003E\u003Cstrong\u003ECriptografia de Dados Transparente (TDE)\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nUma vez que TDE se aplica ao nível de base dados, tudo dentro da base, assim como seus backups, é encriptado.\r\nNaturalmente, os processos de encriptação do dado no momento da escrita e sua decriptação durante a leitura são automáticos e se utilizam de uma chave simétrica que é gerenciada pelo serviço.\r\n\r\nA implementação do TDE no AZURE SQL Database é muito simples e é implementada por default em todas as novas bases de dados que você criar.\r\n\r\nPara mudar esta configuração nas bases antigas ou desativar a encriptação em bases novas (o que não me parece boa ideia), acesse o portal do AZURE, localize a base de dados que deseja configurar, role o menu até encontrar o grupo SECURITY e escolha a guia TRANSPARENT DATA ENCRYPTION, marcando o serviço como ON ou OFF.\r\n\r\n[caption id=\"attachment_155291\" align=\"alignnone\" width=\"2215\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F06\u002FTDE1.jpg\"\u003E\u003Cimg class=\"wp-image-155291 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F06\u002FTDE1.jpg\" alt=\"\" width=\"2215\" height=\"1105\" \u002F\u003E\u003C\u002Fa\u003E Figura 1: Configurando TDE no AZURE SQL DATABASE[\u002Fcaption]\r\n\r\nEntenda que existem duas chaves de encriptação aqui. Uma é a Database Encryption Key (DEK), que efetivamente encripta os dados da base. Com a configuração apresentada acima, significa que ativamos a DEK desta base de dados.\r\n\r\nQuando se usa geo-replicação em bases com TDE, por exemplo, a(s) base(s) secundária(s) compartilha(m) a mesma chave de encriptação da base primária, ou seja, a mesma DEK.\r\n\r\nMas existe um mecanismo de proteção desta chave, que é oferecido por um segundo certificado, que chamamos de Protetor do TDE. O protetor atua ao nível de servidor e, por default, a chave criptográfica deste protetor é gerenciada pelo próprio serviço do AZURE SQL Database. Todo ciclo de vida desta chave (criação, prazo de validade e\r\nexpiração) é gerenciado automaticamente.\r\n\u003Ch2\u003E\u003Cstrong\u003ETDE-BYOK\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nExiste uma outra forma de trabalho, em que o usuário assume o controle do gerenciamento da chave de encriptação do protetor do TDE. Esta alternativa é chamada de BYOK (sigla em inglês para “Bring Your Own Key”).\r\n\r\nPara sua implementação, é preciso respeitar 2 principais requisitos:\r\n1. SQL DATABASE precisa necessariamente estar integrado ao AAD.\r\n2. KEY VAULT precisa necessariamente ter a opção SOFT-DELETE ativada (para evitar problemas com chaves apagadas acidentalmente). Esta opção está disponível no momento da criação do cofre. Caso deseje usar um cofre que foi criado sem esta funcionalidade, você pode configurá-lo usando POWERSHELL. Importante saber que,\r\numa vez ativada, esta mudança é irreversível.\r\n\r\nUma vez resolvidos estes requisitos, basta criar uma chave no KEY VAULT (via portal do AZURE, se preferir) e buscar o servidor SQL no portal do AZURE, já que agora estamos tratando da chave criptográfica do Protetor do TDE.\r\n\r\nNa sequência, procure o grupo SECURITY e escolha a guia TRANSPARENT DATA ENCRYPTION novamente. Você verá uma imagem ligeiramente diferente e ali poderá escolher a opção CUSTOMER-MANAGED KEY, informar o nome do Key Vault a ser usado e apontar para chave que havia criado lá. Ao final, basta salvar a nova\r\nconfiguração.\r\n\r\n[caption id=\"attachment_155294\" align=\"alignnone\" width=\"451\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner01.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155294 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner01.jpg.jpg\" alt=\"\" width=\"451\" height=\"557\" \u002F\u003E\u003C\u002Fa\u003E Figura 2: Configurando TDE-BYOK[\u002Fcaption]\r\n\r\nEsta operação não envolve downtime e não requer nova encriptação de dados. É apenas a troca da chave usada pelo protetor do TDE.\r\n\u003Ch2\u003E\u003Cstrong\u003EALWAYS ENCRYPTED\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nEsta criptografia trata de encriptação de informações sigilosas, como número de documentos, cartões de crédito etc. Por isso é implementada ao nível de coluna.\r\n\r\nDesse modo, o mecanismo do SQL DB não tem acesso à chave de encriptação. O dado é encriptado na aplicação, enviado como uma coluna binária e então armazenado como tal. Seu significado é desconhecido a menos que se tenha acesso à chave utilizada.\r\n\r\nO resultado aqui é que a coluna só é legível para quem acessar o dado através do driver adequado. Nem mesmo os proprietários do banco terão acesso a esta informação (apenas ao valor encriptado, é claro).\r\n\r\n[caption id=\"attachment_155297\" align=\"alignnone\" width=\"471\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner02.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155297 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner02.jpg.jpg\" alt=\"\" width=\"471\" height=\"172\" \u002F\u003E\u003C\u002Fa\u003E Figura 3: Implementação de ALWAYS ENCRYPTED[\u002Fcaption]\r\n\r\nÉ possível implementar o ALWAYS ENCRYPTED através de dois métodos diferentes:\r\n\u003Cul\u003E\r\n \t\u003Cli\u003ECom Chave Determinística: de modo que se possa fazer comparações de igualdade (leia-se: permite usar o campo encriptado na cláusula WHERE)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EChave aleatória (“randômica”): encripta dados de maneira aleatória, oferecendo maior segurança. Porém, você não vai conseguir usar este campo para fazer comparações, porque o resultado encriptado não é necessariamente sempre o mesmo. Para mais informações, consulte a documentação citada nas LEITURAS SUGERIDAS.\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\nO processo de encriptação usa duas chaves: a chave mestra e a chave de encriptação da coluna. Uma funcionalidade que não é default apesar de ser de extrema importância é armazenar estas chaves no AZURE KEY VAULT, para garantir a maior proteção possível. O roteiro a seguir mostra todas as etapas do processo.\r\n\r\nPrimeiramente eu criei a tabela desejada, ainda sem encriptação. IMPORTANTE: utilizei o SQL Server Management Studio versão 18.5 (ou SSMS). Versões antigas podem apresentar assistentes e configurações diferentes.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002FWagner03.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-155298\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002FWagner03.jpg.jpg\" alt=\"\" width=\"592\" height=\"75\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nMeu objetivo era proteger os dados da coluna DOCUMENTO, que armazenaria o CPF do usuário. Então o passo seguinte foi procurar a guia SECURITY para o meu banco de dados, cliquei o botão direito e escolhi ALWAYS ENCRYPTED KEYS. A chave mestra foi a primeira a ser criada.\r\n\r\n[caption id=\"attachment_155300\" align=\"alignnone\" width=\"316\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner04.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155300 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner04.jpg.jpg\" alt=\"\" width=\"316\" height=\"362\" \u002F\u003E\u003C\u002Fa\u003E Figura 4: Definição de chaves do ALWAYS ENCRYPTED[\u002Fcaption]\r\n\r\nO assistente pediu que informasse o nome da chave mestra, onde ela seria armazenada (escolha sempre AZURE KEY VAULT, caso já tenha contratado o serviço). Então informei minha assinatura dos serviços AZURE, o nome do cofre que desejava usar. Finalmente cliquei em GENERATE KEY e então OK.\r\n\r\n[caption id=\"attachment_155301\" align=\"alignnone\" width=\"434\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner05.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155301 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner05.jpg.jpg\" alt=\"\" width=\"434\" height=\"392\" \u002F\u003E\u003C\u002Fa\u003E Figura 5: Definição da chave mestra (COLUMN MASTER KEY)[\u002Fcaption]\r\n\r\nEm seguida, repeti o processo para criar uma chave de encriptação de coluna. Comecei clicando botão direito sobre o grupo desejado, informei o nome da nova chave e a chave mestra que iria usar (aquela que acabei de criar na etapa anterior).\r\n\r\nNeste ponto, já tinha os elementos para encriptar a coluna desejada. Então localizei a tabela que continha a coluna a ser encriptada, cliquei botão direito outra vez e ativei o assistente ENCRYPT COLUMNS.\r\n\r\n[caption id=\"attachment_155302\" align=\"alignnone\" width=\"360\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner06.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155302 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner06.jpg.jpg\" alt=\"\" width=\"360\" height=\"336\" \u002F\u003E\u003C\u002Fa\u003E Figura 6: Encriptando colunas desejadas[\u002Fcaption]\r\n\r\nO próximo passo foi escolher a coluna a ser encriptada, tipo de encriptação e qual chave de encriptação de coluna deveria ser usada. E então encerrei o processo com o conhecido NEXT-NEXT-FINISH.\r\n\r\n[caption id=\"attachment_155303\" align=\"alignnone\" width=\"469\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner07.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155303 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner07.jpg.jpg\" alt=\"\" width=\"469\" height=\"421\" \u002F\u003E\u003C\u002Fa\u003E Figura 7: Especificando a chave e tipo de encriptação da coluna[\u002Fcaption]\r\n\r\nA coluna DOCUMENTO está finalmente encriptada. Mas a tabela continua vazia e são necessários cuidados especiais para inserir dados nesta nova coluna encriptada.\r\n\r\nA primeira ação necessária é alterar os parâmetros de conexão da sua aplicação e ou IDE para trabalhar com ALWAYS ENCRYPTED. Como comentei anteriormente, é necessário usar driver de conexão que suporte este tipo de criptografia.\r\n\r\nPara mostrar como isso funciona, preparei uma simulação diretamente no SSMS. Abri uma nova janela configurando uma nossa sessão: ali mantive o login e senha queestava usando, mas especifiquei o nome do meu banco de dados na aba CONNECTION PROPERTIES e habilitei a opção ENABLE ALWAYS ENCRYPTED na aba ALWAYS ENCRYPTED, como mostra a imagem a seguir.\r\n\r\n[caption id=\"attachment_155304\" align=\"alignnone\" width=\"300\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner8.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155304 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner8.jpg.jpg\" alt=\"\" width=\"300\" height=\"313\" \u002F\u003E\u003C\u002Fa\u003E Figura 8: Configurando a conexão para suporte ao ALWAYS ENCRYPTED[\u002Fcaption]\r\n\r\nPor que especifiquei o banco de dados na conexão? Simples. O driver de conexão necessita acesso à chave criptográfica da coluna e, evidentemente, esta chave está configurada apenas nesta base de dados.\r\n\r\nResolvido o primeiro ponto, vamos ao segundo. É necessário criar uma consulta parametrizada para que a variável usada seja devidamente encriptada antes da inserção do registro. Com estes cuidados, eu consigo executar comandos DML usando texto plano (encriptação\u002Fdecriptação são providenciadas pela própria conexão).\r\n\r\n[caption id=\"attachment_155305\" align=\"alignnone\" width=\"405\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner9.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155305 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner9.jpg.jpg\" alt=\"\" width=\"405\" height=\"272\" \u002F\u003E\u003C\u002Fa\u003E Figura 9: Inserindo dados em tabela com coluna ALWAYS ENCRYPTED[\u002Fcaption]\r\n\r\nObserve que escrita e leitura funcionaram normalmente, como se vê na figura acima. Só por conferência, abro agora uma conexão normal para ler os dados... e então apenas dados encriptados são apresentados.\r\n\r\n[caption id=\"attachment_155306\" align=\"alignnone\" width=\"404\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner10.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155306 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner10.jpg.jpg\" alt=\"\" width=\"404\" height=\"270\" \u002F\u003E\u003C\u002Fa\u003E Figura 10: Visualização da coluna encriptada quando se usa conexão normal[\u002Fcaption]\r\n\r\nCaso deseje dar privilégios para que um usuário ou grupo tenham acesso aos dados encriptados, é preciso especificar estas permissões, como mostra o quadro a seguir.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner11.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-155307\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner11.jpg.jpg\" alt=\"\" width=\"592\" height=\"46\" \u002F\u003E\u003C\u002Fa\u003E\r\n\u003Ch2\u003E\u003Cstrong\u003EMáscara de Dados Dinâmica (DDM)\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nDDM não é propriamente uma encriptação dos dados de uma coluna, mas apenas seu mascaramento enquanto são lidos. Portanto não é um tratamento físico e sim lógico: acrescenta uma determinada máscara aos dados para que eles não sejam inteiramente legíveis.\r\n\r\nA máscara é aplicada para exibição dos dados no momento da consulta. E se aplica a todos usuários, exceto aqueles que tenham privilégio especial sobre a tabela envolvida. Esse acesso é controlado atribuindo ou revogando privilégio de UNMASK. Porém este privilégio é atribuído ao nível de base de dados, isto é, autoriza leitura de TODAS as colunas mascaradas existentes no banco.\r\n\r\nPor ser uma operação lógica, o tipo de máscara usada pode ser alterado a qualquer momento sem nenhum impacto nos dados. Veja a documentação para mais detalhes sobre os tipos de mascaramento disponíveis.\r\n\r\nO código abaixo ilustra a criação de colunas com DDM e atribuição de privilégio de leitura para um usuário comum. IMPORTANTE: como este batch inclui uma inserção de registro com coluna encriptada ALWAYS ON, é necessário estabelecer uma conexão com o SQL Server conforme descrito na seção anterior.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner12.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-155308\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner12.jpg.jpg\" alt=\"\" width=\"591\" height=\"114\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner13.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-155309\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner13.jpg.jpg\" alt=\"\" width=\"589\" height=\"123\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nUsuários com perfil de DBONWER herdam o privilégio de controle sobre a máscara e, portanto, lerão todos os dados. Porém o usuário “PeDeChinelo” vai ler dados mascarados, como mostra a imagem a seguir.\r\n\r\n[caption id=\"attachment_155310\" align=\"alignnone\" width=\"479\"]\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner14.jpg.jpg\"\u003E\u003Cimg class=\"wp-image-155310 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002Fwagner14.jpg.jpg\" alt=\"\" width=\"479\" height=\"325\" \u002F\u003E\u003C\u002Fa\u003E Figura 11: Usuário sem privilégio especial vendo dados mascarados[\u002Fcaption]\r\n\r\nObserve neste exemplo que criei estas colunas com DDM na mesma tabela que já possuía uma coluna com ALWAYS ENCRYPTED e dentro de uma base que trabalha com TDE.\r\n\r\nEm outras palavras, podemos combinar os diferentes tipos de criptografia dentro do AZURE SQL DATABASE. (A menos, é claro, que se tente criar uma coluna ALWAYS ENCRYPTED e adicionar uma máscara DDM, o que não faz nenhum sentido, visto que o dado já está fisicamente encriptado).\r\n\u003Ch2\u003E\u003Cstrong\u003EComentários Finais\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nSegurança de dados é um tópico de grande importância, especialmente em se tratando de bancos de dados na nuvem.\r\n\r\nComo se pode ver nos exemplos apresentados aqui, a implementação dos vários tipos de proteção de dados no AZURE SQL DATABASE é bastante simples e praticamente idêntica ao que se faz em servidores on-premises.\r\n\r\nJá a integração com AZURE KEY VAULT apresenta um custo insignificante se comparado ao nível de proteção que oferece, seja para serviços da nuvem e\u002Fou on-premises.\r\n\u003Ch2\u003E\u003Cstrong\u003ELeituras Sugeridas\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\n1. \u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Fazure-sql\u002Fdatabase\u002Fsecurity-overview\"\u003EAn overview of Azure SQL Database &amp; SQL Managed Instance security capabilities\u003C\u002Fa\u003E por MICROSOFT.\r\n\r\n2. \u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Fazure-sql\u002Fdatabase\u002Ftransparent-data-encryption-tde-overview?tabs=azure-portal\"\u003ETransparent data encryption for SQL Database, SQL Managed Instance &amp; Azure Synapse\u003C\u002Fa\u003E por MICROSOFT\r\n\r\n3. \u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fsql\u002Frelational-databases\u002Fsecurity\u002Fencryption\u002Falways-encrypted-database-engine?view=sql-server-ver15\"\u003EAlways Encrypted\u003C\u002Fa\u003E por MICROSOFT.\r\n\r\n4. \u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fsql\u002Frelational-databases\u002Fsecurity\u002Fencryption\u002Falways-encrypted-query-columns-ssms?view=sql-server-ver15\"\u003EQuery columns using Always Encrypted with SQL Server Management Studio\u003C\u002Fa\u003E por MICROSOFT\r\n\r\n5. \u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fsql\u002Frelational-databases\u002Fsecurity\u002Fdynamic-data-masking?view=sql-server-ver15\"\u003EDynamic Data Masking\u003C\u002Fa\u003E por MICROSOFT.","excerpt":"\u003Cp\u003ERecentemente precisei apresentar para um cliente um material com noções básicas dos recursos de criptografia disponíveis no AZURE SQL Database.\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fdata\u002Fentendendo-os-recursos-de-criptografia-do-azure-sql-database","date":"1 jul, 2020","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002F17104843\u002FAZURE.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":83,"views_count":688900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"Data","slug":"data","id":16,"link":"https:\u002F\u002Fimasters.com.br\u002Fdata"},{"title":"SQL Server","slug":"sql-server","id":7212,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server"}],"tags":[{"title":"azure","slug":"azure","id":2238,"link":"https:\u002F\u002Fimasters.com.br\u002Fazure"},{"title":"Azure SQL Database","slug":"azure-sql-database","id":8420,"link":"https:\u002F\u002Fimasters.com.br\u002Fazure-sql-database"},{"title":"criptografia","slug":"criptografia","id":318,"link":"https:\u002F\u002Fimasters.com.br\u002Fcriptografia"},{"title":"dados","slug":"dados","id":374,"link":"https:\u002F\u002Fimasters.com.br\u002Fdados"},{"title":"database","slug":"database","id":348,"link":"https:\u002F\u002Fimasters.com.br\u002Fdatabase"}],"relateds":[],"seo":[],"type":"post"},{"id":154949,"title":"Bate-bola com Grafos e SQL Server Parte 3 – Visualizando Dados","content":"Desta vez o enfoque é na análise de dados, mais especificamente a visualização dos grafos que foram criados. Eu prefiro começar a conversa com o porquê e depois falo do como. Ou seja, começo mostrando para que serve a visualização dos grafos e, na sequência, apresento como construir um dashboard simples destes grafos.\r\n\u003Ch2\u003E\u003Cstrong\u003EAnalisando Dados em um Dashboard\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nÉ natural que a imagem de milhares de grafos sobrepostos seja muita parecida com uma nuvem. Os poucos “raios” que possam despontar dessa nuvem representam os nós que possuem poucas conexões, geralmente um númeor muito menor que a média dos demais.\r\n\r\nA imagem a seguir apresenta os grafos de cerca de 11 mil jogadores que disputaram partidas de campeonatos europeus entre 2008 e 2015. Considerando este universo (11 mil grafos), fica claro que a quantidade de “raios” que desgarram da nuvem representa um número muito pequeno de nós. E, de fato, fica evidente que são nós que apresentam poucas conexões.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri1.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154950\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri1.jpg.jpg\" alt=\"\" width=\"593\" height=\"325\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nDependendo do que se espera analisar, pode ser vantajoso analisar os grafos fazendo um “zoom” na imagem. Por exemplo, no estudo a seguir, estou observando o universo de jogadores que fizeram parte do elenco do time escocês ABERDEEN durante os 7 anos de histórico. Observo que 93 atletas jogaram pelo time durante este período,\r\nsendo que 01 deles, Andrew Considine, foi o recordista de conexões: 44 no total.\r\n\r\nEm outras palavras, este atleta teve oportunidade de jogar com quase metade dos jogadores que fizeram parte do elenco do time durante estas 07 temporadas. Para destacar este atleta em especial, eu movi este nó para lhe dar maior destaque. Veja o resultado na imagem a seguir.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri2.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154951\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri2.jpg.jpg\" alt=\"\" width=\"598\" height=\"328\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nEm seguida, faço um zoom ainda mais detalhado e avalio os jogadores que estavam no elenco nas temporadas de 2008 e 2015 (primeira e última temporadas do histórico em estudo). Nestes grafos fica óbvio que apenas dois jogadores, Peter Powlet e o próprio Considine fizeram parte do elenco tanto na temporada de 2008 como na de\r\n2015.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri3.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154952\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri3.jpg.jpg\" alt=\"\" width=\"590\" height=\"324\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nVamos agora a outro exemplo: o estudo dos caminhos que conectam dois jogadores. No artigo anterior mostrei uma consulta que identificava o caminho mais curto entre Cristiano Ronaldo e Lionel Messi.\r\n\r\nAqui eu apresento os grafos de um desses caminhos (incluindo Albiol e Villa). Fica claro que existem inúmeros caminhos mais longos que ligam estes quatro atletas, isto é, existem dezenas de jogadores que atuaram com Ronaldo e Albiol, outros tantos que jogaram com Albiol e Villa, e mais outros tantos com Villa e Messi.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri4.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154953\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri4.jpg.jpg\" alt=\"\" width=\"596\" height=\"317\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nObservando mais detalhadamente os grafos, se vê que não houve nenhum jogador além de Albiol que tenha jogado com Ronaldo e Vila, pelo simples fato de que não existem conexões entre Ronaldo e Vila que não passem por Albiol. Pelo mesmo princípio, fica claro que Vila foi o único atleta neste período que jogou com Albiol e Messi.\r\n\r\nCom estes exemplos, espero ter demonstrado a utilidade de se visualizar os grafos. Talvez seja por falta de experiência, mas eu ainda não me sinto confortável fazendo uma análise exploratória dos dados diretamente sobre os grafos. Em geral, testo minhas hipóteses fazendo consultas SQL e uso os grafos para evidenciar o que descobri.\r\n\r\nObviamente os grafos ajudam a entender outras características implícitas nos relacionamentos, mas me parece difícil analisar milhares de grafos em busca de um cenário desejado.\r\n\r\nQuem sabe futuramente, usando ferramentas mais versáteis e rápidas, eu venha a mudar minha opinião. Mas hoje eu uso dashboards de grafos principalmente para demonstrar visualmente descobertas que fiz usando outros recursos.\r\n\u003Ch2\u003E\u003Cstrong\u003EConstruindo um Dashboard\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nAgora apresento em linhas gerais como criar um dashboard de grafos no POWER BI. Primeiramente, é recomendável atualizar a versão do POWER BI DESKTOP instalada na sua máquina. Ao abri-lo, escolho a opção GET DATA na tela de início.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri5.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154954\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri5.jpg.jpg\" alt=\"\" width=\"287\" height=\"170\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nAgora informo qual será a fonte de dados que usarei nestes dashboards. Neste caso, escolho “SQL Server” e clico em CONNECT.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri6.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154955\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri6.jpg.jpg\" alt=\"\" width=\"317\" height=\"358\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nEm seguida, informo o nome da instância SQL e base de dados, marco a opção IMPORT e clico na guia ADVANCED. Minha intenção é definir uma consulta SQL cujos dados serão importados para o dashboard.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri7.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154956\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri7.jpg.jpg\" alt=\"\" width=\"587\" height=\"293\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nA consulta que considerei é apresentada a seguir.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri8.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154957\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri8.jpg.jpg\" alt=\"\" width=\"598\" height=\"142\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nUma vez carregados os dados, começo a tratar da sua visualização. Não existe nenhum objeto nativo no POWER BI que permita uma boa análise de grafos. Sendo assim, decido importar um objeto externo especializado em grafos. Para isso, vou na guia VISUALIZATIONS, clico sobre as reticências e depois em IMPORT FROM APPSOURCE.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri9.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154958\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri9.jpg.jpg\" alt=\"\" width=\"289\" height=\"219\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nNa guia MARKETPLACE, faço uma busca pela palavra-chave “graph”. Existem algumas opções, mas os exemplos que apresento neste artigo foram criados usando o objeto ADVANCED GRAPH VISUAL. Basta escolher o objeto e adicioná-lo no seu dashboard. (Recomendo ao leitor avaliar a licença de cada um dos produtos para entender suas condições de uso).\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri10.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154959\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri10.jpg.jpg\" alt=\"\" width=\"269\" height=\"226\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nFinalmente estou pronto para iniciar a construção do dashboard. Minha intenção é construir um grafo que compare os atletas de N clubes em busca de jogadores que fizeram parte demais de uma equipe. (O POWER BI me permite filtrar centenas deles). Clico no objeto que acabo de instalar e início a etapa de configuração. Veja que abaixo da guia VISUALIZATIONS surge uma série opções de configuração.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri11.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154960\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri11.jpg.jpg\" alt=\"\" width=\"401\" height=\"223\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nPara gerar os grafos desejados, preciso lembrar que pretendo ver TIMES (que aqui será o SOURCE NODES=’TEAM’) e os JOGADORES que fizeram parte do elenco (TARGET NODES=’PLAYER2’). A métrica que desejo visualizar é uma contagem de valores distintos de jogadores, isto é, o número de jogadores que fizeram parte do elenco (VALUE=’COUNT(DISTINCT PLAYER2)’).\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri12.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154961\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri12.jpg.jpg\" alt=\"\" width=\"237\" height=\"291\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nUma questão interessante é que meu modelo de grafos não considera um nó ‘Time’, mas este dado aparece no modelo como um atributo da borda edges.PlayingTogether. Ainda assim, consigo criar uma agregação usando este campo como nó de um grafo.\r\n\r\nÉ comum que os usuários recentes tenham alguma dificuldade de identificar os componentes SOURCE e TARGET NODE na construção dos grafos. Porém, basta lembrar o conceito fundamental dos grafos: dois nós associados através de uma borda.\r\n\r\nNeste caso, o usuário precisa apenas identificar quem é o nó principal da sua análise. Se eu montar grafos com a definição invertida, o perfil da “nuvem” de grafos não mudará muito. Mas ao dar um zoom para visualização de detalhes, eu veria que os destaques, inclusive as métricas, não mostrariam o que eu esperava encontrar.\r\n\r\nAo contrário dos outros objetos de visualização do POWER BI, o ADVANCED GRAPH VISUAL não apresenta tantos recursos de formatação quanto se poderia esperar. Porém ele oferece uma experiência adequada em termos de análise, permitindo inclusive rearranjar os nós na tela.\r\n\r\nSeu ponto fraco, porém, é a performance. A velocidade de atualização dos grafos para uma massa com centenas de milhares de nós pode tornar sua exibição inviável.\r\n\u003Ch2\u003E\u003Cstrong\u003EAnalisando Dados no Novo Dashboard \u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nUma vez concluído meu dashboard, começo as análises escolhendo N times do meu interesse. Neste estudo, selecionei quatro times como filtros:\r\n Real Madrid\r\n Barcelona\r\n Bayern\r\n Paris Saint-Germain\r\n\u003Ch2\u003E\u003Cstrong\u003EAnálise 1\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri13.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154962\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri13.jpg.jpg\" alt=\"\" width=\"587\" height=\"326\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nAs primeiras informações que me saltam aos olhos são as seguintes:\r\n1. Apesar de muitos jogadores terem passado pelos quatro times durante as temporadas de 2008 a 2015 (variando entre 57 e 67 jogadores diferentes), existem muito poucas conexões entre os grafos. Em outras palavras, poucos\r\njogadores atuaram por mais que um destes times durante este período.\r\n\r\n2. Nenhum jogador atuou por mais que 2 dos times, visto que não se vê nenhuma conexão entre 3 ou mais grafos.\r\n\r\n3. Nenhum jogador teve oportunidade durante sua carreira de atuar por Real Madrid e Barcelona, nem por Bayern e PSG. (Pelo menos não entre as temporadas de 2008 a 2015).\r\n\r\n4. Houve 04 atletas que jogaram por Bayern e Real neste período\r\n\r\n5. Houve 02 atletas que jogaram por Bayern e Barcelona e outros 02 que jogaram por PSG e Barcelona.\r\n\r\n6. Houve apenas 01 atleta que jogou pelo Real e PSG. Dando um zoom na imagem, identifico que este atleta foi Angel Di Maria, o argentino.\r\n\u003Ch2\u003E\u003Cstrong\u003EAnálise 2\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nFazendo um novo filtro por temporada (SEASON), observo que houve um único caso de jogador que atuaou por 2 times diferentes na temporada de 2011. Foi Maxwell (brasileiro), que atuou pelo PSG e pelo Barcelona.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri14.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154963\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Facri14.jpg.jpg\" alt=\"\" width=\"584\" height=\"323\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nO leitor mais atento perceberá que o número de jogadores de cada time mudou nesta nova análise. Isso ocorre simplesmente porque agora vemos o número de jogadores atuantes na temporada 2011\u002F2012, acompanhando o filtro que foi aplicado.\r\n\u003Ch2\u003E\u003Cstrong\u003EComentários Finais\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nComo se pode ver, uma simples imagem pode oferecer um sem-número de informações. Na minha opinião, este é o ponto alto dos Grafos.\r\n\r\nÉ evidente que um dashboard precisa de um tratamento estético mais elaborado, porém minha intenção neste artigo era apenas mostrar como evidenciar características importantes dos relacionamentos de dados usando grafos.\r\n\r\nMesmo considerando a limitação da velocidade de atualização dos dados, este tipo de dashboard pode ser muito útil para pequenas massas de dados (na ordem de milhares de grafos).\r\n\u003Ch2\u003E\u003Cstrong\u003ELeituras Sugeridas\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\n1. SQL Graph Architecture por MICROSOFT.\r\n2. Graph processing with SQL Server and Azure SQL Database por\r\nMICROSOFT.\r\n3. European Soccer Database por Hugo Mathien @KAGGLE\r\n4. Graph Databases for Beginners por Roberto Zicari (série de 5 artigos).","excerpt":"\u003Cp\u003EDesta vez o enfoque é na análise de dados, mais especificamente a visualização dos grafos que foram criados. Eu prefiro começar a conversa com o porquê e depois falo do como. Ou seja, começo mostrando para que serve a visualização dos grafos e, na sequência, apresento como construir um dashboard simples destes grafos. Analisando Dados…\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server\u002Fbate-bola-com-grafos-e-sql-server-parte-3-visualizando-dados","date":"13 abr, 2020","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F08\u002F24172315\u002F1768.sql_logob.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":83,"views_count":688900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"SQL Server","slug":"sql-server","id":7212,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server"}],"tags":[],"relateds":[],"seo":[],"type":"post"},{"id":154930,"title":"Bate-bola com Grafos e SQL Server Parte 2 – Implementando o Modelo","content":"Neste artigo dou sequência no estudo de grafos usando a base de dados European Soccer Database, publicada por Hugo Mathien no KAGGLE.\r\n\r\nDesta vez vou tratar da implementação do modelo de grafos definido no artigo anterior usando o SQL Server 2019.\r\nApresento também algumas consultas e análises sobre estes grafos.\r\n\u003Ch2\u003E\u003Cstrong\u003ECriando as Tabelas\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nDefinido o modelo de grafos, é preciso criar as tabelas e carregar os dados. Para facilitar, apresento abaixo o diagrama do modelo.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini1.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154931\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini1.jpg.jpg\" alt=\"\" width=\"536\" height=\"323\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nA criação das tabelas usando T-SQL não tem segredo: é preciso apenas informar que tipo de tabela está sendo criada, se é nó (“as node”) ou borda (“as edge”). No diagrama acima, os campos que são exibidos com um cifrão (“$”) na frente do nome são criados automaticamente pelo SQL Server. É necessário apenas definir os demais\r\ncampos.\r\n\r\nPara facilitar a identificação das tabelas, criei os esquemas “nodes” e “edges”. O quadro a seguir mostra a sintaxe destas instruções.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini2.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154932\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini2.jpg.jpg\" alt=\"\" width=\"596\" height=\"256\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nApesar da criação de tabelas ser bastante simples, a carga de dados requer mais cuidado, como descrevo a seguir.\r\n\u003Ch2\u003E\u003Cstrong\u003EConsiderações sobre a Carga de Dados\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nEm primeiro lugar, é preciso respeitar a sequência: tabelas de nós são carregadas primeiro. Além dos campos que são definidos explicitamente, as tabelas de nós têm um campo que é criado e gerenciado automaticamente, cujo nome é “$node_id” (seguido de uma sequência de caracteres alfanuméricos que tornam este nome único). Estes campos contém um JSON que identifica o registro, como se vê a seguir.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini3.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154933\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini3.jpg.jpg\" alt=\"\" width=\"386\" height=\"49\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nO passo seguinte é a carga dos dados para tabelas de borda. Na prática, estas tabelas sempre vinculam dois nós, sejam eles quais forem. Do mesmo modo que as tabelas de nós, elas também têm campos que são criados e gerenciados automaticamente.\r\n\r\nOs principais deles são os campos “$from_id” e “$to_id”. Neles são carregados os JSONs que se tem no campo “$node_id” das tabelas de nós vinculadas a esta borda. Perceba que, se a definição da borda tem um “DEPARA”,\r\nsignifica que o relacionamento tem uma direção que é definida na carga dos dados! O quadro a seguir mostra um registro da tabela de borda “edges.PlayersInvolved”.\r\n\r\nEscolhi que a coluna “$from_id” traria informação sobre a partida (match) e a coluna “$to_id” informaria o jogador (player) que participou dela.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini4.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154934\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini4.jpg.jpg\" alt=\"\" width=\"600\" height=\"59\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nEsta escolha precisa ser considerada em todas as consultas que forem feitas sobre estes dados. Se acidentalmente eu inverter a relação, buscando dados com base numa relação jogador\u002Fpartida (ao invés de partida\u002Fjogador), nenhum registro será retornado.\r\n\u003Ch2\u003E\u003Cstrong\u003ECarregando Dados\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nPara que fique mais claro, apresento a seguir o modelo relacional dos dados, com as tabelas e campos que vamos carregar.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini5.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154935\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini5.jpg.jpg\" alt=\"\" width=\"599\" height=\"242\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nA carga de dados para tabelas de nós é elementar, porque geralmente temos uma tabela relacional para a mesma entidade que será representada como nó (neste caso, temos MATCH, TEAM e PLAYER).\r\n\r\nNo caso das bordas, vão existir necessariamente uma ou mais junções de tabelas. Isso porque será preciso trazer dados das tabelas relacionais (os atributos da borda) e dados de grafos, visto que os arquivos JSON das duas tabelas de nós envolvidas na relação serão carregados para as colunas “$from_id” e “$to_id” da tabela de borda.\r\n\r\nPara carga dos dados da borda “edges.TeamsInvolved”, por exemplo, foi necessário criar duas declarações separadas em virtude da modelagem da tabela relacional “dbo.Match”. A primeira declaração busca dados do time local (“home”) e a segunda do time visitante (“away”).\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini6.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154936\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini6.jpg.jpg\" alt=\"\" width=\"598\" height=\"196\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nA carga da tabela de borda “edges.PlayersInvolved” é mais elaborada, já que a tabela relacional “dbo.Match” usa 22 colunas para identificar os jogadores que iniciaram a partida. Deste modo, foram criadas 22 declarações SQL para carregar estes dados.\r\n\r\nNo caso da terceira borda, “edges.PlayingTogether”, a situação é ainda mais complexa. Basicamente, preciso criar para cada jogador uma lista com o nome de todos os jogadores que jogaram no mesmo time que ele. Esta lista não pode ter repetições e não pode associar um jogador a ele mesmo. Existem diversas maneiras de se escrever estas declarações. Eu preferi criar um SQL dinâmico para simplificar a tarefa.\r\n\u003Ch2\u003E\u003Cstrong\u003EAnalisando Dados com T-SQL\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nA principal diferença das declarações SQL que usam grafos é que elas não utilizam o operador JOIN entre as tabelas de nós e bordas. Na verdade, a conexão entre tabelas é feita através do operador MATCH.\r\n\r\nO MATCH é incluído na cláusula WHERE junto com os demais predicados que sejam necessários. Ele define o relacionamento entre nós e bordas, sejam eles quantos forem necessários. A sequência dos nós pode ser colocada da maneira que preferir, desde que mude também os marcadores. Por exemplo (os parênteses, traços e símbolos fazem para da sintaxe):\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini7.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154937\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini7.jpg.jpg\" alt=\"\" width=\"598\" height=\"40\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nComeço apresentando um exemplo simples, que por sinal seria resolvido com igual facilidade no modelo relacional. Desejo saber quantas partidas o Cristiano Ronaldo jogou pela liga espanhola na temporada “2009\u002F2010”.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini8.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154938\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini8.jpg.jpg\" alt=\"\" width=\"596\" height=\"142\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nAgora quero saber quantos jogos Cristiano Ronaldo e Lionel Messi fizeram um contra o outro na Liga Espanhola durante todas as temporadas disponíveis na base (2008 a 2015). Esta é uma informação mais complicada de se extrair no modelo relacional.\r\n\r\nCom grafos, basta especificar uma relação entre o jogador1 e uma partida e verificar se o jogador2 participou da mesma partida. Como sei que Messi e Cristiano nunca jogaram no mesmo time, não me preocupei em identificar os times deles como local ou visitante.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini9.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154939\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini9.jpg.jpg\" alt=\"\" width=\"596\" height=\"161\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nA próxima consulta é bastante difícil de se escrever num modelo relacional. Quero saber com quantos jogadores diferentes Cristiano e Messi jogaram durante este período de 2008 a 2015, não importa se jogaram juntos ou contra eles. No modelo de grafos, a complexidade é a mesma da consulta anterior.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini10.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154940\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini10.jpg.jpg\" alt=\"\" width=\"599\" height=\"168\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nAgora quero identificar quem foi o jogador que mais ganhou jogos em campeonatos nacionais no período estudado e por quantos times diferentes. Este tipo de consulta poderia envolver 03 nós e 02 bordas caso meu modelo não incluísse dois atributos na borda que identifica os jogadores que participaram de uma partida: um informando o\r\nnome do time em que o jogador estava e outro informando se este time era local ou visitante. Deste modo temos uma consulta mais simples e com performance melhor, graças ao alinhamento entre a modelagem da base e as expectativas de uso.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini11.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154941\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini11.jpg.jpg\" alt=\"\" width=\"603\" height=\"175\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nMais um exemplo: quero saber se algum jogador já jogou junto com os goleiros Gianluigi Buffon (ex-seleção italiana) e Julio Cesar (ex-seleção brasileira) em ligas nacionais durante o período em estudo, quais foram os times, ligas e temporadas.\r\n\r\nNeste caso, preciso identificar que esse(s) jogador(es) estavam naquelas partidas no mesmo time que um dos dois goleiros. Aqui é preciso distinguir 3 nós, P1 (Buffon), P2 (o jogador que estou procurando) e P3 (Julio). O time em que P2 jogou a partida precisa ser necessariamente igual ao time onde jogaram Buffon ou ao time do Julio\r\nCesar. A lógica aqui é um pouco mais complexa, pois preciso relacionar P1 e P2 a uma partida M1 e P3 e P2 a outra partida M2. Ainda assim, esta declaração é muito mais simples e rápida do que seria num modelo relacional (mesmo considerando que não criei índices customizados para estas tabelas).\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini12a.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154942\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini12a.jpg.jpg\" alt=\"\" width=\"598\" height=\"86\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini12b.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154943\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini12b.jpg.jpg\" alt=\"\" width=\"595\" height=\"298\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nEste caso era razoavelmente simples, porque de fato existiam 02 jogadores que jogaram diretamente com Buffon e também com Julio Cesar. Dizemos que estes grafos têm 02 graus de separação: Buffon  “Jogador P2” Julio Cesar. Mas o que faríamos se não soubéssemos a “distância” entre estes dois jogadores?\r\n\r\nAqui entra um novo operador de grafos, implementado no SQL Server 2019 (ou superior): SHORTEST_PATH. Este operador informa o menor grau de separação existente entre 02 nós quaisquer. A sintaxe usada define uma chamada recursiva sobre os nós e a borda envolvidos, por essa razão que se usa a cláusula FOR PATH para identificar as tabelas recursivas.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini13.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154944\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini13.jpg.jpg\" alt=\"\" width=\"595\" height=\"90\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nTenha em mente que o objetivo do operador SHORTEST_PATH é encontrar apenas um exemplo de caminho mais curto entre os nós “nó1” e “nó2”. Caso eu queira identificar todos os registros (ou “triplas”) que tenham este mesmo grau de separação, vou precisar escrever outra consulta diferente.\r\n\r\nMeu objetivo no próximo exemplo é descobrir qual o caminho mais curto de jogadores que jogaram com Cristiano Ronaldo e Leonel Messi. O fato de ambos terem jogad o por poucos clubes (2 para Ronaldo e apenas para Messi), aliado à conhecida rixa existente entre Real Madrid e Barcelona, tornam muita baixa probabilidade de encontrar jogadores diretamente ligados a eles dois. Neste exemplo eu uso a borda JOGANDO JUNTOS (“edges.PlayingTogether”), que foi criada exatamente com a finalidade de avaliar as relações entre jogadores que jogaram juntos (pelo mesmo time). Com ela, a sintaxe da consulta será ainda mais simples. O fator principal a se considerar nesta consulta é que não se sabe quantos graus de separação existem entre Messi e Ronaldo, considerando apenas campeonatos nacionais europeus. Por esta razão, tenho que utilizar o operador SHORTEST_PATH.\r\n\r\nMuitas vezes se usa as funções STRING_AGG, LAST_VALUE e\u002Fou COUNT juntamente com o operador SHORT_PATH, visto que elas trazem informações relevantes sobre o caminho e os graus de separação dos grafos. É o que faço na consulta a seguir.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini14.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154945\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini14.jpg.jpg\" alt=\"\" width=\"595\" height=\"278\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nNote que esta consulta retorna um único exemplo de tripla que tenha o mínimo de níveis possíveis para ligar Ronaldo e Messi. Na verdade, a quantidade de triplas que atendem a este quesito é maior. Sabendo que preciso fazer a consulta com 03 graus de separação, fica fácil escrevê-la.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini15.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154946\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F03\u002Fcrivelini15.jpg.jpg\" alt=\"\" width=\"597\" height=\"327\" \u002F\u003E\u003C\u002Fa\u003E\r\n\u003Ch2\u003E\u003Cstrong\u003EComentários Finais\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nComo se vê, a implementação de tabelas de grafos usando T-SQL é simples e direta. Até mesmo as consultas usando os operadores MATCH e SHORTEST_PATH são relativamente simples de definir e implementar.\r\nDeixo para os leitores mais céticos a tarefa de implementar consultas equivalentes numa base relacional, pois certamente serão consultas muito maiores e mais lentas.\r\n\r\nÉ verdade que o modelo relacional da base original de Hugo Mathien não favorece estas consultas, mas o resultado final, em termos de complexidade e performance, não seria muito diferente mesmo que as tabelas relacionais fossem modeladas com um grau maior de normalização.\r\n\r\nNo terceiro e último artigo desta série, apresentarei a construção de um dashboard para análise dos grafos aqui criados.\r\n\u003Ch2\u003E\u003Cstrong\u003ELeituras Sugeridas\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\n1. SQL Graph Architecture por MICROSOFT.\r\n2. Graph processing with SQL Server and Azure SQL Database por\r\nMICROSOFT.\r\n3. European Soccer Database por Hugo Mathien @KAGGLE\r\n4. Graph Databases for Beginners por Roberto Zicari (série de 5 artigos).\r\n5. SHORTEST_PATH (Transact-SQL) por MICROSOFT.\r\n\r\n \r\n\r\n ","excerpt":"\u003Cp\u003ENeste artigo dou sequência no estudo de grafos usando a base de dados European Soccer Database, publicada por Hugo Mathien no KAGGLE. Desta vez vou tratar da implementação do modelo de grafos definido no artigo anterior usando o SQL Server 2019. Apresento também algumas consultas e análises sobre estes grafos. Criando as Tabelas Definido o…\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server\u002Fbate-bola-com-grafos-e-sql-server-parte-2-implementando-o-modelo","date":"30 mar, 2020","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F08\u002F24172315\u002F1768.sql_logob.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":83,"views_count":688900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"SQL Server","slug":"sql-server","id":7212,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server"}],"tags":[{"title":"Grafos","slug":"grafos","id":3757,"link":"https:\u002F\u002Fimasters.com.br\u002Fgrafos"},{"title":"sql server","slug":"sql-server-2","id":324,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server-2"}],"relateds":[],"seo":[],"type":"post"},{"id":154854,"title":"Bate-bola com Grafos e SQL Server Parte 1 – Definindo o Modelo","content":"É espantosa a popularização que as novas tecnologias de dados alcançaram na última década. Uma das mais bacanas é a utilização de Grafos para análise de dados, apesar de ela não ser propriamente uma tecnologia nova.\r\n\r\nTeoria dos Grafos é um ramo da matemática inventado por Leonhard Euler há quase 300 anos! Seu foco é a análise de relações (complexas) entre entidades.\r\n\r\nVocê pode dizer que um banco relacional também trata de objetos relacionados, mas nele sempre haverá um número pequeno de relações diretas entre um objeto e seus pares.\r\n\r\nNão é comum encontrar um modelo relacional em que uma tabela se relacione diretamente com mais que 10 outras tabelas. Mas quando pensamos, por exemplo, nos relacionamentos entre pessoas numa rede social, os números rapidamente passam dos milhares.\r\n\r\nPortanto, mesmo que dados relacionais e grafos trabalhem com os mesmos princípios (entidades e relacionamentos), eles claramente ocupam nichos distintos. O primeiro trata de relações simples, enquanto os grafos são úteis nos casos em que se trabalha com relações complexas entre entidades.\r\n\r\nExiste inclusive um jogo chamado “Seis Graus de Separação” que alega que você pode rastrear uma rede de relacionamentos de você até qualquer pessoa do planeta envolvendo, no máximo, outras seis pessoas.\r\n\r\nEm outras palavras, seis relacionamentos. A primeira vez que ouvi falar disso foi nos anos 90, numa matéria da\r\nrevista \u003Ca href=\"https:\u002F\u002Fwww.discovermagazine.com\u002Fmagazine\"\u003EDISCOVER MAGAZINE\u003C\u002Fa\u003E. É uma pena que não consegui encontrá-lo no site da revista\r\n\r\nNesta série, mostro como implementar Grafos usando T-SQL, ou seja, apresento códigos, conceitos e funcionalidades para criação de grafos nos seguintes SGBDs:\r\n\u003Cul\u003E\r\n \t\u003Cli\u003EMICROSOFT SQL Server 2017 ou superior (on-premises)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EMICROSOFT PARALLEL DATA WAREHOUSE (on-premises)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EAZURE SQL DATABASE (nuvem)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EAZURE SYNAPSE ANALYTICS (nuvem)\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\nPara fins de exemplo, escolhi uma massa de dados disponível no KAGGLE que trata de resultados de jogos de ligas europeias de futebol entre as temporadas de 2008 e 2015, a \u003Ca href=\"https:\u002F\u002Fwww.kaggle.com\u002Fhugomathien\u002Fsoccer\"\u003EEuropean Soccer Database\u003C\u002Fa\u003E, compartilhada por \u003Ca href=\"https:\u002F\u002Fwww.kaggle.com\u002Fhugomathien\"\u003EHugo Mathien\u003C\u002Fa\u003E.\r\n\u003Ch2\u003E\u003Cstrong\u003EEntendendo o Modelo\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nO diagrama a seguir apresenta um grafo, envolvendo 02 tipos de entidade, diferenciadas por cores, com 03 elementos diferentes em cada uma. Apresenta também 06 tipos de relacionamentos, que são identificados por rótulos.\r\n\r\nPerceba que a entidade “PEDRO”, por exemplo, se relaciona com todos os outros nós através de diferentes relações, com exceção da relação “VIZINHA DE”, que se refere exclusivamente a cidades.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F02\u002FJoão.jpg.jpg\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154855\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F02\u002FJoão.jpg.jpg\" alt=\"\" width=\"538\" height=\"411\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nQuando trabalhamos com grafos, o foco passa a ser nos elementos de cada entidade, os chamados nós (do inglês “nodes”). Estes nós podem ou não ter atributos associados a eles, dependendo da sua necessidade.\r\n\r\nOutro elemento essencial são as bordas (do inglês “edge”), que definem os relacionamentos que existem entre estes\r\nnós. Observe ainda que as relações têm direção: uma relação é definida de “A” para “B”. Isso será muito importante na hora de definir o modelo e de executar as consultas.\r\n\r\nPara implementar grafos com T-SQL, são necessárias pequenas adaptações nos modelos físico e lógico da base de dados. Assim criamos N tabelas de entidades, contendo todos os nós e atributos referentes a cada entidade. Em seguida criamos M tabelas de bordas, que definem os tipos de relacionamento analisados, informando\r\nque nós estão envolvidos nesta relação.\r\n\r\nEsta estrutura permite armazenar os dados fisicamente de forma muito parecida com os dados relacionais. Ao mesmo tempo, ela nos dá a flexibilidade de analisá-los da maneira desejada, já que o modelo lógico os representa como verdadeiros grafos.\r\n\r\nDetalhe importante: os especialistas alertam que a definição do modelo do grafo está intimamente ligada ao tipo de consultas que se deseja fazer. Em outras palavras, a escolha das bordas, nós e atributos de um modelo pode ser diferente conforme o tipo de consultas que serão feitas sobre estes grafos.\r\n\u003Ch2\u003E\u003Cstrong\u003EExemplo de Modelagem\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nIsto posto, vamos criar nosso modelo de grafos. Meu objetivo é analisar as interações entre jogadores, times e resultados das partidas disputadas em diversas ligas europeias durante o período estudado. O modelo relacional desta base é apresentado a seguir.\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F02\u002Fdados.png.png\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154856\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F02\u002Fdados.png.png\" alt=\"\" width=\"530\" height=\"225\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nOBSERVAÇÃO: a massa de dados original foi compartilhada no KAGGLE como uma base do SQLITE. No entanto, a movimentação destas tabelas para o SQL Server 2019 é um processo tradicional que pode ser feito de inúmeras formas, inclusive como movimentação de arquivos CSV. Sendo assim, não me importei em detalhar as\r\noperações desta etapa.\r\n\r\nUma vez disponíveis os dados relacionais, é necessário definir como serão os grafos utilizados. Para isso, preciso definir quais tabelas de nós e de bordas serão criadas e quais os atributos de cada uma delas.\r\n\r\nA intenção do meu modelo é analisar as interações entre jogadores, times e partidas ocorridas. Para ser mais explícito: pretendo analisar interações entre jogadores (quem jogou no mesmo time, quem foi adversário), entre jogadores e times, entre jogadores e as partidas ocorridas (se ele jogou ou não), entre os times que jogaram entre si e entre times e as partidas que jogaram.\r\n\r\nÀ primeira vista, é um modelo bem simples. Porém as relações entre estas entidades crescem muito rapidamente e este é o problema que os grafos procuram resolver. Veja só algumas contas: num torneio com 20 equipes que jogam 38 rodadas envolvendo 22 jogadores.\r\n\r\nA base em estudo contém dados de 11 ligas por 8 temporadas. Teoricamente, isso representaria cerca de 1,5 milhão de combinações. Porém os times mudam de escalação de jogo para jogo, cada equipe seleciona seus 11 titulares dentro um grupo que tem em média 35 jogadores, o que torna mais difícil estimar o número real de combinações.\r\n\r\nConsiderando os tipos de análise que quero executar, defini o modelo com 03 nós e 03 bordas, a saber:\r\n\u003Cul\u003E\r\n \t\u003Cli\u003ENó TIME (team): equipe que participa do torneio\u003C\u002Fli\u003E\r\n \t\u003Cli\u003ENó JOGADOR (player): associado ao time\u003C\u002Fli\u003E\r\n \t\u003Cli\u003ENó PARTIDA (match): traz dados dos confrontos dentro do torneio\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EBorda TIMES ENVOLVIDOS (TeamsInvolved): identifica relação entre as partidas e as equipes participantes\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EBorda JOGADORES ENVOLVIDOS (PlayersInvolved): identifica jogadores que participaram de cada partida.\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EBorda JOGANDO JUNTOS (PlayingTogether): identifica diretamente os jogadores que entraram em campo por uma mesma equipe.\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\nInformações relevantes que serão usadas apenas como filtros foram incluídas no modelo como atributos. Por exemplo: dia do aniversário, altura e peso do jogador foram incluídos como atributos no nó JOGADORES (players), porque se espera que eles não mudem de uma partida para outra.\r\n\r\nEm contrapartida, o time pelo qual ele jogou, se era do time local ou visitante e qual o número da camisa do jogador foram incluídos na borda JOGADORES ENVOLVIDOS (PlayersInvolved), porque são atributos do jogador que podem variar de uma partida para a outra. Ao final, cheguei no seguinte modelo:\r\n\r\n\u003Ca href=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F02\u002Fdados2.png.png\"\u003E\u003Cimg class=\"alignnone size-full wp-image-154857\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2020\u002F02\u002Fdados2.png.png\" alt=\"\" width=\"465\" height=\"281\" \u002F\u003E\u003C\u002Fa\u003E\r\n\r\nDevido à natureza das pesquisas que pretendo fazer usando a borda JOGANDO JUNTOS (PlayingTogether), precisei definir o relacionamento como se ele fosse bidirecional. Na prática, não existe este conceito no T-SQL e, portanto, o que pretendo fazer de fato é carregar dados considerando as duas direções (de “A” para “B” e de “B” para “A”). Este é um tópico que tratarei no próximo artigo.\r\n\u003Ch2\u003E\u003Cstrong\u003EComentários Finais\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\nNeste primeiro artigo da série, apresentei a definição de um modelo de grafos para analisar partidas de futebol. No próximo artigo, apresentarei a implementação deste modelo no SQL Server 2019 e como funcionam as consultas sobre estes dados.\r\n\u003Ch2\u003E\u003Cstrong\u003ELeituras Sugeridas\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\n1. \u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fsql\u002Frelational-databases\u002Fgraphs\u002Fsql-graph-architecture?view=sql-server-ver15\"\u003ESQL Graph Architecture\u003C\u002Fa\u003E por MICROSOFT.\r\n2. \u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fsql\u002Frelational-databases\u002Fgraphs\u002Fsql-graph-overview?view=sql-server-2017\"\u003EGraph processing with SQL Server and Azure SQL Database\u003C\u002Fa\u003E por\r\nMICROSOFT.\r\n3.\u003Ca href=\"https:\u002F\u002Fwww.kaggle.com\u002Fhugomathien\u002Fsoccer\"\u003E European Soccer Database\u003C\u002Fa\u003E por Hugo Mathien @KAGGLE\r\n4. \u003Ca href=\"http:\u002F\u002Fwww.odbms.org\u002F2015\u002F08\u002Fgraph-databases-for-beginners-why-a-database-query-language-matters\u002F\"\u003EGraph Databases for Beginners\u003C\u002Fa\u003E por Roberto Zicari (série de 5 artigos).\r\n5. \u003Ca href=\"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=yOYodfN84N4\"\u003EA Skeptics Guide to Graph Databases\u003C\u002Fa\u003E por David Bechberger","excerpt":"\u003Cp\u003EÉ espantosa a popularização que as novas tecnologias de dados alcançaram. A utilização de Grafos para análise de dados e o SQL Server…\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server\u002Fbate-bola-com-grafos-e-sql-server-parte-1-definindo-o-modelo","date":"13 mar, 2020","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F08\u002F24172315\u002F1768.sql_logob.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":83,"views_count":688900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"SQL Server","slug":"sql-server","id":7212,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server"}],"tags":[{"title":"sql server","slug":"sql-server-2","id":324,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server-2"}],"relateds":[],"seo":[],"type":"post"},{"id":154395,"title":"Agrupando Dados com GROUPING SETS","content":"\u003Cdiv id=\"contentsContainer\"\u003E\r\n\u003Cdiv id=\"contents\"\u003E\r\n\u003Cp id=\"E437\"\u003E\u003Cspan id=\"E438\" class=\"qowt-font10-Arial\"\u003EChega ser estranho pensar que trabalhemos com tanta frequência com sumarização de dados e ainda assim a opção GROUPING SETS \u003C\u002Fspan\u003E\u003Cspan id=\"E439\" class=\"qowt-font10-Arial\"\u003Eseja uma ilustre desconhecida para a maioria dos mortais\u003C\u002Fspan\u003E\u003Cspan id=\"E440\" class=\"qowt-font10-Arial\"\u003E.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E441\"\u003E\u003Cspan id=\"E442\" class=\"qowt-font10-Arial\"\u003EUma explicação provável é que pouca gente entende\u003C\u002Fspan\u003E\u003Cspan id=\"E443\" class=\"qowt-font10-Arial\"\u003E de fato\u003C\u002Fspan\u003E\u003Cspan id=\"E444\" class=\"qowt-font10-Arial\"\u003E o seu potencial e, por esta razão, ela seria relegada a\u003C\u002Fspan\u003E\u003Cspan id=\"E445\" class=\"qowt-font10-Arial\"\u003Eo \u003C\u002Fspan\u003E\u003Cspan id=\"E446\" class=\"qowt-font10-Arial\"\u003Esegundo plano no mundo d\u003C\u002Fspan\u003E\u003Cspan id=\"E447\" class=\"qowt-font10-Arial\"\u003Eos desenvolvedores \u003C\u002Fspan\u003E\u003Cspan id=\"E448\" class=\"qowt-font10-Arial\"\u003Ede\u003C\u002Fspan\u003E\u003Cspan id=\"E449\" class=\"qowt-font10-Arial\"\u003E bancos de dados.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E450\"\u003E\u003Cspan id=\"E451\" class=\"qowt-font10-Arial\"\u003EPode até parecer à primeira vista que os GROUPING SETS sejam facilmente substituíveis por operadores mais antigos como os ROLLUP e CUBE\u003C\u002Fspan\u003E\u003Cspan id=\"E452\" class=\"qowt-font10-Arial\"\u003E.\u003C\u002Fspan\u003E\u003Cspan id=\"E453\" class=\"qowt-font10-Arial\"\u003E Mas é exatamente aí que você se engana \u003C\u002Fspan\u003E\u003Cspan id=\"E454\" class=\"qowt-font11-SegoeUIEmoji\"\u003E😊.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\r\n\u003Ch2\u003E\u003Cstrong\u003ESQL Server\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\n\u003Cp id=\"E456\" class=\"qowt-stl-Heading3\"\u003E\u003Cspan id=\"E457\"\u003ERelembrando os Operadores ROLLUP e CUBE\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E458\"\u003E\u003Cspan id=\"E459\" class=\"qowt-font10-Arial\"\u003EOs operadores \u003C\u002Fspan\u003E\u003Cspan id=\"E460\" class=\"qowt-font10-Arial\"\u003EROLLUP e CUBE existem no T-SQL desde \u003C\u002Fspan\u003E\u003Cspan id=\"E461\" class=\"qowt-font10-Arial\"\u003Eas primeiras versões do SQL Server. \u003C\u002Fspan\u003E\u003Cspan id=\"E462\" class=\"qowt-font10-Arial\"\u003EAmbos funcionam em conjunto com a cláusula \u003C\u002Fspan\u003E\u003Cspan id=\"E463\" class=\"qowt-font10-Arial\"\u003EGROUP BY e a funcionalidade dos dois é bem parecida:\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\r\n\u003C\u002Fdiv\u003E\r\n\u003C\u002Fdiv\u003E\r\n\u003Cdiv id=\"pageBorders\"\u003E\u003Cspan id=\"E468\" class=\"qowt-font10-Arial\"\u003EGROUP BY \u003C\u002Fspan\u003E\u003Cspan id=\"E470\" class=\"qowt-font10-Arial\"\u003E[…]\u003C\u002Fspan\u003E\u003Cspan id=\"E471\" class=\"qowt-font10-Arial\"\u003E WITH ROLLUP\u003C\u002Fspan\u003E\u003Cspan id=\"E472\" class=\"qowt-font10-Arial\"\u003E: acrescenta à listagem de sumarização os \u003C\u002Fspan\u003E\u003Cspan id=\"E473\" class=\"qowt-font10-Arial\"\u003Etotais parciais calculados da esquerda para direita. \u003C\u002Fspan\u003E\u003Cspan id=\"E474\" class=\"qowt-font10-Arial\"\u003ESe a consulta fizer um agrupamento sobre uma única coluna, o ROLLUP acrescenta o total geral para esta coluna. \u003C\u002Fspan\u003E\u003Cspan id=\"E475\" class=\"qowt-font10-Arial\"\u003EQuando são\u003C\u002Fspan\u003E\u003Cspan id=\"E476\" class=\"qowt-font10-Arial\"\u003E duas colunas\u003C\u002Fspan\u003E\u003Cspan id=\"E477\" class=\"qowt-font10-Arial\"\u003E, acrescenta o total geral e mais o total\u003C\u002Fspan\u003E\u003Cspan id=\"E478\" class=\"qowt-font10-Arial\"\u003E geral\u003C\u002Fspan\u003E\u003Cspan id=\"E479\" class=\"qowt-font10-Arial\"\u003E para cada valor\u003C\u002Fspan\u003E\u003Cspan id=\"E480\" class=\"qowt-font10-Arial\"\u003E da coluna 1\u003C\u002Fspan\u003E\u003Cspan id=\"E481\" class=\"qowt-font10-Arial\"\u003E, como mostra a imagem a seguir.\u003C\u002Fspan\u003E\u003C\u002Fdiv\u003E\r\n\u003Cdiv id=\"contentsContainer\"\u003E\r\n\u003Cdiv id=\"contents\"\u003E\r\n\u003Cp id=\"E482\"\u003E\u003Cimg class=\"alignnone wp-image-154396 \" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F10\u002Fartigo1.jpg.jpg\" alt=\"\" width=\"731\" height=\"697\" \u002F\u003E     \u003Cspan class=\"qowt-font10-Arial\"\u003E\r\n\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E501\" class=\"qowt-li-1_0 qowt-list\"\u003E\u003Cspan id=\"E502\" class=\"qowt-font10-Arial\"\u003EGROUP BY […] WITH CUBE: \u003C\u002Fspan\u003E\u003Cspan id=\"E503\" class=\"qowt-font10-Arial\"\u003Ea diferença do CUBE é que ele \u003C\u002Fspan\u003E\u003Cspan id=\"E504\" class=\"qowt-font10-Arial\"\u003Eacrescenta à listagem \u003C\u002Fspan\u003E\u003Cspan id=\"E505\" class=\"qowt-font10-Arial\"\u003Etodas as possíveis combinações de\u003C\u002Fspan\u003E\u003Cspan id=\"E506\" class=\"qowt-font10-Arial\"\u003E totais parciais \u003C\u002Fspan\u003E\u003Cspan id=\"E507\" class=\"qowt-font10-Arial\"\u003Erelacionad\u003C\u002Fspan\u003E\u003Cspan id=\"E508\" class=\"qowt-font10-Arial\"\u003Ea\u003C\u002Fspan\u003E\u003Cspan id=\"E509\" class=\"qowt-font10-Arial\"\u003Es aos valores distintos de cada coluna \u003C\u002Fspan\u003E\u003Cspan id=\"E510\" class=\"qowt-font10-Arial\"\u003Ede agrupamento\u003C\u002Fspan\u003E\u003Cspan id=\"E511\" class=\"qowt-font10-Arial\"\u003E. \u003C\u002Fspan\u003E\u003Cspan id=\"E512\" class=\"qowt-font10-Arial\"\u003EA figura mostra esta ideia\u003C\u002Fspan\u003E\u003Cspan id=\"E513\" class=\"qowt-font10-Arial\"\u003E.\u003C\u002Fspan\u003E\u003Cspan id=\"E514\" class=\"qowt-font10-Arial\"\u003E Observe\u003C\u002Fspan\u003E\u003Cspan id=\"E515\" class=\"qowt-font10-Arial\"\u003E que existem mais linhas\u003C\u002Fspan\u003E\u003Cspan id=\"E516\" class=\"qowt-font10-Arial\"\u003E de totais parciais neste relatório\u003C\u002Fspan\u003E\u003Cspan id=\"E517\" class=\"qowt-font10-Arial\"\u003E, que são os totais por Mês\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cimg class=\"alignnone wp-image-154397\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F10\u002Fartigo2.jpg.jpg\" alt=\"\" width=\"731\" height=\"666\" \u002F\u003E\r\n\u003Cp id=\"E537\"\u003E\u003Cspan id=\"E538\" class=\"qowt-font10-Arial\"\u003EEnquanto trabalhamos com 2 colunas, é tudo muito simples. Com 3\u003C\u002Fspan\u003E\u003Cspan id=\"E539\" class=\"qowt-font10-Arial\"\u003E colunas agrupadas, a complexidade é consideravelmente maior\u003C\u002Fspan\u003E\u003Cspan id=\"E540\" class=\"qowt-font10-Arial\"\u003E e \u003C\u002Fspan\u003E\u003Cspan id=\"E541\" class=\"qowt-font10-Arial\"\u003Eela cresce exponencialmente à medida que se acrescentam novas colunas\u003C\u002Fspan\u003E\u003Cspan id=\"E542\" class=\"qowt-font10-Arial\"\u003E. Não é raro\u003C\u002Fspan\u003E\u003Cspan id=\"E543\" class=\"qowt-font10-Arial\"\u003E que\u003C\u002Fspan\u003E\u003Cspan id=\"E544\" class=\"qowt-font10-Arial\"\u003E relatórios co\u003C\u002Fspan\u003E\u003Cspan id=\"E545\" class=\"qowt-font10-Arial\"\u003Em 4 ou mais \u003C\u002Fspan\u003E\u003Cspan id=\"E546\" class=\"qowt-font10-Arial\"\u003Ecolunas\u003C\u002Fspan\u003E\u003Cspan id=\"E548\" class=\"qowt-font10-Arial\"\u003E se tornem tão complexos e lentos que \u003C\u002Fspan\u003E\u003Cspan id=\"E549\" class=\"qowt-font10-Arial\"\u003Esimplesmente \u003C\u002Fspan\u003E\u003Cspan id=\"E550\" class=\"qowt-font10-Arial\"\u003Einviabiliza\u003C\u002Fspan\u003E\u003Cspan id=\"E551\" class=\"qowt-font10-Arial\"\u003E o uso destes operadores.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\r\n\u003Ch3 id=\"E553\" class=\"qowt-stl-Heading3\"\u003E\u003Cstrong\u003E\u003Cspan id=\"E554\"\u003EOs Desconhecidos GROUPING SETS\u003C\u002Fspan\u003E\u003C\u002Fstrong\u003E\u003C\u002Fh3\u003E\r\n\u003Cp id=\"E555\"\u003E\u003Cspan id=\"E556\" class=\"qowt-font10-Arial\"\u003EApesar de pouco conhecid\u003C\u002Fspan\u003E\u003Cspan id=\"E557\" class=\"qowt-font10-Arial\"\u003Ea\u003C\u002Fspan\u003E\u003Cspan id=\"E558\" class=\"qowt-font10-Arial\"\u003E, esta opção da cláusula GROUP BY faz parte do padrão ANSI SQL 2006 e existe no SQL Server desde a versão SQL 2008! E ela é realmente bem fácil de usar.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E559\"\u003E\u003Cspan id=\"E560\" class=\"qowt-font10-Arial\"\u003EA forma mais simples de explicar os GROUPING SETS é comparando-os com os operadores ROLLUP e CUBE. \u003C\u002Fspan\u003E\u003Cspan id=\"E561\" class=\"qowt-font10-Arial\"\u003EE a vantage\u003C\u002Fspan\u003E\u003Cspan id=\"E562\" class=\"qowt-font10-Arial\"\u003Em\u003C\u002Fspan\u003E\u003Cspan id=\"E563\" class=\"qowt-font10-Arial\"\u003E de usá-los \u003C\u002Fspan\u003E\u003Cspan id=\"E564\" class=\"qowt-font10-Arial\"\u003Eestá exatamente no controle que eles nos dão sobre o cálculo \u003C\u002Fspan\u003E\u003Cspan id=\"E565\" class=\"qowt-font10-Arial\"\u003Ede totais parciais\u003C\u002Fspan\u003E\u003Cspan id=\"E566\" class=\"qowt-font10-Arial\"\u003E. Em outras palavras\u003C\u002Fspan\u003E\u003Cspan id=\"E567\" class=\"qowt-font10-Arial\"\u003E, você pode facilmente criar um relatório parecido com o\u003C\u002Fspan\u003E\u003Cspan id=\"E568\" class=\"qowt-font10-Arial\"\u003Es que geramos com operadores ROLLUP e CUBE, mas GROUPING SETS permite que você \u003C\u002Fspan\u003E\u003Cspan id=\"E569\" class=\"qowt-font10-Arial\"\u003Etenha controle sobre\u003C\u002Fspan\u003E\u003Cspan id=\"E571\" class=\"qowt-font10-Arial\"\u003Equais totais parciais\u003C\u002Fspan\u003E\u003Cspan id=\"E573\" class=\"qowt-font10-Arial\"\u003Eserão\u003C\u002Fspan\u003E\u003Cspan id=\"E575\" class=\"qowt-font10-Arial\"\u003Ecalculados\u003C\u002Fspan\u003E\u003Cspan id=\"E576\" class=\"qowt-font10-Arial\"\u003E.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E577\"\u003E\u003Cspan id=\"E578\" class=\"qowt-font10-Arial\"\u003EAssim, a utilidade dos GROUPING SETS costuma aparecer \u003C\u002Fspan\u003E\u003Cspan id=\"E579\" class=\"qowt-font10-Arial\"\u003Eapenas quando se trabalha com \u003C\u002Fspan\u003E\u003Cspan id=\"E580\" class=\"qowt-font10-Arial\"\u003Erelatórios \u003C\u002Fspan\u003E\u003Cspan id=\"E581\" class=\"qowt-font10-Arial\"\u003Emais complexos\u003C\u002Fspan\u003E\u003Cspan id=\"E582\" class=\"qowt-font10-Arial\"\u003E. \u003C\u002Fspan\u003E\u003Cspan id=\"E583\" class=\"qowt-font10-Arial\"\u003EPara começar\u003C\u002Fspan\u003E\u003Cspan id=\"E584\" class=\"qowt-font10-Arial\"\u003E, vamos \u003C\u002Fspan\u003E\u003Cspan id=\"E585\" class=\"qowt-font10-Arial\"\u003Ereescrever as consultas com ROLLUP e com CUBE para \u003C\u002Fspan\u003E\u003Cspan id=\"E586\" class=\"qowt-font10-Arial\"\u003Eusar\u003C\u002Fspan\u003E\u003Cspan id=\"E587\" class=\"qowt-font10-Arial\"\u003E GROUPING SETS \u003C\u002Fspan\u003E\u003Cspan id=\"E588\" class=\"qowt-font10-Arial\"\u003Ena geração de relatórios \u003C\u002Fspan\u003E\u003Cspan id=\"E589\" class=\"qowt-font10-Arial\"\u003Eidênticos\u003C\u002Fspan\u003E\u003Cspan id=\"E591\" class=\"qowt-font10-Arial\"\u003Eaos \u003C\u002Fspan\u003E\u003Cspan id=\"E592\" class=\"qowt-font10-Arial\"\u003Eanterior\u003C\u002Fspan\u003E\u003Cspan id=\"E593\" class=\"qowt-font10-Arial\"\u003Ees\u003C\u002Fspan\u003E\u003Cspan id=\"E594\" class=\"qowt-font10-Arial\"\u003E.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E595\"\u003E\u003Cspan id=\"E596\" class=\"qowt-font10-Arial\"\u003ESua\u003C\u002Fspan\u003E\u003Cspan id=\"E597\" class=\"qowt-font10-Arial\"\u003E sintaxe básica é\u003C\u002Fspan\u003E\u003Cspan id=\"E598\" class=\"qowt-font10-Arial\"\u003E esta:\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\r\n\u003C\u002Fdiv\u003E\r\n\u003Cimg class=\"alignnone wp-image-154398\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F10\u002Fartigo3.jpg.jpg\" alt=\"\" width=\"738\" height=\"130\" \u002F\u003E\r\n\u003Cdiv id=\"contents\"\u003E\r\n\u003Cdiv id=\"contentsContainer\"\u003E\r\n\u003Ch3 id=\"contents\"\u003E \u003Cstrong\u003EExemplo 1: GROUPING SETS substituindo operador ROLLUP\u003C\u002Fstrong\u003E\u003C\u002Fh3\u003E\r\n\u003C\u002Fdiv\u003E\r\n\u003Cdiv id=\"contentsContainer\"\u003E\r\n\u003Cdiv id=\"contents\"\u003E\r\n\u003Cdiv id=\"contentsContainer\"\u003E\r\n\u003Cdiv id=\"contents\"\u003E\r\n\u003Cp id=\"E643\"\u003E\u003Cspan id=\"E644\" class=\"qowt-font10-Arial\"\u003EObserve\u003C\u002Fspan\u003E\u003Cspan id=\"E645\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003Cspan id=\"E646\" class=\"qowt-font10-Arial\"\u003Eque, para simularmos \u003C\u002Fspan\u003E\u003Cspan id=\"E647\" class=\"qowt-font10-Arial\"\u003Eos subtotais exibidos em um ROLLUP, precisamos informar\u003C\u002Fspan\u003E\u003Cspan id=\"E648\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003Cspan id=\"E649\" class=\"qowt-font10-Arial\"\u003Eum set com a combinação das colunas de GROUP BY (\u003C\u002Fspan\u003E\u003Cspan id=\"E650\" class=\"qowt-font10-Arial\"\u003EEstado vs Mês)\u003C\u002Fspan\u003E\u003Cspan id=\"E651\" class=\"qowt-font10-Arial\"\u003E, um set\u003C\u002Fspan\u003E\u003Cspan id=\"E652\" class=\"qowt-font10-Arial\"\u003E com \u003C\u002Fspan\u003E\u003Cspan id=\"E653\" class=\"qowt-font10-Arial\"\u003Eos subtotais para a primeira coluna do GROUP BY (Estado) e um terceiro set com o consolidado geral (que é expresso como um set vazio).\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E654\"\u003E\u003Cspan id=\"E655\" class=\"qowt-font10-Arial\"\u003EA declaração SQL e o relatório gerado são apresentados a seguir.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cimg class=\"alignnone wp-image-154399\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F10\u002Fartigo4.jpg.jpg\" alt=\"\" width=\"731\" height=\"606\" \u002F\u003E\r\n\u003Ch3 id=\"E677\"\u003E\u003Cstrong\u003E\u003Cspan id=\"E678\" class=\"qowt-font10-Arial\"\u003EExemplo 2: GROUPING SETS substituindo operador CUBE\u003C\u002Fspan\u003E\u003C\u002Fstrong\u003E\u003C\u002Fh3\u003E\r\n\u003Cp id=\"E679\"\u003E\u003Cspan id=\"E680\" class=\"qowt-font10-Arial\"\u003EPara simular \u003C\u002Fspan\u003E\u003Cspan id=\"E681\" class=\"qowt-font10-Arial\"\u003Eo resultado de um operador CUBE em um relatório de 2 dimensões, só precisamos acrescentar\u003C\u002Fspan\u003E\u003Cspan id=\"E682\" class=\"qowt-font10-Arial\"\u003E mais um set, com os subtotais da coluna Mês.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E684\"\u003E\u003Cspan id=\"E697\" contenteditable=\"false\"\u003E\u003C\u002Fspan\u003E\u003Cimg class=\"alignnone wp-image-154400\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F10\u002Fartigo5.jpg.jpg\" alt=\"\" width=\"730\" height=\"599\" \u002F\u003E     \u003Cspan class=\"qowt-font10-Arial\"\u003E\r\n\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\r\n\u003C\u002Fdiv\u003E\r\n\u003C\u002Fdiv\u003E\r\n\u003Cdiv id=\"contentsContainer\"\u003E\r\n\u003Cdiv id=\"contents\"\u003E\r\n\u003Cdiv id=\"contentsContainer\"\u003E\r\n\u003Cdiv id=\"contents\"\u003E\r\n\u003Ch3 id=\"E703\"\u003E\u003Cstrong\u003E\u003Cspan id=\"E704\" class=\"qowt-font10-Arial\"\u003EExemplo 3: \u003C\u002Fspan\u003E\u003Cspan id=\"E705\" class=\"qowt-font10-Arial\"\u003EGROUPING SETS exibindo \u003C\u002Fspan\u003E\u003Cspan id=\"E706\" class=\"qowt-font10-Arial\"\u003Etotal geral e os subtotais da coluna 1\u003C\u002Fspan\u003E\u003C\u002Fstrong\u003E\u003Cspan id=\"E707\" class=\"qowt-font10-Arial\"\u003E\u003Cstrong\u003E.\u003C\u002Fstrong\u003E \u003C\u002Fspan\u003E\u003C\u002Fh3\u003E\r\n\u003Cp id=\"E708\"\u003E\u003Cspan id=\"E709\" class=\"qowt-font10-Arial\"\u003EConsidere, neste caso, que temos um relatório com \u003C\u002Fspan\u003E\u003Cspan id=\"E710\" class=\"qowt-font10-Arial\"\u003E03 colunas sumarizadas\u003C\u002Fspan\u003E\u003Cspan id=\"E711\" class=\"qowt-font10-Arial\"\u003E, que são Produto, \u003C\u002Fspan\u003E\u003Cspan id=\"E712\" class=\"qowt-font10-Arial\"\u003EEstado\u003C\u002Fspan\u003E\u003Cspan id=\"E713\" class=\"qowt-font10-Arial\"\u003E e Mês\u003C\u002Fspan\u003E\u003Cspan id=\"E714\" class=\"qowt-font10-Arial\"\u003E. Queremos exibir só os totais parciais por Produto\u003C\u002Fspan\u003E\u003Cspan id=\"E715\" class=\"qowt-font10-Arial\"\u003E, mais o total geral.\u003C\u002Fspan\u003E\u003Cspan id=\"E716\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E717\"\u003E\u003Cspan id=\"E718\" class=\"qowt-font10-Arial\"\u003EAcontece que um \u003C\u002Fspan\u003E\u003Cspan id=\"E720\" class=\"qowt-font10-Arial\"\u003Erelatório de \u003C\u002Fspan\u003E\u003Cspan id=\"E721\" class=\"qowt-font10-Arial\"\u003E03 colunas é muito mais complexo\u003C\u002Fspan\u003E\u003Cspan id=\"E722\" class=\"qowt-font10-Arial\"\u003E do que \u003C\u002Fspan\u003E\u003Cspan id=\"E723\" class=\"qowt-font10-Arial\"\u003Eos que vimos até aqui\u003C\u002Fspan\u003E\u003Cspan id=\"E724\" class=\"qowt-font10-Arial\"\u003E.\u003C\u002Fspan\u003E\u003Cspan id=\"E725\" class=\"qowt-font10-Arial\"\u003E Existe um número muito maior de combinações\u003C\u002Fspan\u003E\u003Cspan id=\"E726\" class=\"qowt-font10-Arial\"\u003E entre as colunas, além d\u003C\u002Fspan\u003E\u003Cspan id=\"E727\" class=\"qowt-font10-Arial\"\u003Ee\u003C\u002Fspan\u003E\u003Cspan id=\"E728\" class=\"qowt-font10-Arial\"\u003E que o tamanho do relatório depende\u003C\u002Fspan\u003E\u003Cspan id=\"E729\" class=\"qowt-font10-Arial\"\u003Erá\u003C\u002Fspan\u003E\u003Cspan id=\"E730\" class=\"qowt-font10-Arial\"\u003E da quantidade de itens distintos\u003C\u002Fspan\u003E\u003Cspan id=\"E731\" class=\"qowt-font10-Arial\"\u003E existem em cada uma das três colunas.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E732\"\u003E\u003Cspan id=\"E733\" class=\"qowt-font10-Arial\"\u003ECon\u003C\u002Fspan\u003E\u003Cspan id=\"E734\" class=\"qowt-font10-Arial\"\u003Esidere\u003C\u002Fspan\u003E\u003Cspan id=\"E735\" class=\"qowt-font10-Arial\"\u003E um relatório com as colunas Produto, Estado e Mês\u003C\u002Fspan\u003E\u003Cspan id=\"E736\" class=\"qowt-font10-Arial\"\u003E. Tecnicamente, teremos \u003C\u002Fspan\u003E\u003Cspan id=\"E737\" class=\"qowt-font10-Arial\"\u003Eos seguintes “sets” possíveis:\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E738\" class=\"qowt-li-4_0 qowt-list\"\u003E\u003Cspan id=\"E739\" class=\"qowt-font10-Arial\"\u003E(Produto, Estado, Mês): nível do GROUP BY\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E740\" class=\"qowt-li-4_0 qowt-list\"\u003E\u003Cspan id=\"E741\" class=\"qowt-font10-Arial\"\u003E(Produto, Estado): subtotais desta combinação de colunas\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E742\" class=\"qowt-li-4_0 qowt-list\"\u003E\u003Cspan id=\"E743\" class=\"qowt-font10-Arial\"\u003E(Produto, Mês): subtotais desta combinação de colunas\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E744\" class=\"qowt-li-4_0 qowt-list\"\u003E\u003Cspan id=\"E745\" class=\"qowt-font10-Arial\"\u003E(Estado, Mês)\u003C\u002Fspan\u003E\u003Cspan id=\"E746\" class=\"qowt-font10-Arial\"\u003E: subtotais desta combinação de colunas\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E747\" class=\"qowt-li-4_0 qowt-list\"\u003E\u003Cspan id=\"E748\" class=\"qowt-font10-Arial\"\u003E(Produto): subtotais desta coluna isolada\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E749\" class=\"qowt-li-4_0 qowt-list\"\u003E\u003Cspan id=\"E750\" class=\"qowt-font10-Arial\"\u003E(Estado): subtotais desta coluna isolada\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E751\" class=\"qowt-li-4_0 qowt-list\"\u003E\u003Cspan id=\"E752\" class=\"qowt-font10-Arial\"\u003E(Mês): subtotais desta coluna isolada\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E753\" class=\"qowt-li-4_0 qowt-list\"\u003E\u003Cspan id=\"E754\" class=\"qowt-font10-Arial\"\u003E(): total geral\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E755\"\u003E\u003Cspan id=\"E756\" class=\"qowt-font10-Arial\"\u003ESe \u003C\u002Fspan\u003E\u003Cspan id=\"E757\" class=\"qowt-font10-Arial\"\u003Ecada uma destas três colunas tivesse só 10 \u003C\u002Fspan\u003E\u003Cspan id=\"E758\" class=\"qowt-font10-Arial\"\u003Eelementos distintos, o relatório todo teria ((10 x 10 x 10) + (10 x 10) + (10 x 10) + (10 x 10) \u003C\u002Fspan\u003E\u003Cspan id=\"E759\" class=\"qowt-font10-Arial\"\u003E+ (10) + (10) + (10) + (1)), ou seja, \u003C\u002Fspan\u003E\u003Cspan id=\"E760\" class=\"qowt-font10-Arial\"\u003E1331 linhas.\u003C\u002Fspan\u003E\u003Cspan id=\"E761\" class=\"qowt-font10-Arial\"\u003E Acontece que\u003C\u002Fspan\u003E\u003Cspan id=\"E762\" class=\"qowt-font10-Arial\"\u003E, no\u003C\u002Fspan\u003E\u003Cspan id=\"E763\" class=\"qowt-font10-Arial\"\u003E mundo\u003C\u002Fspan\u003E\u003Cspan id=\"E764\" class=\"qowt-font10-Arial\"\u003E real, \u003C\u002Fspan\u003E\u003Cspan id=\"E765\" class=\"qowt-font10-Arial\"\u003Egeralmente as colunas tem \u003C\u002Fspan\u003E\u003Cspan id=\"E766\" class=\"qowt-font10-Arial\"\u003Emuito mais do que apenas 10 elementos distintos \u003C\u002Fspan\u003E\u003Cspan id=\"E767\" class=\"qowt-font11-SegoeUIEmoji\"\u003E😊.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E768\"\u003E\u003Cspan id=\"E769\" class=\"qowt-font10-Arial\"\u003ESe \u003C\u002Fspan\u003E\u003Cspan id=\"E770\" class=\"qowt-font10-Arial\"\u003Evocê \u003C\u002Fspan\u003E\u003Cspan id=\"E771\" class=\"qowt-font10-Arial\"\u003Eachou \u003C\u002Fspan\u003E\u003Cspan id=\"E772\" class=\"qowt-font10-Arial\"\u003Eeste relatório complexo, \u003C\u002Fspan\u003E\u003Cspan id=\"E773\" class=\"qowt-font10-Arial\"\u003Efaça as contas para outro relatório com 04 colunas agrupadas\u003C\u002Fspan\u003E\u003Cspan id=\"E774\" class=\"qowt-font10-Arial\"\u003E.\u003C\u002Fspan\u003E\u003Cspan id=\"E775\" class=\"qowt-font10-Arial\"\u003E A\u003C\u002Fspan\u003E\u003Cspan id=\"E776\" class=\"qowt-font10-Arial\"\u003Egora sim você está pronto para\u003C\u002Fspan\u003E\u003Cspan id=\"E777\" class=\"qowt-font10-Arial\"\u003E entender a vantagem de se usar GROUPING SETS\u003C\u002Fspan\u003E\u003Cspan id=\"E778\" class=\"qowt-font10-Arial\"\u003E!\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E779\"\u003E\u003Cspan id=\"E780\" class=\"qowt-font10-Arial\"\u003ERetomando o exemplo, ne\u003C\u002Fspan\u003E\u003Cspan id=\"E781\" class=\"qowt-font10-Arial\"\u003Este relatório\u003C\u002Fspan\u003E\u003Cspan id=\"E782\" class=\"qowt-font10-Arial\"\u003E 03 colunas agrupadas, queremos\u003C\u002Fspan\u003E\u003Cspan id=\"E783\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003Cspan id=\"E784\" class=\"qowt-font10-Arial\"\u003Eapenas \u003C\u002Fspan\u003E\u003Cspan id=\"E787\" class=\"qowt-font10-Arial\"\u003Eos resultados do GROUP BY normal, mais\u003C\u002Fspan\u003E\u003Cspan id=\"E788\" class=\"qowt-font10-Arial\"\u003E os subtotais de produto e total geral. \u003C\u002Fspan\u003E\u003Cspan id=\"E789\" class=\"qowt-font10-Arial\"\u003ECom \u003C\u002Fspan\u003E\u003Cspan class=\"qowt-font10-Arial\"\u003EGROUPING SETS a solução é muito simples.\u003C\u002Fspan\u003E\u003Cspan id=\"E790\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003Cspan id=\"E791\" class=\"qowt-font10-Arial\"\u003EObserve que mesmo mostrando só os subtotais por Produto, este relatório já chega 51.773 linhas\u003C\u002Fspan\u003E\u003Cspan id=\"E792\" class=\"qowt-font10-Arial\"\u003E. (Apenas para comparar, \u003C\u002Fspan\u003E\u003Cspan id=\"E793\" class=\"qowt-font10-Arial\"\u003Eo mesmo relatório com o operador CUBE \u003C\u002Fspan\u003E\u003Cspan id=\"E794\" class=\"qowt-font10-Arial\"\u003Etem 65.462 linhas\u003C\u002Fspan\u003E\u003Cspan id=\"E795\" class=\"qowt-font10-Arial\"\u003E)!\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cimg class=\"alignnone wp-image-154401\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F10\u002Fartigo6.jpg.jpg\" alt=\"\" width=\"794\" height=\"612\" \u002F\u003E\r\n\u003Ch3 id=\"E817\" class=\"qowt-stl-Heading3\"\u003E\u003Cstrong\u003E\u003Cspan id=\"E818\"\u003EGROUPING SETS e Performance\u003C\u002Fspan\u003E\u003C\u002Fstrong\u003E\u003C\u002Fh3\u003E\r\n\u003Cp id=\"E820\"\u003E\u003Cspan id=\"E821\" class=\"qowt-font10-Arial\"\u003EUma característica \u003C\u002Fspan\u003E\u003Cspan id=\"E822\" class=\"qowt-font10-Arial\"\u003Eespecialmente interessante \u003C\u002Fspan\u003E\u003Cspan id=\"E823\" class=\"qowt-font10-Arial\"\u003Edos GROUPING SETS é que \u003C\u002Fspan\u003E\u003Cspan id=\"E824\" class=\"qowt-font10-Arial\"\u003Eo custo de execução da consulta\u003C\u002Fspan\u003E\u003Cspan id=\"E825\" class=\"qowt-font10-Arial\"\u003E é proporcional\u003C\u002Fspan\u003E\u003Cspan id=\"E826\" class=\"qowt-font10-Arial\"\u003E à quantidade de subtotais\u003C\u002Fspan\u003E\u003Cspan id=\"E827\" class=\"qowt-font10-Arial\"\u003E solicitados. Portanto o “engine” do SQL Server é suficientemente esperto para calcular apenas o que é necessário. \u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E828\"\u003E\u003Cspan id=\"E829\" class=\"qowt-font10-Arial\"\u003EVeja estes 03 exemplos:\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E830\"\u003E\u003Cspan id=\"E831\" class=\"qowt-font10-Arial\"\u003ECaso 1: \u003C\u002Fspan\u003E\u003Cspan id=\"E832\" class=\"qowt-font10-Arial\"\u003EPlano de Execução para um \u003C\u002Fspan\u003E\u003Cspan id=\"E833\" class=\"qowt-font10-Arial\"\u003EGROUP BY simples\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E834\"\u003E\u003Cspan id=\"E835\" class=\"qowt-font10-Arial\"\u003ECusto total é de 3,53\u003C\u002Fspan\u003E\u003Cspan id=\"E836\" class=\"qowt-font10-Arial\"\u003E849\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cimg class=\"alignnone wp-image-154403\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F10\u002Fartigo7.jpg.jpg\" alt=\"\" width=\"730\" height=\"515\" \u002F\u003E\r\n\u003Cp id=\"E854\"\u003E\u003Cspan id=\"E855\" class=\"qowt-font10-Arial\"\u003ECaso 2: Plano de Execução usando GROUPING SETS apenas para coluna Produto\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E856\"\u003E\u003Cspan id=\"E857\" class=\"qowt-font10-Arial\"\u003ECusto total é de \u003C\u002Fspan\u003E\u003Cspan id=\"E858\" class=\"qowt-font10-Arial\"\u003E4\u003C\u002Fspan\u003E\u003Cspan id=\"E859\" class=\"qowt-font10-Arial\"\u003E,\u003C\u002Fspan\u003E\u003Cspan id=\"E860\" class=\"qowt-font10-Arial\"\u003E00761, pois foram adicionad\u003C\u002Fspan\u003E\u003Cspan id=\"E861\" class=\"qowt-font10-Arial\"\u003Eos 220 subtotais\u003C\u002Fspan\u003E\u003Cspan id=\"E862\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cimg class=\"alignnone wp-image-154404\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F10\u002Fartigo8.jpg.jpg\" alt=\"\" width=\"743\" height=\"461\" \u002F\u003E\r\n\u003Cp id=\"E881\"\u003E\u003Cspan id=\"E882\" class=\"qowt-font10-Arial\"\u003ECaso \u003C\u002Fspan\u003E\u003Cspan id=\"E883\" class=\"qowt-font10-Arial\"\u003E3\u003C\u002Fspan\u003E\u003Cspan id=\"E884\" class=\"qowt-font10-Arial\"\u003E: Plano de Execução \u003C\u002Fspan\u003E\u003Cspan id=\"E885\" class=\"qowt-font10-Arial\"\u003Eusando GROUPING SETS para colunas Produto e Estado\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E886\"\u003E\u003Cspan id=\"E887\" class=\"qowt-font10-Arial\"\u003ECusto total é de \u003C\u002Fspan\u003E\u003Cspan id=\"E889\" class=\"qowt-font10-Arial\"\u003E4\u003C\u002Fspan\u003E\u003Cspan id=\"E890\" class=\"qowt-font10-Arial\"\u003E,5\u003C\u002Fspan\u003E\u003Cspan id=\"E891\" class=\"qowt-font10-Arial\"\u003E4408\u003C\u002Fspan\u003E\u003Cspan id=\"E892\" class=\"qowt-font10-Arial\"\u003E, pois foram acrescentados mais\u003C\u002Fspan\u003E\u003Cspan id=\"E893\" class=\"qowt-font10-Arial\"\u003E 49 subtotais em relação ao exemplo anterior\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cimg class=\"alignnone wp-image-154405\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F10\u002Fartigo10.jpg.jpg\" alt=\"\" width=\"753\" height=\"498\" \u002F\u003E\r\n\u003Ch2 id=\"E912\" class=\"qowt-stl-Heading3\"\u003E\u003Cstrong\u003E\u003Cspan id=\"E913\"\u003ECo\u003C\u002Fspan\u003E\u003Cspan id=\"E914\"\u003Ementários Finais\u003C\u002Fspan\u003E\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\r\n\u003Cp id=\"E915\"\u003E\u003Cspan id=\"E916\" class=\"qowt-font10-Arial\"\u003EA opção \u003C\u002Fspan\u003E\u003Cspan id=\"E917\" class=\"qowt-font10-Arial\"\u003EGROUPING SETS\u003C\u002Fspan\u003E\u003Cspan id=\"E918\" class=\"qowt-font10-Arial\"\u003E facilita muito \u003C\u002Fspan\u003E\u003Cspan id=\"E919\" class=\"qowt-font10-Arial\"\u003Ea geração de subtotais em relatórios SQL\u003C\u002Fspan\u003E\u003Cspan id=\"E920\" class=\"qowt-font10-Arial\"\u003E, \u003C\u002Fspan\u003E\u003Cspan id=\"E921\" class=\"qowt-font10-Arial\"\u003Epermitindo que o \u003C\u002Fspan\u003E\u003Cspan id=\"E922\" class=\"qowt-font10-Arial\"\u003Edesenvolvedor\u003C\u002Fspan\u003E\u003Cspan id=\"E923\" class=\"qowt-font10-Arial\"\u003E tenha muito mais controle sobre \u003C\u002Fspan\u003E\u003Cspan id=\"E924\" class=\"qowt-font10-Arial\"\u003Eo relatório gerado\u003C\u002Fspan\u003E\u003Cspan id=\"E925\" class=\"qowt-font10-Arial\"\u003E.\u003C\u002Fspan\u003E\u003Cspan id=\"E926\" class=\"qowt-font10-Arial\"\u003E \u003C\u002Fspan\u003E\u003Cspan id=\"E927\" class=\"qowt-font10-Arial\"\u003EA performance \u003C\u002Fspan\u003E\u003Cspan id=\"E928\" class=\"qowt-font10-Arial\"\u003Esegue dentro dos padrões esperados, tendo em vista que só os subtotais desejados são calculados durante a execução da consulta.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\r\n\u003Ch3 id=\"E930\" class=\"qowt-stl-Heading3\"\u003E\u003Cstrong\u003E\u003Cspan id=\"E931\"\u003ELeituras Sugeridas\u003C\u002Fspan\u003E\u003C\u002Fstrong\u003E\u003C\u002Fh3\u003E\r\n\u003Cp id=\"E932\" class=\"qowt-li-3_0 qowt-list\"\u003E\u003Ca id=\"E933\" contenteditable=\"false\" href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fpt-br\u002Fsql\u002Ft-sql\u002Fqueries\u002Fselect-group-by-transact-sql?view=sql-server-2017\" target=\"_blank\" rel=\"noopener noreferrer\"\u003E\u003Cspan id=\"E934\" class=\"qowt-font10-Arial qowt-stl-Hyperlink\"\u003ESELECT – GROUP BY – Transact-SQL\u003C\u002Fspan\u003E\u003C\u002Fa\u003E\u003Cspan id=\"E935\" class=\"qowt-font10-Arial\"\u003E por \u003C\u002Fspan\u003E\u003Cspan id=\"E936\" class=\"qowt-font10-Arial\"\u003EMICROSOFT\u003C\u002Fspan\u003E\u003Cspan id=\"E937\" class=\"qowt-font10-Arial\"\u003E.\u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\u003Cp id=\"E938\" class=\"qowt-li-3_0 qowt-list\"\u003E\u003Ca id=\"E939\" contenteditable=\"false\" href=\"https:\u002F\u002Fblogs.msdn.microsoft.com\u002Fcraigfr\u002F2007\u002F10\u002F11\u002Fgrouping-sets-in-sql-server-2008\u002F\" target=\"_blank\" rel=\"noopener noreferrer\"\u003E\u003Cspan id=\"E940\" class=\"qowt-font10-Arial qowt-stl-Hyperlink\"\u003EGROUPING SETS in SQL Server 2008\u003C\u002Fspan\u003E\u003C\u002Fa\u003E\u003Cspan id=\"E941\" class=\"qowt-font10-Arial\"\u003E por \u003C\u002Fspan\u003E\u003Cspan id=\"E942\" class=\"qowt-font10-Arial\"\u003ECraig Fr\u003C\u002Fspan\u003E\u003Cspan id=\"E943\" class=\"qowt-font10-Arial\"\u003Ee\u003C\u002Fspan\u003E\u003Cspan id=\"E944\" class=\"qowt-font10-Arial\"\u003Eedman\u003C\u002Fspan\u003E\u003Cspan id=\"E945\" class=\"qowt-font10-Arial\"\u003E. \u003C\u002Fspan\u003E\u003C\u002Fp\u003E\r\n\r\n\u003C\u002Fdiv\u003E\r\n\u003C\u002Fdiv\u003E\r\n\u003C\u002Fdiv\u003E\r\n\u003C\u002Fdiv\u003E\r\n\u003C\u002Fdiv\u003E\r\n\u003C\u002Fdiv\u003E\r\n\u003C\u002Fdiv\u003E\r\n\u003C\u002Fdiv\u003E","excerpt":"\u003Cp\u003ESQL Server: Chega ser estranho pensar que trabalhemos com tanta frequência com sumarização de dados e ainda assim a opção GROUPING SETS seja desconhecida\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server\u002Fagrupando-dados-com-grouping-sets","date":"4 nov, 2019","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F05\u002F24111854\u002FSSQL-768x403.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":83,"views_count":688900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"SQL Server","slug":"sql-server","id":7212,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server"}],"tags":[],"relateds":[],"seo":[],"type":"post"},{"id":149245,"title":"Consultando arquivos JSON no SQL Server","content":"O formato JSON (Java Script Object Notation) há muito está consolidado no mercado, com muitas ferramentas exportando e consumindo arquivos neste formato.\r\n\r\nPor conta disso, muitas vezes precisamos cruzar dados de um arquivo JSON com dados relacionais, por exemplo.\r\n\r\nPara esses casos, o SQL Server oferece a função OPENJSON. Neste artigo, apresento alguns exemplos de uso da função em declarações SQL.\r\n\u003Ch2\u003EComo ler dados JSON\u003C\u002Fh2\u003E\r\nEsta função foi incorporada no SQL Server a partir da versão 2016. Ela permite ler um arquivo JSON e retornar um resultado em formato de tabela. Dessa forma, é possível cruzar dados semiestruturados com dados relacionais.\r\n\r\nPorém, é importante observar que ela não lida com coleções de documentos JSON, mas sim com um único arquivo por chamada.\r\n\r\nAlém disso, deve-se observar também que a base de dados que usa OPENJSON precisa ter nível de compatibilidade 130 ou superior. Caso chame a função numa base de dados mais antiga, receberá uma mensagem de erro como essa:\r\n\u003Cpre\u003E\u003Ccode class=\"language-bash\"\u003EMsg 208, Level 16, State 1, Line XX\r\nInvalid object name 'OPENJSON'\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n\u003Ch2\u003EExemplos de uso\u003C\u002Fh2\u003E\r\nA seguir mostro alguns exemplos de uso da função OPENJSON. Preparei exemplos usando o mesmo arquivo JSON (disponível \u003Ca href=\"https:\u002F\u002Fgist.github.com\u002FVItor100\u002F2425d415d85b0be23bb0f002b2f9a9df\"\u003Eneste link\u003C\u002Fa\u003E). Este documento trata de informações de associados de um clube de colecionadores de automóveis.\r\n\r\nOs dados tratam do nome do colecionador, idade, cidade onde reside e a descrição dos carros que possui, como marca, cor, ano de fabricação, valor estimado e, por fim, nome e cidade de residência dos proprietários anteriores.\r\n\u003Cul\u003E\r\n \t\u003Cli\u003EUm script contendo as declarações SQL de todos os exemplos apresentados neste artigo está disponível \u003Ca href=\"https:\u002F\u002Fgist.github.com\u002FVItor100\u002F810ee6f29d0a59b9f9e93655da4614e7\"\u003Eneste link\u003C\u002Fa\u003E.\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\n\u003Ch3\u003EExemplo 1 – Consulta simples\u003C\u002Fh3\u003E\r\nA primeira coisa a se entender sobre essa função é que ela não se presta a ler o conteúdo de um arquivo externo. Ela apenas interpreta a estrutura de um documento JSON, com suas marcações (ou tags), valores e vetores (ou arrays).\r\n\r\nPor essa razão, na maioria das vezes usaremos OPENJSON precedida da função OPENROWSET: esta lê o arquivo desejado e joga seu conteúdo numa variável, que em seguida será tratada pela função OPENSON.\r\n\r\nVeja o exemplo a seguir.\r\n\r\n\u003Cstrong\u003EDeclaração\u003C\u002Fstrong\u003E\r\n\u003Cpre\u003E\u003Ccode class=\"line-numbers language-sql\"\u003E--Exemplo 1 : consulta genérica\r\nDECLARE @json AS NVARCHAR(MAX)\r\n\r\nSELECT @json = BulkColumn \r\nFROM OPENROWSET (BULK 'C:\\TEMP\\exemplo.json', SINGLE_CLOB) as Arquivo\r\n\r\nSELECT F.* FROM OPENJSON(@json) AS F\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n\u003Cstrong\u003EResultado\u003C\u002Fstrong\u003E\r\n\r\n\u003Cimg class=\"aligncenter size-full wp-image-149249\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F03\u002Fm.png\" alt=\"\" width=\"336\" height=\"91\" \u002F\u003E\r\n\r\nObserve que as marcações foram convertidas em campos e que o vetor foi mantido na sua forma original. Além disso, tem-se uma nova coluna “type”, que informa a posição da marcação dentro do documento JSON.\r\n\r\nJá temos aqui um avanço, mas este output ainda não é muito útil para manipulação. Seria muito difícil gerar métricas sobre dados neste formato ou cruzá-los com dados relacionais.\r\n\u003Ch3\u003EExemplo 2 – Nomeando as marcações como nomes de campos\u003C\u002Fh3\u003E\r\nNeste novo exemplo o problema anterior é facilmente corrigido com o uso da opção WITH (), que permite definir campos, seus tipos de dados e a origem dos dados exibidos. O resultado aqui é uma tabela relacional como outra qualquer.\r\n\r\nNo exemplo a seguir, resolvi manter os nomes de colunas idênticos aos nomes das marcações. O ponto importante é o mapeamento das colunas usando o identificador ‘$.[NomeDaMarcação]’ de forma apropriada.\r\n\r\n\u003Cstrong\u003EDeclaração\u003C\u002Fstrong\u003E\r\n\u003Cpre\u003E\u003Ccode class=\"line-numbers language-sql\"\u003E--Exemplo 2 : nomeando as marcações como nomes de campos\r\nDECLARE @json AS NVARCHAR(MAX)\r\n\r\nSELECT @json = BulkColumn \r\nFROM OPENROWSET (BULK 'C:\\TEMP\\exemplo.json', SINGLE_CLOB) as Arquivo\r\n\r\nSELECT F.*\r\nFROM OPENJSON(@json) \r\nWITH (\r\n Colecionador VARCHAR(200)\t'$.Colecionador',\r\n Idade INTEGER '$.Idade',\r\n Cidade VARCHAR(200)\t'$.Cidade',\r\n Carros NVARCHAR(MAX) AS JSON \r\n) AS F\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n\u003Cstrong\u003EResultado\u003C\u002Fstrong\u003E\r\n\r\n\u003Cimg class=\"aligncenter size-full wp-image-149250\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F03\u002Fm1.png\" alt=\"\" width=\"463\" height=\"37\" \u002F\u003E\r\n\u003Ch3\u003EExemplo 3 – consultando dados dentro de vetores\u003C\u002Fh3\u003E\r\nNo exemplo anterior ainda temos um problema. É difícil consultar os dados do vetor “carros”. Isso é resolvido usando o operador CROSS APPLY, que trata este vetor como se fosse independente da estrutura do documento JSON.\r\n\r\nPara isso, no exemplo anterior eu já defini de propósito a coluna “Carros”, como “NVARCHAR(MAX) AS JSON”. Veja como fica a declaração SQL.\r\n\r\n\u003Cstrong\u003EDeclaração\u003C\u002Fstrong\u003E\r\n\u003Cpre\u003E\u003Ccode class=\"line-numbers language-sql\"\u003E--Exemplo 3 : consultando dados dentro de vetores\r\nDECLARE @json AS NVARCHAR(MAX)\r\n\r\nSELECT @json = BulkColumn \r\nFROM OPENROWSET (BULK 'C:\\TEMP\\exemplo.json', SINGLE_CLOB) as Arquivo\r\n\r\nSELECT Raiz.Colecionador, Raiz.Idade, Raiz.Cidade, Carros.*\r\nFROM OPENJSON(@json) \r\nWITH (\r\n Colecionador VARCHAR(200)\t'$.Colecionador',\r\n Idade INTEGER '$.Idade',\r\n Cidade VARCHAR(200)\t'$.Cidade',\r\n Carros NVARCHAR(MAX) AS JSON \r\n)AS Raiz\r\nCROSS APPLY OPENJSON ( Raiz.Carros )\r\nWITH (\r\n Marca VARCHAR(50) '$.Marca',\r\n Cor VARCHAR(200) '$.Cor',\r\n AnoFabricacao INTEGER '$.AnoFabricacao',\r\n ValorEstimado MONEY '$.ValorEstimado', \r\n ProprietariosAnteriores NVARCHAR(MAX) AS JSON\r\n) AS Carros\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n\u003Cstrong\u003EResultado\u003C\u002Fstrong\u003E\r\n\r\n\u003Cimg class=\"aligncenter size-full wp-image-149252\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F03\u002Fss.png\" alt=\"\" width=\"569\" height=\"190\" \u002F\u003E\r\n\u003Ch3\u003EExemplo 4 – gerando métricas\u003C\u002Fh3\u003E\r\nDesta vez, o objetivo é gerar métricas sobre os dados do arquivo JSON. As métricas desejadas para o colecionador Zeca Balero são as seguintes:\r\n\u003Cul\u003E\r\n \t\u003Cli\u003EQual é o carro mais antigo da coleção (modelo e ano de fabricação)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EQual é a quantidade total e o valor médio dos carros\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EIdade média dos proprietários anteriores\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\nPara isso, ainda falta converter em colunas as marcações do vetor “ProprietariosAnteriores”. Existem mais detalhes a se considerar, mas primeiro vamos ver os resultados.\r\n\r\n\u003Cstrong\u003EDeclaração\u003C\u002Fstrong\u003E\r\n\u003Cpre\u003E\u003Ccode class=\"line-numbers language-sql\"\u003E--Exemplo 4 : gerando métricas\r\nDECLARE @json AS NVARCHAR(MAX)\r\n\r\nSELECT @json = BulkColumn \r\nFROM OPENROWSET (BULK 'C:\\TEMP\\exemplo.json', SINGLE_CLOB) as Arquivo\r\n\r\n;WITH cteMetrica (Colecionador, Idade, Cidade, Marca, AnoFabricacao, ValorEstimado,IdadePropAnt) \r\n\tAS \r\n\t(\r\n\tSELECT Raiz.Colecionador, Raiz.Idade, Raiz.Cidade, Carros.Marca,\r\n\t\tCarros.AnoFabricacao, Carros.ValorEstimado, PropAnt.Idade\r\n\tFROM OPENJSON(@json) \r\n\tWITH (\r\n\tColecionador VARCHAR(200)\t'$.Colecionador',\r\n\tIdade INTEGER '$.Idade',\r\n\tCidade VARCHAR(200)\t'$.Cidade',\r\n\tCarros NVARCHAR(MAX) AS JSON \r\n\t) AS Raiz\r\n\tCROSS APPLY OPENJSON ( Raiz.Carros )\r\n\tWITH (\r\n\tMarca VARCHAR(50)\t'$.Marca',\r\n\tCor VARCHAR(200)\t'$.Cor',\r\n\tAnoFabricacao INTEGER '$.AnoFabricacao',\r\n\tValorEstimado MONEY '$.ValorEstimado', \r\n\tProprietariosAnteriores NVARCHAR(MAX) AS JSON\r\n\t) AS Carros\r\n\tCROSS APPLY OPENJSON ( Carros.ProprietariosAnteriores)\r\n\tWITH (\r\n\tNome VARCHAR(200)\t'$.Nome',\r\n\tIdade INTEGER\t '$.Idade',\r\n\tCidade VARCHAR(200) '$.Cidade'\r\n\t) AS PropAnt\r\n\tWHERE Raiz.Colecionador = 'Zeca Balero'\r\n\t),\r\ncteMetPropAnt (Colecionador,CarroMaisAntigo, MediaIdadePropAnt)\r\n\tAS (\r\n\tSELECT \r\n c.Colecionador\r\n , MIN(c.AnoFabricacao) AS CarroMaisAntigo\r\n , AVG(c.IdadePropAnt) AS MediaIdadePropAnt \r\n\tFROM cteMetrica c\r\n\tGROUP BY c.Colecionador\r\n\t),\r\ncteMetGeral (Colecionador, Idade, Cidade, Contagem, ValorMedio)\r\n\tAS (\r\n\tSELECT \r\n T.Colecionador\r\n , T.Idade\r\n , T.Cidade\r\n , COUNT(T.Marca) AS Contagem\r\n , AVG(T.ValorEstimado) AS ValorMedio\r\n\tFROM (\r\n\t\tSELECT DISTINCT \r\n c.Colecionador\r\n , c.Idade\r\n , c.Cidade\r\n , c.Marca\r\n , c.ValorEstimado\r\n\t\tFROM cteMetrica c\r\n\t\t) T\r\n\tGROUP BY T.Colecionador, T.Idade, T.Cidade\r\n\t)\r\n\r\nSELECT M1.*, M2.*\r\nFROM cteMetGeral M1\r\n\tINNER JOIN cteMetPropAnt M2 ON M1.Colecionador = M2.Colecionador\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n\u003Cstrong\u003EResultado\u003C\u002Fstrong\u003E\r\n\r\n\u003Cimg class=\"aligncenter size-full wp-image-149253\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F03\u002Fssss.png\" alt=\"\" width=\"566\" height=\"46\" \u002F\u003E\r\n\r\nO leitor mais atento notará que o arquivo JSON lista vários antigos proprietários para cada automóvel listado. Assim, quando fizemos o CROSS APPLY com o vetor “ProprietariosAnteriores”, nós desnormalizamos os dados, gerando duplicidades que causariam cálculos incorretos.\r\n\r\nPor esta razão, essa consulta precisou eliminar essas duplicidades antes de calcular o número total de veículos da coleção e valor médio dos carros.\r\n\r\nEste é um ponto importante quando se trabalha com arquivos JSON, visto que, em essência, a existência de vetores dentro da estrutura quase sempre levará a duplicação de informações.\r\n\u003Ch2\u003EComentários finais\u003C\u002Fh2\u003E\r\nO objetivo deste trabalho foi apresentar informações introdutórias para manipulação de arquivos JSON dentro do SQL Server. Os recursos aqui mostrados ajudarão o leitor a cobrir grande número de casos de uso de arquivos JSON.\r\n\r\nOutros casos mais específicos, como a manipulação de diversos arquivos JSON, podem ser encontrados nas leituras recomendas apresentadas a seguir.\r\n\u003Ch2\u003ELeituras sugeridas\u003C\u002Fh2\u003E\r\n\u003Cul\u003E\r\n \t\u003Cli\u003E\u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fpt-br\u002Fsql\u002Frelational-databases\u002Fjson\u002Fimport-json-documents-into-sql-server?view=sql-server-2017\"\u003EImportar documentos JSON para o SQL Server\u003C\u002Fa\u003E, por MICROSOFT.\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fpt-br\u002Fsql\u002Frelational-databases\u002Fjson\u002Fjson-data-sql-server?view=sql-server-2017\"\u003EDados JSON no SQL Server\u003C\u002Fa\u003E, por MICROSOFT.\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fpt-br\u002Fsql\u002Ft-sql\u002Ffunctions\u002Fopenjson-transact-sql?view=sql-server-2017\"\u003EOPENJSON (Transact-SQL)\u003C\u002Fa\u003E, por MICROSOFT.\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E","excerpt":"\u003Cp\u003ENo seguinte artigo, Wagner Crivelini mostra como consultar arquivos JSON no SQL Server e apresenta exemplos.\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fbanco-de-dados\u002Fconsultando-arquivos-json-no-sql-server","date":"12 mar, 2019","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2019\u002F03\u002F18104336\u002FConsultando-arquivos-JSON-no-SQL-Server.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":83,"views_count":688900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"Banco de Dados","slug":"banco-de-dados","id":7209,"link":"https:\u002F\u002Fimasters.com.br\u002Fbanco-de-dados"},{"title":"SQL Server","slug":"sql-server","id":7212,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server"}],"tags":[{"title":"json","slug":"json","id":532,"link":"https:\u002F\u002Fimasters.com.br\u002Fjson"},{"title":"sql server","slug":"sql-server-2","id":324,"link":"https:\u002F\u002Fimasters.com.br\u002Fsql-server-2"}],"relateds":[],"seo":[],"type":"post"},{"id":143713,"title":"Melhorando a Experiência do Usuário com Azure Search - Parte 05: apresentando resultados","content":"Quando falamos de mecanismos de busca, pesquisar uma base de conhecimento é só metade do problema. É preciso considerar como exibir resultados.\r\n\r\nEm geral, precisamos de uma lista razoavelmente pequena e bem focada de resultados para melhorar a eficiência do trabalho.\r\n\r\nOs principais recursos e estratégias para apresentar resultados disponíveis no Azure Search são o objeto deste artigo.\r\n\u003Ch2\u003EOrdenando resultados\u003C\u002Fh2\u003E\r\nEste é um recurso simples, que pode causar um grande efeito na sua busca. Por default, os resultados são ordenados por sua nota ou “score”. Mas podemos escolher qualquer outro campo da base de conhecimento que tenha sido definido como “SORTABLE” durante a criação da base de conhecimento.\r\n\r\nPara a base que criei, algumas formas de ordenação são realmente interessantes: ordenar resultados por data de publicação (DATA), veículo da publicação (MIDIA), ou pela lista de autores (AUTOR).\r\n\r\nO exemplo a seguir combina um filtro e ordenadores numa única busca. Listo apenas os títulos que tenho publicados no portal SQL Server Central e ordeno resultados em ordem decrescente de data de publicação.\r\n\u003Cul\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBusca 1\u003C\u002Fstrong\u003E: Busca de TITULO filtrada por MIDIA e ordenada por DATA (decrescente)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EEndpoint\u003C\u002Fstrong\u003E: \u003Ca href=\"https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&$select=TITULO&$filter=MIDIA%20eq%20'SQLServerCentral'&$orderby=DATA%20desc\"\u003Ehttps:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&$select=TITULO&$filter=MIDIA%20eq%20'SQLServerCentral'&$orderby=DATA%20desc\u003C\u002Fa\u003E\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EVerbo\u003C\u002Fstrong\u003E: GET\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EHeaders (usando chave de consulta)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EContent-type\u003C\u002Fstrong\u003E: application\u002FJSON\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EApi-Key\u003C\u002Fstrong\u003E: 4DDB0B46B1CE55768C1A8B062564DAC7 (OBS: chave de consulta)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EAuthorization\u003C\u002Fstrong\u003E: “No Auth”\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBody (raw)\u003C\u002Fstrong\u003E: Vazio\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\n\u003Cstrong\u003EBody (resultado)\u003C\u002Fstrong\u003E:\r\n\u003Cpre\u003E\u003Ccode class=\"line-numbers language-csharp\"\u003E{\r\n \"@odata.context\": \"https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes('publications')\u002F$metadata#docs(TITULO)\",\r\n \"@odata.count\": 4,\r\n \"value\": [\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"SQL and the JOIN Operator\"\r\n },\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"Do You Really Need Surrogate Keys? Part 1 – Concepts and Methods\"\r\n },\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"Database Modeling and Diagrams with SQL Server 2008\"\r\n },\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"Cursors for T-SQL Beginners\"\r\n }\r\n ]\r\n}\r\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\nUma aplicação interessante deste recurso é quando ordenamos resultados de busca com relação à proximidade geográfica com o lugar onde o usuário se encontra. Obviamente isso vai exibir que sua base de conhecimento inclua as coordenadas de latitude e longitude (por exemplo, uma base de conhecimento que descreve as filiais da empresa), além de usar a função GEO.DISTANCE para calcular distância desta posição até a posição do usuário.\r\n\u003Ch2\u003ENavegação padrão\u003C\u002Fh2\u003E\r\nPor default, a navegação nos resultados do Azure Search é feita via paginação, e utilizamos parâmetros TOP e SKIP para apresentar os documentos. Estes parâmetros funcionam de forma idêntica a outras linguagens: o SKIP descarta N resultados e o TOP seleciona outros N resultados.\r\n\r\nÉ importante lembrar que os parâmetros SKIP e TOP devem trabalhar em conjunto para fins de paginação, mas eles também funcionam separadamente caso seja necessário.\r\n\r\nO exemplo a seguir mostra a paginação dos resultados de artigos que publiquei no portal iMasters, exibindo a segunda página de 10 artigos, de um total de 68 resultados listados em ordem decrescente de DATA.\r\n\u003Cul\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBusca 1\u003C\u002Fstrong\u003E: Busca de TITULO filtrada por MIDIA (“iMasters”) e ordenada por DATA, exibindo a segunda página (resultados de números 11 a 20 do total de 68 resultados).\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EEndpoint\u003C\u002Fstrong\u003E: \u003Ca href=\"https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&$select=TITULO&$filter=MIDIA%20eq%20'iMasters'&$skip=10&$top=10&$orderby=DATA%20desc\"\u003Ehttps:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&$select=TITULO&$filter=MIDIA%20eq%20'iMasters'&$skip=10&$top=10&$orderby=DATA%20desc\u003C\u002Fa\u003E\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EVerbo\u003C\u002Fstrong\u003E: GET\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EHeaders (usando chave de consulta)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EContent-type\u003C\u002Fstrong\u003E: application\u002FJSON\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EApi-Key\u003C\u002Fstrong\u003E: 4DDB0B46B1CE55768C1A8B062564DAC7 (OBS: chave de consulta)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EAuthorization\u003C\u002Fstrong\u003E: “No Auth”\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBody (raw)\u003C\u002Fstrong\u003E: Vazio\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\n\u003Cstrong\u003EBody (resultado)\u003C\u002Fstrong\u003E:\r\n\u003Cpre\u003E\u003Ccode class=\"line-numbers language-csharp\"\u003E{\r\n \"@odata.context\": \"https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes('publications')\u002F$metadata#docs(TITULO)\",\r\n \"@odata.count\": 68,\r\n \"value\": [\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"Trabalhando com tabelas particionadas\"\r\n },\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"Quando o MSDB cresce demais\"\r\n },\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"Identificando tabelas sem índices\"\r\n },\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"Servidores registrados: executando operações em todo ambiente\"\r\n },\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"Índices e o excesso de coisa boa – Parte 03: objetos grandes demais\"\r\n },\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"Índices e o excesso de coisa boa – Parte 02: objetos sem uso\"\r\n },\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"Índices e o excesso de coisa boa – Parte 01: identificando casos críticos\"\r\n },\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"SQL Server Físico vs Lógico - Parte 3\"\r\n },\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"Sobre SQL Hints, Humildade e Canja de Galinha\"\r\n },\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"SQL Server Físico vs Lógico - Parte 2\"\r\n }\r\n ]\r\n}\r\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n\u003Ch2\u003EDestacando resultados\u003C\u002Fh2\u003E\r\nO Azure Search também permite destacar um resultado, funcionalidade que já virou padrão em grande parte das aplicações de busca. A forma de se obter este resultado é bastante simples: basta incluir na consulta a propriedade “highlight” e informar em quais campos serão destacados os termos da busca.\r\n\r\nVeja este exemplo.\r\n\u003Cul\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBusca 2\u003C\u002Fstrong\u003E: Busca dos artigos publicados na MIDIA “IBM DeveloperWorks” que contém a palavra “DB2”, fazendo highlight na palavra pesquisada apenas quando ela aparecer no campo TITULO do documento.\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EEndpoint\u003C\u002Fstrong\u003E: \u003Ca href=\"https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&$filter=MIDIA%20eq%20'IBM\"\u003Ehttps:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&$filter=MIDIA%20eq%20'IBM\u003C\u002Fa\u003E DeveloperWorks'&search='DB2'&highlight=TITULO\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EVerbo\u003C\u002Fstrong\u003E: GET\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EHeaders (usando chave de consulta)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EContent-type\u003C\u002Fstrong\u003E: application\u002FJSON\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EApi-Key\u003C\u002Fstrong\u003E: 4DDB0B46B1CE55768C1A8B062564DAC7 (OBS: chave de consulta)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EAuthorization\u003C\u002Fstrong\u003E: “No \u003Cstrong\u003EAuth”\u003C\u002Fstrong\u003E\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBody\u003C\u002Fstrong\u003E \u003Cstrong\u003E(raw)\u003C\u002Fstrong\u003E: Vazio\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\n\u003Cstrong\u003EBody (resultado)\u003C\u002Fstrong\u003E:\r\n\u003Cpre\u003E\u003Ccode class=\"line-numbers language-csharp\"\u003E{\r\n \"@odata.context\": \"https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes('publications')\u002F$metadata#docs\",\r\n \"@odata.count\": 2,\r\n \"value\": [\r\n {\r\n \"@search.score\": 0.4950139,\r\n \"@search.highlights\": {\r\n \"TITULO@odata.type\": \"#Collection(String)\",\r\n \"TITULO\": [\r\n \"Usando Expressões de Tabela (CTEs) Recursivas no <em>DB2<\u002Fem>\"\r\n ]\r\n },\r\n \"id\": \"77\",\r\n \"MIDIA\": \"IBM DeveloperWorks\",\r\n \"LINGUA\": \"Português\",\r\n \"AUTOR\": \"Wagner Crivelini\",\r\n \"TITULO\": \"Usando Expressões de Tabela (CTEs) Recursivas no DB2\",\r\n \"TEMA\": \"Alguns recursos do DB2 estão disponíveis há muito tempo, mas pouca gente usa. Isto acontece com uma funcionalidade das expressões de tabela (as CTEs, da sigla em inglês Common Table Expressions), que é suportada pelo DB2 desde 2004. Muita gente conhece e usa as CTEs, mas poucos desenvolvedores sabem que podem incluir recursividade em suas CTEs. As CTEs recursivas oferecem grande versatilidade para nossas declarações SQL e o DB2 também as suporta há muito tempo. Estranhamente, este é um recurso pouco conhecido.\",\r\n \"DATA\": 41163,\r\n \"LINK\": \"https:\u002F\u002Fwww.ibm.com\u002Fdeveloperworks\u002Fbr\u002Flocal\u002Fdata\u002Fcte_recursivas_db2\u002F\",\r\n \"TAGS\": \"CTE\"\r\n },\r\n {\r\n \"@search.score\": 0.32053876,\r\n \"@search.highlights\": {\r\n \"TITULO@odata.type\": \"#Collection(String)\",\r\n \"TITULO\": [\r\n \"DBA 101: administrando estruturas de dados do <em>DB2<\u002Fem>\"\r\n ]\r\n },\r\n \"id\": \"76\",\r\n \"MIDIA\": \"IBM DeveloperWorks\",\r\n \"LINGUA\": \"Português\",\r\n \"AUTOR\": \"Wagner Crivelini\",\r\n \"TITULO\": \"DBA 101: administrando estruturas de dados do DB2\",\r\n \"TEMA\": \"Entendendo os conceitos de Tablespace, Bufferpool, Extent e Container\",\r\n \"DATA\": 41215,\r\n \"LINK\": \"https:\u002F\u002Fwww.ibm.com\u002Fdeveloperworks\u002Fbr\u002Flocal\u002Fdata\u002Fdba_101_administrando_estruturas_dados_db2\u002F\",\r\n \"TAGS\": \"físico\"\r\n }\r\n ]\r\n}\r\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\nComo se vê, foram encontrados apenas dois documentos que atenderam ao critério de pesquisa, sendo que ambos apresentaram a palavra “DB2”. Por conta disso, foram geradas marcações HTML (“<em><\u002Fem>”) para destaque ou ênfase do texto desejado. Estas marcações são apresentadas no quadro acima na cor azul.\r\n\u003Ch2\u003ENavegação facetada\u003C\u002Fh2\u003E\r\nEste tipo de navegação é largamente utilizado hoje em dia, especialmente em grandes sites de vendas online. Esta navegação permite que o próprio usuário aplique seus filtros enquanto analisa os resultados apresentados por sua aplicação de busca. Veja na imagem a seguir um exemplo de aplicação com navegação facetada (fonte: documentação do Azure Search).\r\n\r\n\u003Cimg class=\"aligncenter wp-image-143714 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F10\u002FFACETS.jpg\" alt=\"\" width=\"620\" height=\"450\" \u002F\u003E\r\n\r\nO uso deste tipo de navegação requer uma preparação da base de conhecimento, que precisa identificar quais campos são “FACETABLE”, ou seja, que campos que podem ser usados para navegação facetada. O grande problema é que os campos e propriedades de um índice não são editáveis: pode-se acrescentar campos, mas não alterar ou excluí-los. Mais uma vez observamos a importância de um bom planejamento de tudo que se espera fazer com uma base de conhecimento antes de se criar o índice.\r\n\r\nNo caso da base que eu utilizo nesta série de artigos, o índice \u003Cstrong\u003Epublications\u003C\u002Fstrong\u003E não previu uso de nenhum campo para navegação facetada. Nesta situação, a única saída é reconstruir o índice utilizado.\r\n\r\nNum índice pequeno, este processo é bem rápido. Mas a situação pode ser muito diferente dependendo da quantidade e tamanho dos documentos envolvidos, podendo deixar sua aplicação ou site fora do ar por horas, se não dias.\r\n\r\nA figura a seguir mostra a nova configuração do índice \u003Cstrong\u003Epublications\u003C\u002Fstrong\u003E.\r\n\r\n\u003Cimg class=\"aligncenter wp-image-143715 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F10\u002Flines.jpg\" alt=\"\" width=\"620\" height=\"470\" \u002F\u003E\r\n\r\nVeja a seguir como retornar um resultado facetado. Por simplificação e clareza, uso o método POST para destacar cada elemento informado. A consulta apresenta os campos TITULO e TAGS dos artigos que publiquei no portal iMasters, listando os resultados em ordem decrescente de DATA e, além de tudo, permitindo navegação facetada por AUTOR.\r\n\r\nVeja que o Azure Search acrescentou um bloco com cada rótulo encontrado no campo AUTOR e mais a contagem dos resultados obtidos para cada um dos casos. Neste exemplo, foram encontrados apenas dois rótulos distintos, como vemos a seguir.\r\n\u003Cul\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBusca 4\u003C\u002Fstrong\u003E: Busca de TITULO filtrada por MIDIA (“iMasters”) e ordenada por DATA, exibindo navegação facetada por AUTOR.\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EEndpoint\u003C\u002Fstrong\u003E: \u003Ca href=\"https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs\u002Fsearch?api-version=2016-09-01\"\u003Ehttps:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs\u002Fsearch?api-version=2016-09-01\u003C\u002Fa\u003E\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EVerbo\u003C\u002Fstrong\u003E: POST\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EHeaders (usando chave de consulta)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EContent-type\u003C\u002Fstrong\u003E: application\u002FJSON\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EApi-Key\u003C\u002Fstrong\u003E: 4DDB0B46B1CE55768C1A8B062564DAC7 (OBS: chave de consulta)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EAuthorization\u003C\u002Fstrong\u003E: “No Auth”\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\n\u003Cstrong\u003EBody raw\u003C\u002Fstrong\u003E:\r\n\u003Cpre\u003E\u003Ccode class=\"line-numbers language-csharp\"\u003E{\r\n \"search\": \"*\"\r\n , \"count\": true\r\n , \"queryType\":\"full\"\r\n , \"select\": \"TITULO,TAGS\"\r\n , \"filter\": \"MIDIA eq 'iMasters'\"\r\n , \"orderby\": \"DATA desc\"\r\n , \"facets\":[\"AUTOR\"]\r\n}\r\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n\u003Cstrong\u003EBody (resultado)\u003C\u002Fstrong\u003E:\r\n\u003Cpre\u003E\u003Ccode class=\"line-numbers language-csharp\"\u003E(-- amostra do resultado)\r\n{\r\n \"@odata.context\": \"https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes('publications')\u002F$metadata#docs(TITULO,TAGS)\",\r\n \"@odata.count\": 68,\r\n \"@search.facets\": {\r\n \"AUTOR@odata.type\": \"#Collection(Microsoft.Azure.Search.V2016_09_01.QueryResultFacet)\",\r\n \"AUTOR\": [\r\n {\r\n \"count\": 67,\r\n \"value\": \"Wagner Crivelini\"\r\n },\r\n {\r\n \"count\": 1,\r\n \"value\": \"Wagner Crivelini & Paulo Roberto Elias\"\r\n }\r\n ]\r\n },\r\n \"@search.nextPageParameters\": {\r\n \"search\": \"*\",\r\n \"count\": true,\r\n \"queryType@odata.type\": \"#Microsoft.Azure.Search.V2016_09_01.QueryType\",\r\n \"queryType\": \"full\",\r\n \"select\": \"TITULO,TAGS\",\r\n \"filter\": \"MIDIA eq 'iMasters'\",\r\n \"orderby\": \"DATA desc\",\r\n \"facets@odata.type\": \"#Collection(String)\",\r\n \"facets\": [\r\n \"AUTOR\"\r\n ],\r\n \"skip\": 50\r\n },\r\n \"value\": [\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"SQL Server: Auditando Dados com Tabelas Temporais\",\r\n \"TAGS\": \"Tabela Temporal\"\r\n },\r\n {\r\n \"@search.score\": 1,\r\n \"TITULO\": \"Introdução ao Luis - Parte 04: Aplicação em Produção\",\r\n \"TAGS\": \"LUIS\"\r\n }, \r\n ........................................................................\r\n ],\r\n \"@odata.nextLink\": \"https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes('publications')\u002Fdocs\u002Fsearch.post.search?api-version=2016-09-01\"\r\n}\r\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\r\n\u003Ch2\u003EComentários finais\u003C\u002Fh2\u003E\r\nA navegação e apresentação dos resultados de uma busca são elementos essenciais para o sucesso da sua aplicação. Portanto, dedique o tempo adequado para planejar sua aplicação e invista na simplicidade de uso e poder de pesquisa do Azure Search.\r\n\r\nEste artigo traz exemplos elementares para os principais recursos de navegação e apresentação disponíveis neste serviço. Deixo a cargo do leitor a adaptação destes exemplos para caso mais complexos.\r\n\r\nNo sexto e último artigo da série, o tema é o uso do Azure Search para um novo tipo de aplicação: as buscas cognitivas, que usam recursos de aprendizado de máquina (Machine Learning) e linguagem natural (Natural Language Processing - NLP) para identificar conteúdo sobre dados desestruturados.\r\n\u003Ch2\u003ELeituras sugeridas\u003C\u002Fh2\u003E\r\n\u003Cul\u003E\r\n \t\u003Cli\u003E\u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Fsearch\u002F\"\u003EAzure Search Documentation\u003C\u002Fa\u003E, por MICROSOFT.\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Ca href=\"https:\u002F\u002Fapp.pluralsight.com\u002Flibrary\u002Fcourses\u002Fazure-adding-search-abilities-apps\"\u003EAdding Search Abilities to Your Apps with Azure Search\u003C\u002Fa\u003E, por Chad Campbell, PLURALSIGHT.\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Fsearch\u002Fsearch-faceted-navigation\"\u003EHow to implement faceted navigation in Azure Search\u003C\u002Fa\u003E, por MICROSOFT.\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E","excerpt":"\u003Cp\u003EContinuando a sua série de artigos sobre o Azure Search, o autor apresenta exemplos elementares para os principais recursos de navegação e apresentação disponíveis neste serviço.\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fbanco-de-dados\u002Fmelhorando-experiencia-usuario-com-azure-search-parte-05-apresentando-resultados","date":"5 out, 2018","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F10\u002F04162704\u002FAzuuu-768x403.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":83,"views_count":688900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"Banco de Dados","slug":"banco-de-dados","id":7209,"link":"https:\u002F\u002Fimasters.com.br\u002Fbanco-de-dados"},{"title":"Microsoft Azure","slug":"windows","id":7277,"link":"https:\u002F\u002Fimasters.com.br\u002Fwindows"}],"tags":[{"title":"Azure search","slug":"azure-search","id":6253,"link":"https:\u002F\u002Fimasters.com.br\u002Fazure-search"},{"title":"Body","slug":"body","id":7820,"link":"https:\u002F\u002Fimasters.com.br\u002Fbody"},{"title":"microsoft azure","slug":"microsoft-azure","id":2935,"link":"https:\u002F\u002Fimasters.com.br\u002Fmicrosoft-azure"},{"title":"navegação facetada","slug":"navegacao-facetada","id":4121,"link":"https:\u002F\u002Fimasters.com.br\u002Fnavegacao-facetada"},{"title":"resultados","slug":"resultados","id":3911,"link":"https:\u002F\u002Fimasters.com.br\u002Fresultados"}],"relateds":[],"seo":[],"type":"post"},{"id":142940,"title":"Melhorando a Experiência do Usuário com Azure Search - Parte 04: recursos avançados","content":"Os mecanismos de busca que temos atualmente estão cada vez mais poderosos. E o mesmo acontece com o Azure Search.\r\n\r\nNo artigo anterior, mostrei como este serviço funciona em operações básicas, mas isso é só a ponta do iceberg. Existe uma grande variedade de funcionalidades e recursos adicionais neste serviço.\r\n\r\nApresento a seguir algumas funcionalidades mais sofisticadas do Azure Search.\r\n\u003Ch2\u003EPensando no mundo real\u003C\u002Fh2\u003E\r\nQuando se trabalha com uma base de conhecimento pequena, raramente vamos nos importar com performance das consultas, quantidade de documentos retornados em uma consulta ou mesmo a quantidade de consultas simultâneas, mas no mundo real as coisas são diferentes. Quando sua base chega a ordem de Terabytes, as preocupações e os cuidados necessários para que sua aplicação funcione bem passam a ser bem diferentes.\r\n\r\nVem daí a necessidade de termos recursos mais poderosos, seja para aumentar a velocidade da consulta, para identificação de uma resposta com maior probabilidade de acerto, ou para que se reduza a sobrecarga de trabalho do serviço a fim de permitir que mais usuários possam acessá-lo simultaneamente.\r\n\u003Ch2\u003ETipos de consulta\u003C\u002Fh2\u003E\r\nJá apresentei consultas que são classificadas como “pesquisas de texto de forma livre”, que chamei de consultas básicas. Este é o primeiro tipo, mas o Azure Search oferece \u003Ca href=\"https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Fsearch\u002Fsearch-query-overview\"\u003E10 tipos diferentes de consultas\u003C\u002Fa\u003E. As demais costumam ser chamadas genericamente de pesquisas avançadas.\r\n\r\nAs pesquisas avançadas estão intimamente ligadas ao “modelo” ou esquema definido para o índice. Podemos fazer buscas em campos específicos dos documentos, filtrar documentos, ordená-los e realizar buscas de diferentes formas.\r\n\r\nPara facilitar, apresento outra vez o quadro com o modelo dos documentos que utilizo no índice criado no segundo artigo da série.\r\n\u003Cpre class=\"brush: javascript; gutter: true\"\u003E{\r\n\r\n "id" : "31"\r\n\r\n , "MIDIA" : "iMasters"\r\n\r\n , "LINGUA" : "Português"\r\n\r\n , "AUTOR" : "Wagner Crivelini"\r\n\r\n , "TITULO" : "Dicas e truques para importação de arquivos em formato texto"\r\n\r\n , "TEMA" : "Tem inúmeras coisas no mundo de TI que nos são vendidas como se fossem mais fáceis que roubar doce... "\r\n\r\n , "DATA" : "03\u002F12\u002F2013"\r\n\r\n , "LINK" : "https:\u002F\u002Fimasters.com.br\u002Fbanco-de-dados\u002Fdicas-e-truques-para-importacao-de-arquivos-em-formato-texto"\r\n\r\n , "TAGS" : "arquivos texto"\r\n\r\n}\u003C\u002Fpre\u003E\r\nObserve que na definição do índice “publications”, defini que todos os campos são do tipo “SEARCHABLE”, com exceção do campo “DATA”.\r\n\r\n\u003Cimg class=\"aligncenter wp-image-142941 size-full\" src=\"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F09\u002FFIELDS.jpg\" alt=\"\" width=\"620\" height=\"427\" \u002F\u003E\r\n\r\n\u003Cstrong\u003EObservação\u003C\u002Fstrong\u003E: os nomes de campos distinguem letras maiúsculas e minúsculas; é necessário conhecer a grafia exata para usá-los nas pesquisas.\r\n\r\nA seguir apresento alguns exemplos onde exploro quatro tipos de pesquisas avançadas:\r\n\u003Cul\u003E\r\n \t\u003Cli\u003EPesquisas por proximidade\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EPesquisas “fuzzy” (que usam lógica nebulosa)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EPesquisas com “boosting” para termos especiais\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EPesquisas com expressões regulares\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\nObserve que nos exemplos que apresento a seguir eu incluo o parâmetro “queryType=full” para informar que estou realizando pesquisas complexas.\r\n\u003Ch2\u003EPesquisas por proximidade\u003C\u002Fh2\u003E\r\nSe tentamos fazer uma busca de duas palavras usando consultas simples, temos apenas duas alternativas: ou pesquisamos uma cadeia de caracteres exata, ou buscamos documentos que contenham as duas palavras desejadas. É comum que nenhuma das opções resolva seu problema.\r\n\r\nA primeira alternativa é restrita demais. A segunda é aberta demais. Como fazer para buscar palavras que estejam próximas umas das outras, independente da sequência em que se apresentam?\r\n\r\nPronto, é isso que faz a pesquisa por proximidade.\r\n\r\nVeja o exemplo a seguir. Sei que a base de dados tem 17 documentos que apresentam a palavra “modelo” (sugiro que não acredite em mim e tente verificar por conta própria), mas quero fazer uma busca que traga apenas documentos que tenham as palavras “modelo” e “importante” separadas por até três outras palavras.\r\n\r\nEssa é a pesquisa que apresento no quadro a seguir. Especifico as palavras que desejo encontrar e uso o operador “~” para informar qual é a distância aceitável para minha pesquisa.\r\n\u003Cul\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBusca 1\u003C\u002Fstrong\u003E: pesquisa por proximidade das palavras “modelo” e “importante”, que podem estar separadas por até três palavras (a proximidade desejada)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EEndpoint\u003C\u002Fstrong\u003E: \u003Ca href=\"https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&search=%22modelo%20importante%22~3\"\u003Ehttps:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&search=%22modelo%20importante%22~3\u003C\u002Fa\u003E\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EVerbo\u003C\u002Fstrong\u003E: GET\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EHeaders (usando chave de consulta)\u003C\u002Fstrong\u003E: Content-type: application\u002FJSON\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EApi-Key\u003C\u002Fstrong\u003E: 4DDB0B46B1CE55768C1A8B062564DAC7 (OBS: chave de consulta)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EAuthorization\u003C\u002Fstrong\u003E: “No Auth”\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBody (raw)\u003C\u002Fstrong\u003E: vazio\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\n\u003Cstrong\u003EBody (resultado)\u003C\u002Fstrong\u003E:\r\n\u003Cpre class=\"brush: javascript; gutter: true\"\u003E(foi encontrado um único documento)\r\n\r\n{\r\n\r\n "@odata.context": "https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes('publications')\u002F$metadata#docs",\r\n\r\n "@odata.count": 1,\r\n\r\n "value": [\r\n\r\n {\r\n\r\n "@search.score": 0.07630738,\r\n\r\n "id": "56",\r\n\r\n "MIDIA": "iMasters",\r\n\r\n "LINGUA": "Português",\r\n\r\n "AUTOR": "Wagner Crivelini",\r\n\r\n "TITULO": "Identificando tabelas sem índices",\r\n\r\n "TEMA": "A maioria dos arquitetos de bancos de dados concorda que toda tabela deve ter uma chave primária. Em outras palavras, toda tabela precisa ter um identificador de registros que garanta a unicidade dos dados (quer dizer: que não existam dados duplicados). Essa é uma característica tão importante no modelo relacional que, no momento em que se cria a chave primária da tabela (daqui por diante chamaremos apenas de PK, do inglês “primary key”), automaticamente o SQL Server cria também um índice clusterizado sobre este(s) mesmo(s) campo(s).",\r\n\r\n "DATA": 42814,\r\n\r\n "LINK": "https:\u002F\u002Fimasters.com.br\u002Fbanco-de-dados\u002Fsql-server\u002Fidentificando-tabelas-sem-indices\u002F?trace=1519021197&source=admin",\r\n\r\n "TAGS": "HEAP"\r\n\r\n }\r\n\r\n ]\r\n\r\n}\u003C\u002Fpre\u003E\r\nObserve que a sequência de palavras que existe no documento não alterou o resultado da busca.\r\n\u003Ch2\u003EPesquisas Fuzzy\u003C\u002Fh2\u003E\r\nJá teve problema para encontrar um documento que, no final das contas, você descobriu que a palavra pesquisada tinha sido digitada de forma errada?\r\n\r\nPara estas situações, pode-se executar pesquisas com lógica nebulosa (“fuzzy logic”). Estas pesquisas buscam palavras semelhantes a um radical: informa-se o radical desejado seguido do operador “~” e um valor entre 0 (valor default que pode ser omitido) e 2. Este operador especifica a distância para edição do texto buscado. Quanto maior o valor informado, mais alternativas do radical serão aceitas.\r\n\r\nVeja um exemplo interessante: quero buscar os artigos que tenham em seu título a palavra “base”, mas decidi usar uma pesquisa Fuzzy. Para simplificar o resultado, observe que especifico que a busca será feita apenas no campo TITULO e que o resultado exibirá apenas este campo. O resultado é bastante interessante.\r\n\u003Cul\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBusca 2\u003C\u002Fstrong\u003E: pesquisa Fuzzy da palavra “base” nos títulos dos artigos, considerando distância de edição zero\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EEndpoint\u003C\u002Fstrong\u003E: \u003Ca href=\"https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&searchFields=TITULO&$select=TITULO&search=base~\"\u003Ehttps:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&searchFields=TITULO&$select=TITULO&search=base~\u003C\u002Fa\u003E\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EVerbo\u003C\u002Fstrong\u003E: GET\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EHeaders (usando chave de consulta)\u003C\u002Fstrong\u003E: Content-type: application\u002FJSON\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EApi-Key\u003C\u002Fstrong\u003E: 4DDB0B46B1CE55768C1A8B062564DAC7 (OBS: chave de consulta):\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EAuthorization\u003C\u002Fstrong\u003E: “No Auth”\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBody (raw)\u003C\u002Fstrong\u003E: vazio\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\n\u003Cstrong\u003EBody (resultado)\u003C\u002Fstrong\u003E:\r\n\u003Cpre class=\"brush: javascript; gutter: true\"\u003E{\r\n\r\n "@odata.context": "https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes('publications')\u002F$metadata#docs(TITULO)",\r\n\r\n "@odata.count": 5,\r\n\r\n "value": [\r\n\r\n {\r\n\r\n "@search.score": 1.1838781,\r\n\r\n "TITULO": "Preparando sua Base de Dados para o Mundo"\r\n\r\n },\r\n\r\n {\r\n\r\n "@search.score": 1.1838781,\r\n\r\n "TITULO": "Usando a dica HASH JOIN - estudo de caso"\r\n\r\n },\r\n\r\n {\r\n\r\n "@search.score": 0.9183874,\r\n\r\n "TITULO": "As famosas bases de dados “lentas”"\r\n\r\n },\r\n\r\n {\r\n\r\n "@search.score": 0.9183874,\r\n\r\n "TITULO": "Restaurando bases de dados em instâncias diferentes"\r\n\r\n },\r\n\r\n {\r\n\r\n "@search.score": 0.59193903,\r\n\r\n "TITULO": "Databasecast 65: front-end, back-end e DBA"\r\n\r\n }\r\n\r\n ]\r\n\r\n}\u003C\u002Fpre\u003E\r\nVeja que o resultado traz artigos que tenham em seu título as palavras “base”, “bases”, “caso” e “back”. A variabilidade da palavra encontrada é até maior do que se poderia esperar, mas é fácil perceber a lógica usada para incluir nesta lista as palavras “cASo\" e “BAck\".\r\n\u003Ch2\u003EPesquisas com boosting de termos\u003C\u002Fh2\u003E\r\nEsse tipo de pesquisa envolve duas ou mais palavras atribuindo um peso a cada uma delas. Isso informa ao otimizador de buscas qual é o termo prioritário e, assim, aumenta a nota (ou “score”) dos documentos que tiverem esta palavra.\r\n\r\nPara informar o peso de uma palavra, basta acrescentar o operador “^”, seguido de um número inteiro.\r\n\r\nNo exemplo a seguir quero encontrar entre os artigos que já publiquei, aqueles que falassem do produto CASSANDRA comparado a SGBDs transacionais. Então criei a pesquisa a seguir, que busca no campo TEMA os termos “CASSANDRA” e “transacional”, sendo que o primeiro tem peso 2.\r\n\u003Cul\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBusca 3\u003C\u002Fstrong\u003E: pesquisa Boosting das palavras “CASSANDRA” (peso 2) e “transacional” executada sobre campo TEMA. Campos exibidos: TITULO e TEMA\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EEndpoint\u003C\u002Fstrong\u003E: \u003Ca href=\"https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&searchFields=TEMA&$select=TITULO,TEMA&search=CASSANDRA^2%20transacional&relacional\"\u003Ehttps:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&searchFields=TEMA&$select=TITULO,TEMA&search=CASSANDRA^2%20transacional&relacional\u003C\u002Fa\u003E\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EVerbo\u003C\u002Fstrong\u003E: GET\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EHeaders (usando chave de consulta)\u003C\u002Fstrong\u003E: Content-type: application\u002FJSON\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EApi-Key\u003C\u002Fstrong\u003E: 4DDB0B46B1CE55768C1A8B062564DAC7 (OBS: chave de consulta)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EAuthorization\u003C\u002Fstrong\u003E: “No Auth”\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBody (raw)\u003C\u002Fstrong\u003E: vazio\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\n\u003Cstrong\u003EBody (resultado):\u003C\u002Fstrong\u003E\r\n\u003Cpre class=\"brush: javascript; gutter: true\"\u003E{\r\n\r\n "@odata.context": "https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes('publications')\u002F$metadata#docs(TITULO,TEMA)",\r\n\r\n "@odata.count": 4,\r\n\r\n "value": [\r\n\r\n {\r\n\r\n "@search.score": 0.96760786,\r\n\r\n "TITULO": "Databasecast 68: História do Cassandra",\r\n\r\n "TEMA": "Neste episódio do DatabaseCast Mauro Pichilian (@pichiliani) ), Wagner Crivelini (@wcrivelini) e o convidado Eiti Kimura (@eitikimura) flertam com as mulheres para falar sobre o Cassandra. Neste episódio você vai aprender como se adaptar rápido a mudanças, andar sobre brasas em fogo e cacos de vidro, como o Cassandra é um NoSQL diferentes dos demais, deixar a consistência transacional de lado e marcar os erros na migração para um NoSQL na sua cartela de bingo."\r\n\r\n },\r\n\r\n {\r\n\r\n "@search.score": 0.2599703,\r\n\r\n "TITULO": "DatabaseCast 61: Particionamento de dados",\r\n\r\n "TEMA": "Neste episódio do DatabaseCast Mauro Pichilian (@pichiliani), Wagner Crivelini (@wcrivelini) e o convidado Ricardo Rezende (@ricarezende) separam os dados como se eles estivesse dentro de um pacote de M&Ms. Neste episódio você vai aprender quais são os tipos de particionamento no Oracle, SQL Server, MySQL, PostgreSQL, MongoDB e Cassandra, discutir se o Hadoop é ou não um banco de dados, mandar um alô para o pessoal do Suriname e da Suécia e aprender a chamar certas soluções de gambiware."\r\n\r\n },\r\n\r\n {\r\n\r\n "@search.score": 0.19911498,\r\n\r\n "TITULO": "DatabaseCast 03: NoSQL",\r\n\r\n "TEMA": "Nesta terceira edição do DatabaseCast os participantes deixam a consistência transacional de lado para falar sobre uma das novas tecnologias da área: NoSQL ou Not Only SQL."\r\n\r\n },\r\n\r\n {\r\n\r\n "@search.score": 0.1161504,\r\n\r\n "TITULO": "Respeite a normalização",\r\n\r\n "TEMA": "Existem vários tipos de aplicações que não precisam de normalização. Estão aí os modelos NOSQL, cada vez mais populares, que não me deixam mentir. Mas se você vai trabalhar no mundo transacional, faça um favor a você mesmo: tenha muito respeito pela normalização do seu banco de dados relacional. Normalização é uma das principais ferramentas para garantir que sua base trabalhe com dados de boa qualidade, ou seja: dados consistentes e sem redundância."\r\n\r\n }\r\n\r\n ]\r\n\r\n}\u003C\u002Fpre\u003E\r\nForam encontrados quatro documentos, mas os scores variam bastante e não é difícil entender:\r\n\u003Cul\u003E\r\n \t\u003Cli\u003EO primeiro documento tem nota 0,97 porque ele contém os dois termos pesquisados\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EO documento 2 tem uma nota muito menor (0,26), porque ele contém só a palavra principal, “CASSANDRA”.\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EO documento 3 tem nota menor (0,20) porque ele só contém a palavra secundária, “transacional”.\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EE o documento 4 tem nota ainda menor (0,12), porque ele só tem a palavra “transacional”, mas bem mais longe do início do campo TEMA.\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\nA questão da distância, ou seja, o número de palavras descartadas até encontrar a(s) palavra(s) desejada(s), explica também porque o documento 2 tem uma nota baixa mesmo contendo a palavra principal.\r\n\u003Ch2\u003EPesquisas com expressões regulares\u003C\u002Fh2\u003E\r\nQuando se fala de pesquisas de dados, ainda não há nada mais conhecido e respeitado do que o uso de expressões regulares. Essa “linguagem” de pesquisa de padrões apareceu nos anos 1950 e resiste bravamente até hoje. Não é à toa que este tipo de pesquisa também seja suportado pelo Azure Search.\r\n\r\nNeste exemplo, busco pelas palavras “ROLLUP” e “ROLLBACK” usando uma expressão REGEX elementar. Lembre-se de que o Azure Search reconhece expressões REGEX desde que estejam entre caracteres “\u002F”, isto é, no início e no final da expressão.\r\n\u003Cul\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBusca 4\u003C\u002Fstrong\u003E: Pesquisa com REGEX do padrão “\u002FROLL(UP|BACK)\u002F”\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EEndpoint\u003C\u002Fstrong\u003E: \u003Ca href=\"https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&$select=AUTOR,TITULO,TEMA&search=\u002FROLL(UP|BACK)\u002F\"\u003Ehttps:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&$select=AUTOR,TITULO,TEMA&search=\u002FROLL(UP|BACK)\u002F\u003C\u002Fa\u003E\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EVerbo\u003C\u002Fstrong\u003E: GET\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EHeaders (usando chave de consulta)\u003C\u002Fstrong\u003E: Content-type: application\u002FJSON\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EApi-Key\u003C\u002Fstrong\u003E: 4DDB0B46B1CE55768C1A8B062564DAC7 (\u003Cstrong\u003Eobvervação\u003C\u002Fstrong\u003E: chave de consulta)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EAuthorization\u003C\u002Fstrong\u003E: “No Auth”\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBody (raw)\u003C\u002Fstrong\u003E: Vazio\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\n\u003Cstrong\u003EBody (resultado):\u003C\u002Fstrong\u003E\r\n\u003Cpre class=\"brush: javascript; gutter: true\"\u003E {\r\n\r\n "@odata.context": "https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes('publications')\u002F$metadata#docs(AUTOR,TITULO,TEMA)",\r\n\r\n "@odata.count": 3,\r\n\r\n "value": [\r\n\r\n {\r\n\r\n "@search.score": 0.37796447,\r\n\r\n "AUTOR": "Wagner Crivelini",\r\n\r\n "TITULO": "Trabalhando com transações",\r\n\r\n "TEMA": "A ideia de se trabalhar com transações foi uma grande invenção na história dos bancos de dados. Elas facilitam enormemente o controle de operações, além de garantirem a integridade dos dados. Resumindo: frequentemente a dupla COMMIT\u002FROLLBACK salva a pátria!"\r\n\r\n },\r\n\r\n {\r\n\r\n "@search.score": 0.37796447,\r\n\r\n "AUTOR": "Wagner Crivelini",\r\n\r\n "TITULO": "Construindo relatórios de referência cruzada no Microsoft SQL SERVER 2005 – Parte 2 : Estudo dos operadores PIVOT e ROLLUP",\r\n\r\n "TEMA": " No artigo anterior desta série, vimos os recursos básicos da linguagem T-SQL que são normalmente usados em consultas relacionadas a Business Intelligence (BI). Na verdade, as cláusulas, operadores e funções ali expostos devem fazer parte da “caixa de ferramentas” de qualquer desenvolvedor que use a linguagem SQL. Neste artigo vamos um pouco mais além. Vamos explorar, de fato, a geração de relatórios de referência cruzada (crosstab) baseados em linguagem SQL. Se você fizer uma consulta rápida no Google antes de ler este artigo, vai ver que existe uma unanimidade entre os AUTOR que escrevem sobre este tema: todos dizem que, se possível, você deve evitar usar linguagem SQL para tarefas como esta. "\r\n\r\n },\r\n\r\n {\r\n\r\n "@search.score": 0.37796447,\r\n\r\n "AUTOR": "Wagner Crivelini",\r\n\r\n "TITULO": "DesafioSQL #49 : operadores CUBE\u002FROLLUP",\r\n\r\n "TEMA": " Wagner Crivelini vem novamente nos brindar com mais um desafio. Desta vez, o velho fantasma da sumarização será confrontado e de uma maneira muito divertida, utilizando como exemplo o velho e empolgante jogo de “Super Trunfo”. E, novamente, a solução deste desafio usará o padrão ANSI, o que permite a implementação da mesma solução e vários SGBDs. E caso você tenha um desafio que gostaria de compartilhar conosco, envie sua sugestão para webeditor@sqlmagazine.com.br Divirtam-se."\r\n\r\n }\r\n\r\n ]\r\n\r\n}\u003C\u002Fpre\u003E\r\nO resultado foi exatamente o esperado, deixando de fora documentos com palavras como “trollar” e “Rock’n’Roll”.\r\n\u003Ch2\u003EFiltrando documentos\u003C\u002Fh2\u003E\r\nA ideia de um filtro é praticamente oposta à ideia de busca. O filtro exclui documentos antes da busca ser executada, ou seja, estamos escolhendo um subgrupo da base de conhecimento para depois iniciarmos uma busca.\r\n\r\nÉ possível filtrar documentos usando operadores lógicos (AND, OR , NOT), matemáticos (igual, maior, menor, etc) e outros.\r\n\r\nPode-se também combinar filtros e diferentes tipos de busca. No exemplo a seguir preparei uma pesquisa que mostra todas as minhas publicações que tratavam de NOSQL publicadas até o fim do ano de 2013.\r\n\r\n\u003Cstrong\u003EUm detalhe importante\u003C\u002Fstrong\u003E: quando criei esta base de conhecimento, eu acabei carregando os documentos convertendo datas em números inteiros. Portanto, ao invés de filtrar pela data 31\u002F12\u002F2013, devo filtrar pelo número correspondente a esta data, que é 41639.\r\n\u003Cul\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBusca 5\u003C\u002Fstrong\u003E: Pesquisa da palavra “NOSQL” em documentos publicados até 31\u002F12\u002F2013.\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EEndpoint\u003C\u002Fstrong\u003E: \u003Ca href=\"https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&$select=TITULO,TEMA,DATA&search=NOSQL&$filter=DATA%20le%2041639\"\u003Ehttps:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes\u002Fpublications\u002Fdocs?api-version=2016-09-01&$count=true&queryType=full&$select=TITULO,TEMA,DATA&search=NOSQL&$filter=DATA%20le%2041639\u003C\u002Fa\u003E\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EVerbo\u003C\u002Fstrong\u003E: GET\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EHeaders (usando chave de consulta)\u003C\u002Fstrong\u003E: Content-type: application\u002FJSON\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EApi-Key\u003C\u002Fstrong\u003E: 4DDB0B46B1CE55768C1A8B062564DAC7 (OBS: chave de consulta)\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EAuthorization\u003C\u002Fstrong\u003E: “No Auth”\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Cstrong\u003EBody (raw)\u003C\u002Fstrong\u003E: Vazio\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\n\u003Cstrong\u003EBody (resultado)\u003C\u002Fstrong\u003E:\r\n\u003Cpre class=\"brush: javascript; gutter: true\"\u003E{\r\n\r\n "@odata.context": "https:\u002F\u002Fwcrivelini-test1.search.windows.net\u002Findexes('publications')\u002F$metadata#docs",\r\n\r\n "@odata.count": 3,\r\n\r\n "value": [\r\n\r\n {\r\n\r\n "@search.score": 3.5645275,\r\n\r\n "TITULO": "Minhas Primeiras Impressões sobre NoSQL",\r\n\r\n "TEMA": "Minha experiência com bases de dados NoSQL é, para todos os efeitos práticos, zero. Meu primeiro contato com a ideia de uma base NoSQL foi em 2010, gravando um programa do DatabaseCast em que íamos entrevistar alguns especialistas. Passados três anos, eu continuo um leigo no assunto. Mas, durante esse tempo, o NoSQL ficou no meu radar. Leio, converso com gente que entende e procuro ir aprendendo aos poucos.",\r\n\r\n "DATA": 41576,\r\n\r\n },\r\n\r\n {\r\n\r\n "@search.score": 1.0664054,\r\n\r\n "TITULO": "DatabaseCast 03: NoSQL",\r\n\r\n "TEMA": "Nesta terceira edição do DatabaseCast os participantes deixam a consistência transacional de lado para falar sobre uma das novas tecnologias da área: NoSQL ou Not Only SQL.",\r\n\r\n "DATA": 40387,\r\n\r\n },\r\n\r\n {\r\n\r\n "@search.score": 0.14182188,\r\n\r\n "TITULO": "Respeite a normalização",\r\n\r\n "TEMA": "Existem vários tipos de aplicações que não precisam de normalização. Estão aí os modelos NOSQL, cada vez mais populares, que não me deixam mentir. Mas se você vai trabalhar no mundo transacional, faça um favor a você mesmo: tenha muito respeito pela normalização do seu banco de dados relacional. Normalização é uma das principais ferramentas para garantir que sua base trabalhe com dados de boa qualidade, ou seja: dados consistentes e sem redundância.",\r\n\r\n "DATA": 41374,\r\n\r\n }\r\n\r\n ]\r\n\r\n}\u003C\u002Fpre\u003E\r\n\u003Ch2\u003ELimitação do tamanho das pesquisas\u003C\u002Fh2\u003E\r\nA primeira questão de limite de tamanho a se considerar é o tamanho do próprio endpoint. Esta é uma questão simples de se resolver, bastando substituir o método GET (que uso nestes exemplos) pelo método POST.\r\n\r\nMas existem também os limites do próprio serviço de pesquisa. Estes limites são muito grandes e dificilmente são atingidos, mas eles existem. São dois:\r\n\u003Cul\u003E\r\n \t\u003Cli\u003EConsultas devem usar no máximo 1024 cláusulas, incluindo AND, OR, NOT, etc\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EOs termos da consulta não podem exceder o limite de 32 Kb, ou seja, mais de 30 mil caracteres.\u003C\u002Fli\u003E\r\n \t\u003Cli\u003EDificilmente estes limites são atingidos, até porque a execução de uma única consulta tão extensa teria uma performance caótica e poderia até mesmo comprometer todo serviço de busca.\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E\r\n\u003Ch2\u003EComentários finais\u003C\u002Fh2\u003E\r\nApresentei aqui exemplos elementares usando alguns recursos avançados de pesquisa do Azure Search. Para quaisquer fins práticos, apenas arranhei a superfície do mecanismo, já que se pode fazer buscas extremamente complexas.\r\n\r\nDe qualquer modo, em algumas ocasiões pode-se obter resultados de performance melhores caso seja possível executá-la apenas com recursos básicos, então vale a pena verificar o comportamento dos seus índices e buscas antes de implementá-los na sua aplicação.\r\n\r\nNo próximo artigo falarei sobre técnicas de apresentação e ranqueamento de resultados das buscas. Até lá!\r\n\u003Ch2\u003ELeituras sugeridas\u003C\u002Fh2\u003E\r\n\u003Cul\u003E\r\n \t\u003Cli\u003E\u003Ca href=\"https:\u002F\u002Fwww.google.com\u002Furl?q=https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Fsearch\u002F&sa=D&ust=1536246819793000\"\u003EAzure Search Documentation\u003C\u002Fa\u003E, por MICROSOFT.\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Ca href=\"https:\u002F\u002Fwww.google.com\u002Furl?q=https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Fsearch\u002Fsearch-query-overview&sa=D&ust=1536246819793000\"\u003EQuery types and composition in Azure Search\u003C\u002Fa\u003E, por MICROSOFT.\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Ca href=\"https:\u002F\u002Fwww.google.com\u002Furl?q=https:\u002F\u002Fdocs.microsoft.com\u002Fen-us\u002Fazure\u002Fsearch\u002Fsearch-query-lucene-examples&sa=D&ust=1536246819794000\"\u003ELucene syntax query examples for building advanced queries in Azure Search\u003C\u002Fa\u003E, por MICROSOFT\u003C\u002Fli\u003E\r\n \t\u003Cli\u003E\u003Ca href=\"https:\u002F\u002Fwww.google.com\u002Furl?q=https:\u002F\u002Fapp.pluralsight.com\u002Flibrary\u002Fcourses\u002Fazure-adding-search-abilities-apps&sa=D&ust=1536246819794000\"\u003EAdding Search Abilities to Your Apps with Azure Search por Chad Campbell\u003C\u002Fa\u003E, PLURALSIGHT.\u003C\u002Fli\u003E\r\n\u003C\u002Ful\u003E","excerpt":"\u003Cp\u003EDando continuidade a sua série de artigos sobre o Azure Search, neste artigo o autor apresenta algumas funcionalidades mais sofisticadas da plataforma.\u003C\u002Fp\u003E\n","link":"https:\u002F\u002Fimasters.com.br\u002Fdevsecops\u002Fmelhorando-experiencia-usuario-com-azure-search-parte-04-recursos-avancados","date":"10 set, 2018","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F09\u002F06134712\u002FSSSAAS-768x403.jpg","externalMention":"","author":{"id":"452","thumbnail":"https:\u002F\u002Fstatic.imasters.com.br\u002Fwp-content\u002Fuploads\u002F2018\u002F05\u002F30184745\u002FwagnercriveliniP-128x128.jpeg","name":"Wagner Crivelini","description":"Consultor Sênior na Microsoft, na área de Data Insights para América Latina. Especialista em bancos de dados, é colunista em diversos portais de TI do Brasil e do exterior, com mais de 100 artigos técnicos publicados. É também co-produtor do DatabaseCast, primeiro podcast brasileiro sobre bancos de dados.","slug":"wagner-crivelini","url":"https:\u002F\u002Fimasters.com.br\u002Fperfil\u002Fwagner-crivelini","registered":"2010-12-30 11:28:37","social":{"linkedin":null,"youtube":null,"facebook":"","twitter":"https:\u002F\u002Ftwitter.com\u002Fwcrivelini@gmail.com","instagram":null,"github":null,"url":"http:\u002F\u002Fwww.wcrivelini.com.br","mail":"wcrivelini@gmail.com"},"articles_count":83,"views_count":688900,"certifications":null,"conquests":null,"office":null},"categories":[{"title":"Banco de Dados","slug":"banco-de-dados","id":7209,"link":"https:\u002F\u002Fimasters.com.br\u002Fbanco-de-dados"},{"title":"DevSecOps","slug":"devsecops","id":1,"link":"https:\u002F\u002Fimasters.com.br\u002Fdevsecops"},{"title":"Microsoft Azure","slug":"windows","id":7277,"link":"https:\u002F\u002Fimasters.com.br\u002Fwindows"}],"tags":[{"title":"azure","slug":"azure","id":2238,"link":"https:\u002F\u002Fimasters.com.br\u002Fazure"},{"title":"Azure search","slug":"azure-search","id":6253,"link":"https:\u002F\u002Fimasters.com.br\u002Fazure-search"},{"title":"microsoft azure","slug":"microsoft-azure","id":2935,"link":"https:\u002F\u002Fimasters.com.br\u002Fmicrosoft-azure"}],"relateds":[],"seo":[],"type":"post"}],"totalArticles":83,"maxPages":9,"page":1,"isFetchingPagination":false},"category":{"success":false,"data":{}},"categoryArticles":{"success":false,"isFetchingPagination":false,"maxPages":0,"page":1,"data":{}},"categoryMostRead":{"success":false,"data":{}},"home":{"success":false,"featured":[],"options":{"homeProducts":[]},"allCategories":{},"featuredArticles":{},"magazines":{"data":[]},"tv":{},"forums":[],"authorsRanking":{},"events":{},"certificatedUsers":[],"news":[]},"page":{"success":false,"data":{}},"magazine":{"success":false,"magazines":[]},"schedule":{"success":false,"data":{}},"singleNews":{"success":false,"data":{}},"listNews":{"success":false,"isFetchingPagination":false,"maxPages":0,"page":1,"data":[]},"sponsors":{"success":false,"data":{}},"header":{"success":true,"menus":{"main":[{"ID":138755,"order":1,"parent":0,"title":"Back-End","url":"https:\u002F\u002Fimasters.com.br\u002Fback-end","attr":"package","target":"","classes":"package","xfn":"","description":"Tecnologias utilizadas no backend da aplicação","object_id":7158,"object":"category","type":"taxonomy","type_label":"Categoria","children":[]},{"ID":138756,"order":2,"parent":0,"title":"Mobile","url":"https:\u002F\u002Fimasters.com.br\u002Fmobile","attr":"package","target":"","classes":"package","xfn":"","description":"Conteúdos sobre Desenvolvimento Mobile nas plataformas iOS (iPhone e iPad) e Android.","object_id":4255,"object":"category","type":"taxonomy","type_label":"Categoria","children":[]},{"ID":139476,"order":3,"parent":0,"title":"Front End","url":"https:\u002F\u002Fimasters.com.br\u002Ffront-end","attr":"package","target":"","classes":"package","xfn":"","description":"Conteúdos sobre HTML5, CSS3, Javascript, JQuery, Web Standards e SEO.","object_id":7304,"object":"category","type":"taxonomy","type_label":"Categoria","children":[]},{"ID":138764,"order":4,"parent":0,"title":"DevSecOps","url":"https:\u002F\u002Fimasters.com.br\u002Fdevsecops","attr":"package","target":"","classes":"package","xfn":"","description":"","object_id":1,"object":"category","type":"taxonomy","type_label":"Categoria","children":[]},{"ID":139204,"order":5,"parent":0,"title":"Design & UX","url":"https:\u002F\u002Fimasters.com.br\u002Fdesign-ux","attr":"package","target":"","classes":"package","xfn":"","description":"Conteúdos sobre User Experience, Arquitetura de Informação, Usabilidade, Acessibilidade, Design Responsivo, Teoria do Design e Photoshop.","object_id":7252,"object":"category","type":"taxonomy","type_label":"Categoria","children":[]},{"ID":138759,"order":6,"parent":0,"title":"Data","url":"https:\u002F\u002Fimasters.com.br\u002Fdata","attr":"package","target":"","classes":"package","xfn":"","description":"Conteúdos sobre Banco de Dados Oracle, MySQL, SQL Server, MongoDB, DB2 e Postgre SQL, sobre BI e análise de dados.","object_id":16,"object":"category","type":"taxonomy","type_label":"Categoria","children":[]},{"ID":138758,"order":7,"parent":0,"title":"APIs e Microsserviços","url":"https:\u002F\u002Fimasters.com.br\u002Fapis-microsservicos","attr":"package","target":"","classes":"package","xfn":"","description":"Dicas e tutoriais sobre APIs públicas como Facebook, Twitter, PayPal, Buscapé, Google, etc e arquitetura de microsserviços, com códigos de exemplo, vídeos, cursos.","object_id":4257,"object":"category","type":"taxonomy","type_label":"Categoria","children":[]},{"ID":156291,"order":8,"parent":0,"title":"Crypto","url":"https:\u002F\u002Fcryptobusinessreview.com\u002F","attr":"","target":"","classes":"","xfn":"","description":"","object_id":156291,"object":"custom","type":"custom","type_label":"Link personalizado","children":[]}],"secondary":[{"ID":138752,"order":1,"parent":0,"title":"Fórum iMasters","url":"https:\u002F\u002Fforum.imasters.com.br\u002F","attr":"","target":"_blank","classes":"","xfn":"","description":"","object_id":138752,"object":"custom","type":"custom","type_label":"Link personalizado","children":[]},{"ID":139067,"order":2,"parent":0,"title":"Portal E-Commerce Brasil","url":"http:\u002F\u002Fwww.ecommercebrasil.com.br","attr":"","target":"","classes":"","xfn":"","description":"","object_id":139067,"object":"custom","type":"custom","type_label":"Link personalizado","children":[]},{"ID":156289,"order":3,"parent":0,"title":"CBR","url":"https:\u002F\u002Fcryptobusinessreview.com\u002F","attr":"","target":"","classes":"","xfn":"","description":"","object_id":156289,"object":"custom","type":"custom","type_label":"Link personalizado","children":[]}]}},"webinar":{"success":false,"data":{}},"webinars":{"success":false,"isFetchingPagination":false,"maxPages":0,"page":1,"data":{"next":[],"prev":[]}},"tv":{"sectionNameLeft":{"small":"Vídeos","large":"iMasters TV"},"itemsLeft":[{"text":"Em Destaque","slug":"recents"},{"text":"Mais Vistos","slug":"most-viewed"}],"sectionNameRight":{"small":"","large":""},"itemsRight":[{"text":"Mais Recentes","slug":"recents"},{"text":"7Masters","slug":"7-masters"},{"text":"PHP Experience","slug":"php-experience"},{"text":"Android DevConference","slug":"android-devconference"},{"text":"Busca","slug":"search"}],"currentVideo":"recents","currentListVideo":"recents"}} window.__SERVER_VARS__ = {"applicationRestUrl":"https:\u002F\u002Fadmin.imasters.com.br\u002Fwp-json","applicationBaseUrl":"https:\u002F\u002Fimasters.com.br"}