Arquivo mensal 30/07/2020

porPaulo Henrique Corrêa Cardoso

Insert, Update e Delete… Quer aprender ?

Fala pessoal, tudo bem ?

Você que tem acompanhado os outros artigos em Banco de dados, deve ter visto que já expliquei o que é SQL, o que é e como criamos uma banco de dados e também como criamos tabelas, colunas e chaves.

Agora vamos ver como manipular dados dentro do banco, utilizando a parte da linguagem DML (Data Manipulation Language) ou seja Linguagem de Manipulação de Dados.

Então vamos ver os comando INSERT, UPDATE e DELETE explorando cada um deles e fazendo alguns exemplos juntos… Vamos lá?

Comando INSERT.

Primeiramente vamos começar com o comando de inclusão de dados.

O comando INSERT na verdade é INSERT INTO e a estrutura do mesmo é a seguinte :
INSERT INTO table_name (column1, column2, column3, …)
VALUES (value1, value2, value3, …)

Onde table_name representa o nome da tabela que vamos inserir os dados, column[n] representa as colunas que serão consideradas na inclusão do registro e value[n] representa os dados que serão incluídos nas colunas do registro.

Então vamos para o exemplo.

INSERT INTO Categoria (Descricao)
VALUES ('Eletrônicos'),
       ('Papelaria'),
       ('Vestuário')

No exemplo acima, foi adicionado 3 categorias, na tabela Categoria (criada no artigo Criando tabelas – Microsoft SQL Server).

Como a coluna IdCategoria desta tabela esta com valor auto incremental, a mesma não precisou ser adicionada no comando de inclusão.

Esses são os valores inseridos no banco:

Agora vamos inserir registros na tabela Produto.

INSERT INTO Produto (DescProduto,Preco,Peso,Ativo,IdCategoria,DataCriacao,CodBarras)
VALUES ('TV LCD 50 Polegadas',2500.00,32.54646,1,1,GETDATE(),'')

INSERT INTO Produto (DescProduto,Preco,Peso,Ativo,IdCategoria,DataCriacao,CodBarras)
VALUES ('Caderno Capa dura 50 folhas',3.50,0.150,1,2,GETDATE(),''),
       ('Camiseta M Preta',25.99,.1367,1,3,GETDATE(),'')

Aqui temos dois exemplos, o primeiro está inserindo apenas um registro e o segundo inserindo dois registros.

Note que o valor referente a coluna IdCategoria, deve existir na tabela Categoria. Caso o mesmo não exista ocorrera o erro com a seguinte mensagem:
The INSERT statement conflicted with the FOREIGN KEY constraint “FK_ProdutoCategoria”. The conflict occurred in database “DataBaseName”, table “dbo.Categoria”, column ‘IdCategoria’.

Nos exemplos. utilizamos a função GETDATE(), que retorna a data e hora atual do sistema.
Os registros ficaram da seguinte forma:

Comando UPDATE.

Agora, vamos falar sobre o comando de atualização.

O comando UPDATE tem a seguinte estrutura básica:

UPDATE table_name SET column2 = value2 WHERE column1 = [valor de filtro]

Muito importante nos atentarmos nas condições do WHERE, pois caso as mesmas estejam erradas, podemos acabar alterando registros que não queremos.

Vamos ao exemplo:

UPDATE Produto SET Preco = 2550.00, CodBarras = '7892509106405' WHERE IdProduto = 1

UPDATE Produto SET Preco = 4.00 WHERE IdProduto = 2

Nos exemplos acima, foram realizadas alterações do preço e do código de barras do produto com IdProduto = 1 e alteramos o preço do produto com IdProduto = 2.
Os registros ficaram da seguinte forma:

Comando DELETE.

Por último vamos ver o comando de exclusão de registros.

O comando DELETE tem a seguinte estrutura:

DELETE FROM table_name WHERE column1 = [valor de filtro]

Muito importante nos atentarmos nas condições do WHERE, pois caso as mesmas estejam erradas, podemos acabar deletando registros que não queremos.

Vamos ao exemplo:

DELETE FROM Produto WHERE IdProduto = 3

Veja que o registro foi deletado.

Bom pessoal, esse é o conteúdo de hoje e com ele entendemos um pouco sobre a parte DML da linguagem SQL.

Aguarde o próximo conteúdo sobre banco de dados.

Até a próxima!!!

porPaulo Henrique Corrêa Cardoso

Programação Orientada a Objetos – ADVPL

Olá pessoal, tudo bem ?

Hoje vou falar um pouco sobre o programação orientada a objetos (POO) dentro da linguagem ADVPL.

O ADVPL é uma linguagem baseada no Clipper, sendo assim, uma linguagem estruturada.

Com a evolução das linguagens, a TOTVS buscou aprimorar sua linguagem, e com o passar do tempo, e trouxe a orientação a objetos para dentro do ADVPL.

Então, como todas as linguagens POO, ela possui Classes, Propriedades, Métodos, Herança, Encapsulamento, Polimorfismo e Abstração.

Vou explicar um pouco de cada parte do conceito de POO na linguagem ADVPL.

Primeiramente vamos começar com a definição da classe.

#INCLUDE 'TOTVS.CH'
/*/-----------------------------------------------------------
{Protheus.doc} ExemploClass
Classe de exemplo ADVPL

Uso: Geral

@author Paulo Henrique Corrêa Cardoso.
@since 27/07/2020
@version 1.0
-----------------------------------------------------------/*/
CLASS ExemploClass From LongClassName
  
  // Defina os parâmetros que sua classe deverá possuir
  Data cPropStr
  Data nPropNum
  Data dPropData
  Data oPropObj
  Data aPropArray
  Data lActive
  
  METHOD New() CONSTRUCTOR
  METHOD Activate()
  METHOD Deactivate()
  METHOD Executar()
  // Demais métodos pertinentes a sua classe 
  
ENDCLASS

Nesta primeira primeira parte de definição da classe vamos colocar o nome da classe logo após a palavra reservada CLASS e o nome da classe pai que nossa classe vai herdar após a palavra reservada From.

Como não estamos herdando essa classe de nenhuma classe especifica vamos herdar a classe LongClassName que permite a utilização de nomes longos.

Logo abaixo começamos a definir as propriedades da classe, utilizando a palavra reservada Data, seguido do nome da propriedade.

Logo abaixo vamos definir as assinaturas dos métodos existentes em nossa classe. Repare que definimos um método New que será o construtor da nossa classe, utilizando a palavra reservada CONSTRUCTOR.

E por fim, encerramos a definição da classe utilizando a palavra reservada ENDCLASS.

Com nossa classe definida, começamos a realizar a construção de nossos métodos dentro da classe.

Primeiramente vamos definir o método construtor e  entender sua importância.

/*/-----------------------------------------------------------
{Protheus.doc} New()
Construtor da classe

Uso: ExemploClass

@sample
//ExemploClass():New()

@author Paulo Henrique Corrêa Cardoso.
@since 27/07/2020
@version 1.0
-----------------------------------------------------------/*/
METHOD New() CLASS ExemploClass

  ::cPropStr      := " "
  ::nPropNum      := 0
  ::dPropData     := Date()
  Self:oPropObj   := NIL
  Self:aPropArray := {}
  Self:lActive    := .F.

Return Self

O método New, é importante para a iniciação base das propriedades da classe, ou seja seus valores default, desta forma vamos garantir a integridade do funcionamento da classe.

Também podemos definir a obrigatoriedade do preenchimento dos parâmetros da classe, obrigando a passagem deles por parâmetro do método. Isso deve ser feito da mesma forma que é feito em uma função comum do ADVPL.

Muito importante que o retorno deste método seja a palavra reservada Self, que representa o objeto da instância da nossa classe.

Ou seja nosso método New tem a função de criar a instância em que iremos trabalhar, possibilitando a utilização de todos os métodos e propriedades existentes em nossa classe.

Note que para manipularmos ou acessarmos propriedades de dentro de nossa classe podemos utilizar a palavra reservada Self ou ::, as duas formas indicam que estamos acessando propriedades ou métodos de nossa classe corrente. Isso só pode ser utilizado dentro do escopo da classe, ou seja, dentro dos métodos da mesma.

 

Outros métodos importantes de utilizamos são os métodos Activate e o Deactivate.

Com o método Activate podemos definir que nossa classe esta pronta para executar determinados métodos e realizar uma pré-validação de suas execução.

E o método Deactivate é importante para realizarmos a destruição dos objetos e informações correntes, já que o ADVPL não destrói essas informações automáticamente, deixando as mesmas em memória até a finalização da thread corrente.

Vamos defini-los :

/*/-----------------------------------------------------------
{Protheus.doc} Activate()
Ativa a classe

Uso: ExemploClass

@sample
//ExemploClass():Activate()

@author Paulo Henrique Corrêa Cardoso.
@since 27/07/2020
@version 1.0
-----------------------------------------------------------/*/
METHOD Activate() CLASS ExemploClass
  
  If !Empty(::cPropStr) .AND. ::nPropNum > 0
    ::lActive := .T.
  EndIf
Return ::lActive

/*/-----------------------------------------------------------
{Protheus.doc} Deactivate()
Desativa a classe

Uso: ExemploClass

@sample
//ExemploClass():Deactivate()

@author Paulo Henrique Corrêa Cardoso.
@since 27/07/2020
@version 1.0
-----------------------------------------------------------/*/
METHOD Deactivate() CLASS ExemploClass
    
    If ::oPropObj <> NIL 
        ::oPropObj:DeActivate()  
        FreeObj(::oPropObj)
        ::oPropObj := Nil	
    EndIf
    
    ::lActive := .F.
Return

 

Vamos agora criar um exemplo de métodos de execução:

/*/-----------------------------------------------------------
{Protheus.doc} Executar()
Método exemplo de execução na classe.

Uso: ExemploClass

@sample
//ExemploClass():Executar()

@author Paulo Henrique Corrêa Cardoso.
@since 27/07/2020
@version 1.0
-----------------------------------------------------------/*/
METHOD Executar() CLASS ExemploClass
  Local cRet := ""
    
  If ::lActive 
     If ::nPropNum > 10 
       cRet := "Data de Execução do método - " + DTOS(dPropData) + "Texto: "+ ::cPropStr
     Else
       cRet := " Propriedade numerica é menor ou igual a 10 "
     EndIf
  Else
    cRet := "A Classe não está ativa"
  EndIf
    
Return cRet

 

No exemplo a seguir vamos aprender a instanciar e executar métodos da classe.

/*/-----------------------------------------------------------
{Protheus.doc} ExecClas()
Utilizando classe de Exemplo 

Uso: ExemploClass

@sample
//U_ExecClas()

@author Paulo Henrique Corrêa Cardoso.
@since 27/07/2020
@version 1.0
-----------------------------------------------------------/*/
User Function ExecClas()
  Local oObjClass  := NIL
  Local cTextoRet  := ""
  
   // Cria instancia da classe 
   oObjClass := ExemploClass():New() 
   
   // Preenche propriedades 
   oObjClass:cPropStr := "Teste 1"
   oObjClass:nPropNum := 20
   
   // Ativa a classe
   oObjClass:Activate()
   
   // Executa métodos
   cTextoRet := oObjClass:Executar() 
   Conout(cTextoRet)
   
   // Desativa e destroi a classe
   oObjClass:Deactivate()
   FreeObj(oObjClass)
   oObjClass := NIL
    
Return

Com essas estruturas podemos definir os métodos que quisermos e compartilhar as propriedades existentes na classe, entre eles.

Tenho certeza que com a utilização da orientação a objetos você vai economizar e reutilizar muitos códigos em seus futuros desenvolvimentos.

 

Espero que gostem…

 

Até a próxima!!!

 

porPaulo Henrique Corrêa Cardoso

Trabalhando com Webservice Rest ADVPL

Já pensou em integrar suas aplicações com o ERP Protheus ? O Protheus, como vários ERP’s, são sistemas muito completos e que abrange diversas áreas da empresa, porém sabemos que muitos desses ERP’s não tem acompanhado as novas aplicações de mercado, principalmente na área web/mobile. Mas enquanto as grandes desenvolvedoras adequam seus ERP’s para essa nova geração tecnológica, podemos muito bem fazer os grandes e arcaicos ERP’s conversarem com ferramentas mais amigáveis, dessa forma unimos o melhor de cada uma das tecnologias para otimizar os trabalhos. O Protheus contempla algumas formas de realizar integração, como: Webservice SOAP EAI Próprio Webservice Rest Em minha concepção o mais aderente as plataformas existentes no mercado é o webservice Rest que possui sua representação em JSON e por padrão TOTVS já possui sua camada interface e de autenticação bem implementadas. Passos necessários para preparar seu Protheus para funcionar com o Webservice Rest:

Configurar um server de webservice Rest

Para realizar a configuração será necessário adicionarmos alguns itens no arquivo .ini do server Protheus. Sugiro que seja criado um server separado para o Webservice, tanto por questão de performance, como também por questão de manutenção.
[GENERAL]
MAXSTRINGSIZE=10
 
[HTTPV11]
Enable=1
Sockets=HTTPREST

[HTTPREST]
Port=8080
URIs=HTTPURI
SECURITY=1

[HTTPURI]
URL=/rest
PrepareIn=All
Instances=1,2

[ONSTART]
jobs=HTTPJOB
RefreshRate=30

[HTTPJOB]
MAIN=HTTP_START
ENVIRONMENT=environment
 

Desenvolvendo sua Classe Rest ADVPL

Para começarmos a desenvolver nossa Primeira classe Rest em ADVPL vamos precisar entender um pouco a ideia dos verbos existentes nesta representação:
  • POST – Verbo responsável por realizar inclusões de registros no sistema.
  • PUT – Verbo  responsável por realizar alterações de registros no sistema.
  • GET – Verbo responsável por realizar o retorno de registros do sistema.
  • DELETE – Verbo  responsável por realizar exclusões de registros do sistema.
Definidas as responsabilidades de cada método podemos começar a exemplificar cada um deles. Para isso, primeiro precisamos a construir a estrutura base do nosso fonte ADVPL para nossa classe Rest.
#Include 'Protheus.ch'
#Include 'RestFul.CH'    //Necessario utilizar a incluide do RESTFUL

/*/-----------------------------------------------------------
{Protheus.doc} WsRstExp()
Dummy function da Classe Rest
Esta função é necessario pois o ADVPL necessita de um function
dentro do fonte 
Uso: WsRstExp

@sample
//U_WsRstExp()

@author Paulo Henrique Corrêa Cardoso.
@since 21/07/2020
@version 1.0
-------------------------------------------------------------/*/
User Function WsRstExp()
Return

/*/-----------------------------------------------------------
{Protheus.doc} WsRstExp()
Definição da Classe, propriedades e assinatura dos métodos
Uso: WsRstExp

@sample
//U_WsRstExp()

@author Paulo Henrique Corrêa Cardoso.
@since 21/07/2020
@version 1.0
-------------------------------------------------------------/*/
WSRESTFUL WsRstExp DESCRIPTION "Serviço REST de exemplo"
    WSDATA param1    As STRING
    WSDATA param2    As STRING Optional

    WSMETHOD GET    DESCRIPTION "Get Exemplo"     WSSYNTAX "/WsRstExp?param1={valueParam1}&param2={valueParam2}"
    WSMETHOD POST   DESCRIPTION "Post Exemplo"    WSSYNTAX "/WsRstExp"
    WSMETHOD PUT    DESCRIPTION "Put Exemplo"     WSSYNTAX "/WsRstExp?param1={valueParam1}&param2={valueParam2}"
    WSMETHOD DELETE DESCRIPTION "Delete Exemplo"  WSSYNTAX "/WsRstExp?param1={valueParam1}&param2={valueParam2}"

END WSRESTFUL
No exemplo acima definimos a classe WsRstExp, na sequencia definimos 2 parâmetros sendo um deles como opicional. Em seguida definimos a assinatura dos 4 métodos que serão utilizados. Na definição da assinatura temos a seguinte estrutura: WSMETHOD <cVerb> [cId] DESCRIPTION <cDescription> [WSSYNTAX <cSintax>] [PATH <cPath>] [TTALK <cTTalkVersion>] Na definição do método temos a seguinte estrutura: WSMETHOD <cVerb> [cId] [QUERYPARAM <QueryParms>] [PATHPARAM <PathParms>] [HEADERPARAM <HeaderParms>] WSRESTFUL <WsRestFul>
Nome Tipo Descrição Obrigatório
cVerb POST, PUT, GET ou DELETE X
cId Caracter ID para diferenciar e possibilitar a criação de métodos que utilizam verbos http repetidos
cDescription Caracter Descrição do método REST X
cSintax Caracter Sintaxe HTTP da chamada REST. Esta informação é utilizada apenas para documentação do REST.
cPath Caracter Definição do endpoint que irá acionar aquele método.
*Pode conter agrupamento, o nome da classe e os pathparms. (A partir da release 12.1.23 da lib, em jan./2019).
cTTalkVersion Caracter Valor “v1” para sinalizar que o método utiliza o padrão de mensagem de erro do TTALK.
QueryParms Indica os parâmetros, separados por vírgulas, que este método receberá via QueryString.
O parâmetros indicados aqui devem ser declarados como WSDATA.
PathParms Indica os parâmetros, separados por vírgulas, que este método receberá via path, ou seja, como parte da URL.
HeaderParms Indica os parâmetros, separados por vírgulas, que este método receberá via Header na requisição HTTP.
WsRestFul Caracter Indica o nome da classe, do serviço, que o método atual pertence. X
Agora vamos começar a definir os métodos logo abaixo do código anterior:
/*/-----------------------------------------------------------
{Protheus.doc} GET
Get de Exemplo - Método utilizado para consultas
Uso: WsRstExp
@sample
//GET / WsRstExp
@author Paulo Henrique Corrêa Cardoso.
@since 21/07/2020
@version 1.0
-------------------------------------------------------------/*/
WSMETHOD GET WSRECEIVE param1, param2 WSSERVICE WsRstExp
   Local lRet      := .T.         // Recebe o Retorno 
   Local oJsonRet  := NIL         // Recebe o JSON de Saida
   
    /*
   
  Trecho com a sua codificação
   
   */
  
   // Monta Objeto JSON de retorno
   oJsonRet := NIL
   oJsonRet := JsonObject():new()

   oJsonRet['Propriedade1'] := EncodeUTF8("Retorno 1", "cp1252") 
   oJsonRet['Propriedade2'] := 10 
   oJsonRet['Propriedade3'] := .T.
  
   // Devolve o retorno para o Rest
   ::SetResponse(oJsonRet:toJSON())
   
Return lRet


/*/-----------------------------------------------------------
{Protheus.doc} POST
Post de Exemplo - Método utilizado para inclusões
Uso: WsRstExp
@sample
//POST/ WsRstExp
@author Paulo Henrique Corrêa Cardoso.
@since 21/07/2020
@version 1.0
-------------------------------------------------------------/*/
WSMETHOD POST WSRECEIVE nullparam WSSERVICE WsRstExp
   Local lRet      := .T.         // Recebe o Retorno 
   Local cBody	   := ''          // Recebe o conteudo do Rest
   Local oJson     := NIL         // Recebe o JSON de Entrada
   Local oJsonRet  := NIL         // Recebe o JSON de Saida
   
   // Pega o conteudo JSON da transação Rest
   cBody := ::GetContent()
   ::SetContentType("application/json")

   oJson := JsonObject():new()
   oJson:fromJson(cBody)
  
   /*
   
  Trecho com a sua codificação
   
   */
  
   // Monta Objeto JSON de retorno
   oJsonRet := NIL
   oJsonRet := JsonObject():new()

   oJsonRet['Propriedade1'] := EncodeUTF8("Retorno 1", "cp1252") 
   oJsonRet['Propriedade2'] := 10 
   oJsonRet['Propriedade3'] := .T.
  
   // Devolve o retorno para o Rest
   ::SetResponse(oJsonRet:toJSON())
        
   FreeObj(oJsonRet)
   FreeObj(oJson)

Return lRet

/*/-----------------------------------------------------------
{Protheus.doc} PUT
PUT de Exemplo - Método utilizado para Alterações
Uso: WsRstExp
@sample
//PUT / WsRstExp
@author Paulo Henrique Corrêa Cardoso.
@since 21/07/2020
@version 1.0
-------------------------------------------------------------/*/
WSMETHOD PUT WSRECEIVE param1, param2 WSSERVICE WsRstExp
   Local lRet      := .T.         // Recebe o Retorno 
   Local cBody	   := ''          // Recebe o conteudo do Rest
   Local oJson     := NIL         // Recebe o JSON de Entrada
   Local oJsonRet  := NIL         // Recebe o JSON de Saida
   
   // Pega o conteudo JSON da transação Rest
   cBody := ::GetContent()
   ::SetContentType("application/json")

   oJson := JsonObject():new()
   oJson:fromJson(cBody)
  
   /*
   
  Trecho com a sua codificação
   
   */
  
   // Monta Objeto JSON de retorno
   oJsonRet := NIL
   oJsonRet := JsonObject():new()

   oJsonRet['Propriedade1'] := EncodeUTF8("Retorno 1", "cp1252") 
   oJsonRet['Propriedade2'] := 10 
   oJsonRet['Propriedade3'] := .T.
  
   // Devolve o retorno para o Rest
   ::SetResponse(oJsonRet:toJSON())
        
   FreeObj(oJsonRet)
   FreeObj(oJson)

Return lRet

/*/-----------------------------------------------------------
{Protheus.doc} DELETE 
DELETE de Exemplo - Método utilizado para exclusões
Uso: WsRstExp
@sample
//DELETE  / WsRstExp
@author Paulo Henrique Corrêa Cardoso.
@since 21/07/2020
@version 1.0
-------------------------------------------------------------/*/
WSMETHOD DELETE WSRECEIVE param1, param2 WSSERVICE WsRstExp
   Local lRet      := .T.         // Recebe o Retorno 
   Local cBody	   := ''          // Recebe o conteudo do Rest
   Local oJson     := NIL         // Recebe o JSON de Entrada
   Local oJsonRet  := NIL         // Recebe o JSON de Saida
   
   // Pega o conteudo JSON da transação Rest
   cBody := ::GetContent()
   ::SetContentType("application/json")

   oJson := JsonObject():new()
   oJson:fromJson(cBody)
  
   /*
   
  Trecho com a sua codificação
   
   */
  
   // Monta Objeto JSON de retorno
   oJsonRet := NIL
   oJsonRet := JsonObject():new()

   oJsonRet['Propriedade1'] := EncodeUTF8("Retorno 1", "cp1252") 
   oJsonRet['Propriedade2'] := 10 
   oJsonRet['Propriedade3'] := .T.
  
   // Devolve o retorno para o Rest
   ::SetResponse(oJsonRet:toJSON())
        
   FreeObj(oJsonRet)
   FreeObj(oJson)
 
Return lRet
Nos exemplos acima utilizei a Classe JsonObject para tratar dados do tipo JSON, com a mesma é possivel transformar o JSON para objeto e vice-versa.

Muito importante

Para realizar os retornos para o Webservice Rest, temos dois métodos que precisamos utilizar. Em caso de sucesso e vamos devolver um JSON com conteúdo, utilizamos o método ::SetResponse(“[JSON]”). Em caso de falha utilizamos o método SetRestFault([StatusErro]), EncodeUTF8(“[Mensagem de Erro]”, “cp1252”)). Observação : utilizo a função EncodeUTF8(“Texto”, “cp1252”), para suprimir problemas de acentuação ao utilizar o envio de textos pela WS Rest. Nos casos de falha podemos utilizar a tabela abaixo para definir o StatusErro:
Status HTTP Descrição
422 Exceções de negócio
400 Requisição Mal Formada
401 Requisição Requer Autenticação
403 Requisição Negada
404 Recurso não Encontrado
405 Método não Permitido
408 Tempo esgotado para a requisição
413 Requisição excede o tamanho máximo permitido
415 Tipo de mídia inválida (falta de informar o content-type correto, ver JSON)
429 Requisição excede a quantidade máxima de chamadas permitidas à API
500 Erro de servidor
  Vou deixar aqui a documentação da TOTVS com mais algumas informações importantes sobre toda a estrutura do REST. https://tdn.totvs.com/display/framework/REST+ADVPL https://tdn.totvs.com/pages/viewpage.action?pageId=75269436   É isso pessoal. Espero que ajude muito vocês.  

Até a próxima!!!

porPaulo Henrique Corrêa Cardoso

Criando tabelas – Microsoft SQL Server

Fala pessoal, tudo bem ?

Hoje eu vou passar um conteúdo para quem esta começando a aprender a linguagem SQL. Vamos aprender a criar tabelas, colunas e chaves, utilizando o banco de dados Microsoft SQL Server.

Vamos aprender comandos de uma parte da linguagem SQL chamada de DDL (Data Definition Language), ou seja, linguagem de definição de dados.

Mas antes de começarmos a criação da nossa tabela, vamos primeiro aprender um pouco sobre a tipagem de dados utilizados na maioria dos bancos.

Os bancos tem alguns tipos de dados específicos, por isso vou citar os principais e deixar um link com todos os tipos disponíveis para o Microsoft SQL Server.

Tipagem de Dados

int – O tipo de dados int é o tipo de dados inteiros, seu intervalo de dados vai de -2.147.483.648 até 2.147.483.647 e ocupa 4 bytes de armazenamento.

decimal – O tipo decimal guarda dados que possuem casas decimais de precisão, ou seja definimos o tamanho exato de quantidade de casas que o numero poderá ter entre números inteiros e casas decimais. Por exemplo, o número 123,45 tem uma precisão de 5 e uma escala de 2, sua definição fica da seguinte forma decimal(5,2).

A precisão máxima padrão do tipo decimal é 38 e o mesmo tem uma ocupação de armazenamento representado pela tabela abaixo:

Precisão Bytes de armazenamento
1 – 9 5
10–19 9
20–28 13
29-38 17

float – O tipo float é um tipo dados numéricos aproximados para uso com dados numéricos de ponto flutuante. Como são aproximados nem todos os valores no intervalo de tipo de dados podem ser representados de maneira exata.

Sua definição fica da seguinte forma : float(n) em que n é o número de bits usado para armazenar a mantissa do número float na notação científica e, portanto, exige a precisão e o tamanho do armazenamento. Se n for especificado, ele precisará ser um valor entre 1 e 53. O valor padrão de n é 53.

O armazenamento é representado pela tabela abaixo:

Valor de n Precisão Bytes de armazenamento
1-24 7 dígitos 4 bytes
25-53 15 dígitos 8 bytes

datetime – Define uma data combinada com uma hora do dia que inclui frações de segundos e se baseia em um período de 24 horas. Exemplo: 2020-07-21 20:32:00.520

Intervalo de datas Janeiro 1, 1753, a dezembro 31, 9999
Intervalo de horas 00:00:00 a 23:59:59.997

Seu tamanho é de 8 bytes.

char – Tipo de dados de caractere de tamanho fixo, ou seja, o valor que será armazenado possuirá o tamanho definido na declaração deste tipo.

Exemplo, ao definir uma coluna da tabela como char(10) e realizar o input da informação ‘ABC’, a mesma será gravada como ‘ABC ‘.

varchar – Tipo de dados de caractere de tamanho variável,ou seja, o valor que será armazenado possuirá o tamanho variável no memento da gravação, sempre respeitando o tamanho limite definido na declaração do tipo.

Exemplo, ao definir uma coluna da tabela como varchar(10) e realizar o input da informação ‘ABC’, a mesma será gravada como ‘ABC’.

bit – É um tipo dado inteiro que pode aceitar um valor 1, 0 ou NULL. Os valores de cadeia de caracteres TRUE e FALSE podem ser convertidos em valores bit: TRUE é convertido em 1 e FALSE é convertido em 0.

Para mais tipos de dados aceitos pelo Microsoft SQL Server, consulte Aqui

Bom, agora que falamos sobre os tipos de dados mais comuns, podemos a começar entrar na definição de comandos para criar uma tabela dentro do banco de dados.

Criando uma tabela.

Primeiramente vamos utilizar o comando CREATE TABLE para criar a tabela, definindo as colunas da mesma.

Veja o exemplo:

CREATE TABLE Produto (
  IdProduto   INT           IDENTITY(1,1) NOT NULL,
  DescProduto VARCHAR(60)                 NOT NULL,
  Preco       DECIMAL(14,2)               NOT NULL,
  Peso        FLOAT                       NOT NULL,
  Ativo       BIT                         NOT NULL,
  IdCategoria INT                         NOT NULL,
  DataCriacao DATETIME                    NOT NULL
)

Veja que ao definir as colunas, foram utilizados exemplos de alguns tipos explicados anteriormente.

A primeira coluna definida, possui duas informações diferentes das demais. A propriedade IDENTITY(1,1) define que a coluna será auto-incrementada, iniciando no valor 1 e acrecendo 1 a cada novo registro.

Lembrando que a propriedade IDENTITY é opcional.

Temos também a propriedade NOT NULL, que define que a coluna não aceitará valores nulos, podemos também utilizar a propriedade NULL para permitindo o caso contrario.

Ao executar esses comandos no Microsoft SQL Server teremos nossa primeira tabela criada.

Alterando uma tabela

Mas e se eu precisar adicionar ou alterar uma coluno dentro de uma tabela existente, como posso fazer?

Para isso entramos nos comandos de alteração de tabela, o ALTER TABLE.

O comando ALTER TABLE tem diversas propriedades, vamos abordar algumas principais que você vai utilizar no dia a dia.

A Primeira é o comanda para adicionar uma nova coluna na tabela. Para isso utilizaremos o comando ADD.

Veja o exemplo:

ALTER TABLE Produto
ADD CodBarras CHAR(13)    NULL,
    Cor       VARCHAR(10) NULL

Neste exemplo adicionamos duas novas colunas em nossa tabela, utilizando os comandos ALTER TABLE + o comando ADD.

Se precisarmos modificar uma coluna existente, utilizaremos o comando ALTER COLUMN, da seguinte forma:

ALTER TABLE Produto
ALTER COLUMN Cor VARCHAR(20) NOT NULL

Veja que neste exemplo alteramos o tamanho e a propriedade NOT NULL da coluna Cor, utilizando os comandos ALTER TABLE + ALTER COLUMN.

Caso precisemos excluir uma coluna, vamos utilizar o comando DROP COLUMN, da seguinte forma:

ALTER TABLE Produto
DROP COLUMN Cor

Veja que a coluna foi excluída com esse comando.

Chaves da tabela.

Agora que aprendemos os comandos básicos para criação de uma tabela, vamos entender um pouco sobre chaves da tabela.

Existem dois tipos de chaves que utilizamos em uma tabela. A Primary Key (chave primaria) e as Foreign Key’s (chaves estrangeiras).

Uma tabela pode ter apenas uma Primary Key, e seu valor não poderá se repetir entre os registros.

A criação dessa chave pode ser feita no momento da criação to campo na tabela, ou posteriormente com um comando especifico.

Veja o comando para adicionar a Primary Key posteriormente a criação da tabela:

ALTER TABLE Produto
ADD CONSTRAINT PK_Produto_IdProduto PRIMARY KEY CLUSTERED (IdProduto)

Onde “PK_Produto_IdProduto” é o nome que definimos pra nossa Primary Key e IdProduto é o campo que fará parte da chave.

Já as Foreign Key’s são chaves de relacionamento com outras tabelas, e servem para garantir a integridade de registros entre as mesmas.

Para esse exemplo vou criar uma tabela de Categoria para a classificação dos Produtos.

CREATE TABLE Categoria(
  IdCategoria  INT          IDENTITY(1,1) NOT NULL,
  Descricao    VARCHAR(100)               NOT NULL, 
  CONSTRAINT PK_Categoria_IdCategoria    PRIMARY KEY CLUSTERED (IdCategoria)
)

Veja que nesse exemplo eu criei a Primary Key no momento da criação da tabela.

Agora vamos criar uma Foreign Key na tabela de Produtos, relacionando o campo IdCatetoria da tabela Produto com o da tabela Categoria.

ALTER TABLE Produto
ADD CONSTRAINT FK_ProdutoCategoria
FOREIGN KEY (IdCategoria) REFERENCES Categoria(IdCategoria)

Onde “FK_ProdutoCategoria” é o nome da Foreign Key , “(IdCatetoria)” é o campo chave de relacionamento da tabela Produto e “Categoria(IdCategoria)” é a referencia com a tabela de Categoria e com o campo Primary Key da mesma.

Dessa forma quando tentar inserir um registro na tabela de Produtos com uma categoria que não exista o banco de dados não permitira a inclusão do registro, da mesma forma que não será permitido excluir uma categoria que esteja vinculada com algum produto.

Excluindo uma tabela.

Para deletar uma tabela, temos o comando DROP TABLE, que deve ser utilizado da seguinte forma:

DROP TABLE Categoria

Bom pessoal, esse foi o conteúdo do Post de hoje.

Espero que ajude muito vocês!!!

Qualquer dúvida, deixe nos comentários.

Até a próxima!!!

porPaulo Henrique Corrêa Cardoso

Lógica de programação, um conhecimento para a vida.

Vejo muitas pessoas que estão tentando começar trabalhar na área de análise e desenvolvimento de software, sempre com muita dificuldade em escolher a melhor linguagem de programação, ou fazendo diversos cursos de desenvolvimento, mas nunca consegue evoluir na carreira.

Se você acredita que um curso de programação, ou as vezes até mesmo a faculdade de tecnologia vai te ensinar a programar, sinto dizer que será uma decepção… Decepção que vi nos olhos de diversos colegas que fizeram faculdade comigo.

Antes de mais nada, quero te dizer que o principal conhecimento da área de programação não é a linguagem de programação que você vai utilizar…
A principal skill dessa louca profissão é uma palavrinha de 6 letras…”Lógica”.

A lógica é a base pra qualquer linguagem de programação, não importa qual seja, se você tiver o seu raciocínio lógico aguçado, você será capaz de desenvolver em qualquer linguagem de programação.

Muito além disso, a lógica aguçada vai te ajudar em todas as áreas cognitivas da sua vida.

Na minha época de faculdade, vi diversos professores tentando introduzir a programação na cabeça dos alunos, com uma linguagem chamada Portugol, que nada mais é que uma linguagem de programação em português.

Só que muitos desses alunos não conseguiam pensar de forma estruturado o suficiente para conseguirem escrever uma condições básicas para efetuar as tarefas solicitadas. Isso tudo porque faltava o principal para o desenvolvimento, que é a lógica.

O melhor caminho pra aprender a lógica computacional, no meu ponto de vista, é quebrar ao máximo uma tarefa em pequenas sub-tarefas, de forma muito detalhada e bem compreensível.

Vou usar um exemplo bem simples que tive em minhas aulas de lógica na minha época de meu curso técnico.

Como trocar um pneu de um carro.

Você esta em uma estrada e sente o que o pneu do seu veículo furou, o que fazer?

1 – Ligue a seta para encostar na via.

2 – Vire a direção, sentido ao local que você quer estacionar, de uma forma suave.

3 – Vá parando o veículo aos poucos.

4 – Quando o veículo estiver totalmente parado, puxe o freio de mão.

5 – Desligue o veículo.

6 – Saia do veículo e abra o porta-malas.

7 – Retire o triângulo de sinalização e as ferramentas do porta-malas.

8 – Posicione o triângulo de sinalização na pista, com uma boa distância do veículo.

9 – Volte até o veículo, pegue a chave de rodas e solte um parafuso de cada vez do pneu furado.

10 – Posicione o macaco no local correto para retirar o pneu…

Acho que já deu pra você ter ideia de como é, não é mesmo?
Um bom exercício para você que está começando a estudar lógica, é completar esse exemplo da forma mais detalhada possível.

Viu só, a ideia desse exercício é demonstrar cada passo, de forma estruturada.

Temos que imaginar que um computador interpreta exatamente cada comando que passamos de forma literal e não de forma abstrata.

Após fixarmos a ideia de sempre deixar as informações o mais detalhadas possíveis, começamos a empregar o conceitos de decisões.

Se e Senão

Uma das bases da lógica é o conceito de decisão. Esse conceito temos que utilizar pra tudo em nossa vida pois o mesmo nos fará pensar o que vai acontecer, cada caminho que vamos seguir e prever as possíveis situações.

Uma técnica muito boa para visualizarmos esse conceito é a utilização de fluxogramas.

Os fluxogramas, são representações de processos, através de gráficos esquemáticos, onde cada símbolo tem uma função.

Neste exemplo podemos ver a tomada de decisão para uma lâmpada que parou de funcionar.

Muito importante !!!

Antes de começarmos a desenvolver a lógica de qualquer coisa que queremos passar para um programa, ou até mesmo para algum processo que desejamos criar pra qualquer área da vida, é imprescindível entender o problema, todas as suas variáveis e condições de falha e sucesso.

Quando estiver com esse raciocino lógico bem fixado na sua cabeça, você vai perceber que a linguagem de programação vai entrar muito mais fácil no seu dia a dia!

A complexidade da lógica em um vídeo. (Para rir um pouco…)

Espero que esse conteúdo te ajude!!!
E lembre-se, a lógica antes da linguagem…
A lógica é tudo !!!

Até a próxima !!!

porPaulo Henrique Corrêa Cardoso

O que podemos esperar da tecnologia?

Já parou pra pensar o quanto a tecnologia evoluiu nessas últimas duas décadas ? Eu sou do início da década de 90 e peguei a grande parte da expansão tecnológica. Ainda sou de uma época onde se encontrava as fitas de máquina de escrever em bazares e as pesquisas eram feitas na Barsa.   Filmes eram alugados em locadora de VHS, e o orelhão estava em cada esquina. Tenho certeza de muitos que estão lendo esse texto não tem nem ideia do que são essas coisas, e se olharmos pra traz, esse passado é muito recente. O grande boom tecnológico começou nos meados dos anos 2000, onde se iniciou muito forte o conceito de globalização e as grandes empresas de tecnologias começaram a abrir mercado para o público geral. Uma década de grande evolução onde usávamos a boa e velha internet discada, lembrando que navegar de madrugada era mais barato. Época também que surgiu os incríveis pendrives e MP3s de 128mb. Hoje 20 anos depois já começamos entrar na era do compartilhamento e digitalização das informações, usando conexões de alta velocidade em equipamentos minúsculos como celulares, smartwatch’s, óculos de realidade virtual e computação em nuvem.    Se pensarmos no tempo da evolução humana, esses 20 anos passaram como segundos… Com isso, eu lanço a dúvida, o que será do nosso futuro tecnológico? Tenho certeza que cada vez mais as tecnologia estarão presente em todas as áreas, e as pessoas que não colocarem um “dedo nisso”, com toda certeza terão muita dificuldade. A tecnologia nos possibilitará avanços grandiosos na medicina, agricultura, comunicação, e até mesmo na conquista espacial, de forma que jamais imaginamos. Veremos a “internet das coisas” melhorarem muito nossas experiências com o meio em que vivemos, onde os equipamentos compartilharão informações sobre nossas preferências e nos ajudarão em diversas tarefas de nosso dia a dia. A inteligência artificial também será cada vez mais aprimorada e utilizada no meio corporativo e social. Meios de transporte inteligentes, autônomos e com energia limpa também terão um grande avanço e colheremos muitos frutos com isso. Com esses grandes avanços, temos que tomar cuidado para não regredirmos em nossas relações interpessoais e sempre lembrar que a tecnologia existe para nós ajudar a melhorar as coisas, mas não podemos jamais perder nossa essência humana. Mas com toda certeza teremos muitas conquistas nos próximos 10 anos e muitas mais nós próximos 20. Será que o pai da computação Alan Turing chegou a imaginar onde poderíamos chegar?

E você, como vê o futuro da tecnologia ?

porPaulo Henrique Corrêa Cardoso

Escopo de variáveis ADVPL

Fala pessoal, tudo bem ? Hoje tenho um assunto bem bacana pra quem trabalha com o desenvolvimento de sistemas Protheus® na linguagem ADVPL. Vamos entender melhor como funciona o escopo de variáveis e qual é o melhor para se utilizar em cada caso, isso impacta diretamente em performance e memória quando se trata de sistemas de grande escala. Primeiramente vou listar quais são os tipos de escopo e exemplificar cada um deles.

Global

Variáveis globais conseguem carregar suas informação para qualquer thread criada após a sua definição. São muito úteis quando precisamos definir ou recuperar valores em rotinas de processamento multi-thread. Devemos tomar cuidado ao utilizá-la, pois a mesma ficará disponível para qualquer execução iniciada após sua definição, podendo acarretar problemas de sobreposição caso concorra com mais de uma execução. No exemplo a seguir vamos definir duas variáveis globais que terão seus valores modificados por uma função executada em outra Thread, e na sequência recuperar seus valores na função atual.
User Function ExJobXPT()
  Local lRetJob := .F.

  // Tenta obter acesso exclusivo pra gravar a variável global
  While !( GlbLock() )
    Sleep(5)
  End While
  
  //Define e seta o valor nas variáveis globais
  PutGlbValue("lRetExec", lRetJob )
  PutGlbValue("cTexto", "Teste" )
  
  //Libera o acesso excluvivo a pilha de variáveis globais
  GlbUnlock()
  
  //Executa rotina em uma nova Thread 
  StartJob("U_ExecXPTO",GetEnvServer(),.T.)
  
  // Le os valores gravado pela função onde a váriavel global foi alterada.
  lRetJob  := GetGlbValue("lRetExec")
  If lRetJob
    Conount(GetGlbValue("cTexto"))
  Else
    Conount("Retornou Falso")
  EndIf
Return

Public

A variável Public e uma variável que fica valida em todo o escopo de execução do sistema ou seja do momento em que a mesma for criada até o momento que fizer a desconexão da sessão ativa ou destruição da mesma. É uma variável que temos que tomar cuidado ao utilizar, justamente pelo escopo abrangente que a mesma possui. A criação sem necessidade podo causar problemas de lentidão ou até mesmo problemas em tempo de execução do programa caso o mesmo não seja preparado para isso. A mesma pode ser utilizada para definir informações que serão utilizadas em diversas rotinas do sistema. Elas são equiparadas as Session’s de  outras linguagens. Alguns exemplos de variáveis públicas existentes são : cFilAnt, cEmpAnt, dDatabase, cModulo. No exemplo a seguir vamos ver um caso onde guardamos a hora inicial da chamada de uma função de menu, e verificamos se o tempo que demorou para entrar em outra função foi maior que 3 minutos.
// Função executada em um botão do menu do protheus
User Function ProcInic()
    Public cHoraIni := TIME()
    
    // Seu Código
Return


// Função executada em um outro botão do menu do protheus
User Function ProcFim()
    Local cDifTime := ElapTime ( cHoraIni, TIME() )
    If cDifTime > "00:03:00" 
        Alert("O tempo de execução entre a função inicial e final demorou mais de 3 minutos.")
    EndIf

Return

Static

As variáveis do tipo Static tem seu escopo definido dentro da execução de uma thread, ou seja, consegue ser acessado por qualquer função hierarquicamente acima ou abaixo do local onde foi declarada, normalmente as variáveis Static são declaradas logo após a definição das includes do fonte e podem ser utilizadas somente pelo programa fonte corrente. No exemplo abaixo, vamos incrementar a variável em cada nível de função chamada.
#Include "Protheus.ch"

Static nVar := 0

User Function Pai()
  nVar += 10
  conOut("Pai")
  conOut(nVar)
  Filho()
  
  // Muito importante limpar o valor da váriavel static ao concluir sua utilização
  nVar := 0
Return
 
Static Function Filho()
  nVar += 10
  conOut("Filho")
  conOut(nVar)
  Neto()
Return
 
Static Function Neto()
  nVar += 10
  conOut("Neto")
  conOut(nVar)
Return
Muito importante lembrar a necessidade de limpar a variável ao final de sua utilização, pois se as funções foram executadas novamente sem essa limpeza pode acarretar em valores errôneos.

Private

O escopo da variável Private tem sua definição valida para todas as funções hierarquicamente chamadas após a sua declaração, independente do programa fonte utilizado e a mesma se encerra ao final da execução da sua função de origem. Este tipo de escopo não necessita do identificador Private para ser criada, basta escrever o nome da variável não existente que em momento de execução o ADVPL cria como Private, isso pode ser um grande problema em caso de uma exceção, pois será muito difícil  encontrar onde a mesma foi criada. Vejo muitos analistas/programadores que não declaram as variáveis, isso além de deixar o código muito confuso pode causar problemas em tempo de execução e aumento de memória. No exemplo abaixo podemos ver que a variável cNome definida como Private dentro da função Filho() consegue ser acessada pela função Neto(), porém não consegue ser acessada pela função U_Pai().
User Function Pai()
  Filho() 
  If Type("cNome") == "C"
    conOut(cNome)
  Else
    conOut("Variável não definida")
  EndIf
Return
 
Static Function Filho()
  Private cNome := "Paulo"
  Neto()
  conOut("Filho")
  conOut(cNome)
Return
 
Static Function Neto()
  conOut("Neto")
  If Type("cNome") == "C"
    conOut(cNome)
  EndIf
Return

Local 

O escopo Local é o escopo de menor abrangência, ou seja, ele só funciona dentro da função onde a variável foi declarada, e é o escopo que devemos utilizar com mais frequência, pois terá o menor tempo de vida útil dentro da execução, consequentemente o menor custo de memória. No exemplo abaixo precisamos definir a variável local dentro da função onde queremos utilizar, note que a função Filho() não encontrará a variável cVarNome se a mesma não for declarada.
User Function Pai()
  Local cVarNome := "Paulo"
  conOut(cVarNome)
  Filho()
Return
Static Function Filho() 
  Local cVarNome := "Henrique"
  conOut(cVarNome)
Return
  
  Um detalhe muito importante do escopo de variáveis é que elas podem ser subsistidas por uma variável de escopo menor caso a mesma seja declarada dentro do local utilizado, por exemplo. Se eu possuir uma variável Public cXPTO com o valor “A” já declarado e dentro de uma novo fonte eu declarar uma variável Static cXPTO  com o valor “B” as duas variáveis existirão, mas o sistema vai priorizar o escopo mais baixo para a utilização no processamento corrente. Esta sequência hierárquica de escopo é : PublicStatic  > Private > Local .  O escopo Global não entra nessa hierarquia pois o mesmo é definido e acessado de forma diferente dos outros.   É isso pessoal, espero que ajude muito vocês e se tiveram alguma dúvida só deixar nos comentários.  

Até a próxima !!! 

 
porPaulo Henrique Corrêa Cardoso

Como se concentrar durante o período de trabalho

Para você que tem dificuldade de concentração no momento de trabalho, assim como eu, vou dar algumas dicas que vão ajudar muito na sua capacidade de concentração, criativa e cognitiva.

Veja essas dicas:

Escute uma playlist que te deixe concentrado.

No meu caso, sempre que preciso fazer tarefas onde preciso de foco total, eu coloco uma playlist de Rock que eu mesmo montei. Dessa forma tiro totalmente o som externo, as conversas  e distrações que tiram meu foco.

Pode ser o tipo de música que você preferir, no meu caso foi o bom e velho Rock And Roll .

Vou deixar minha playlist do Spotify aqui caso alguém queira fazer as “Pedras rolarem”.

Open in Spotify

Defina uma agenda em sua rotina.

Uma dica muito importante, para você que acaba se perdendo no tempo, ou se aguem te chama a todo momento, é utilizar uma agenda para organizar suas tarefas.
Pode ser um agenda de papel (raiz) ou algo mais moderno como utilizar a agenda do Google Calendar ou qualquer agenda virtual, o importante é se organizar.

Organize suas tarefas e processos.

Tenha uma forma de organizar a ordem das suas tarefas, assim você não esquece de nenhuma e vai ter uma produtividade muito maior.

Existem diversas ferramentas e metodologias para isso.

Uma metodologia muito útil para isso é o Scrum que foi desenvolvido para gerenciar projetos, organizar tarefas e agilizar processos. Para mim ele é muito mais que uma ferramenta de trabalho e pode ser empregado em todas as áreas da sua vida.

Uma ferramenta bem bacana que uso para organizar minhas tarefas é o Trello. Essa ferramenta te ajuda a organizar suas tarefas em card’s e dividi-las em etapas de processo.

Faça pausas durante o trabalho.

É muito importante fazer pausas durante o expediente. Nenhuma mente é produtiva 100% do tempo, e sem as pausas nossa mente e nosso corpo pode chegar a uma exaustão e comprometer a qualidade do seu trabalho.

Então, faça pausa para tomar um café, distrair a cabeça ou até mesmo bater um papo com algum colega de trabalho.

É isso mesmo, as vezes desviar o foco te ajuda a ter foco no momento correto !!!

 

Essas são as minhas dicas para que seu trabalho seja mais produtivo e com uma melhor qualidade.

porPaulo Henrique Corrêa Cardoso

Script para reorganizar/recriar índices no Microsoft SQL Server

Muitas vezes sentimos uma performance terrível em nosso banco de dados.

Um dos fatores que pode fazer isso acontecer é a defasagem dos índices das tabelas de nosso banco.

Isso acontece devido a  grande quantidade de manipulações dos dados, principalmente com os comandos Insert e Delete.

Para isso podemos criar um script para reorganizar, e dependendo dos casos recriar os índices do nosso SQL Server…
Essas ações melhoram o desempenho do banco.

Vou explicar os passos para montar esse Script que vai te ajudar muito.

Primeiramente, vamos criar algumas variáveis de controle que serão utilizadas no momento da leitura dos índices…

DECLARE @tableName nvarchar(500) 
DECLARE @indexName nvarchar(500) 
DECLARE @percentFragment decimal(11,2)
DECLARE @page_count int

 

Na sequência vamos definir nosso Cursor, que servirá para armazenar a lista de índices que iremos realizar a manutenção.

Dentro da criação do cursor, escrevemos um comando Select que vai cruzar dados entre a tabela de status dos índices (sys.dm_db_index_physical_stats), a tebela de tabelas(sys.tables), a tabela de Schemas(sys.schemas) e a tabela de Índices(sys.indexes).

Definimos um parâmetro de busca de fragmentação onde o % de fragmentação for maior que 5% e a quantidade de páginas do índice for maior que 10.

Com isso começamos a pegar os índices que já começam a apresentar lentidão nas consultas…

DECLARE FragmentedTableList cursor for 
SELECT  dbtables.[name] AS 'Table',
    dbindexes.[name] AS 'Index',
    indexstats.avg_fragmentation_in_percent,
    indexstats.page_count
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
INNER JOIN sys.tables dbtables 
  ON dbtables.[object_id] = indexstats.[object_id]
INNER JOIN sys.schemas dbschemas 
  ON dbtables.[schema_id] = dbschemas.[schema_id]
INNER JOIN sys.indexes dbindexes 
  ON dbindexes.[object_id] = indexstats.[object_id]
  AND indexstats.index_id = dbindexes.index_id
  AND dbindexes.[name] IS NOT NULL
WHERE indexstats.database_id = DB_ID()
    AND indexstats.avg_fragmentation_in_percent > 05
    AND indexstats.page_count  > 10 
ORDER BY indexstats.page_count DESC, indexstats.avg_fragmentation_in_percent DESC
 
OPEN FragmentedTableList

 

Por último, vamos abri o cursor, fazer a leitura dos índices e executar as devidas manutenção:

Quando o percentual de fragmentação estiver entre 5% e 30%, vamos realizar o reorganize do índice, ou seja, vamos reorganizar este índice.

Agora, se o percentual for maior que 30% vamos realizar o rebuild do índice, ou seja, realizar a reconstrução do mesmo, pois a defasagem do mesmo já esta bem critica.

FETCH NEXT FROM FragmentedTableList  
INTO @tableName, @indexName, @percentFragment, @page_count
 
WHILE @@FETCH_STATUS = 0 
  BEGIN 
    PRINT 'Processando ' + @indexName + ' na tabela ' + @tableName + ' com ' + CAST(@percentFragment AS NVARCHAR(50)) + '% fragmentado' 
       
    IF(@percentFragment BETWEEN 05 AND 30) 
      BEGIN 
        
        EXEC( 'ALTER INDEX ' +  @indexName + ' ON ' + @tableName + ' REORGANIZE;') 
        PRINT 'Concluindo a reorganização do índice ' + @indexName + ' da tabela ' + @tableName 
      END 
    ELSE IF (@percentFragment > 30)
      BEGIN 
        EXEC( 'ALTER INDEX ' +  @indexName + ' ON ' + @tableName + ' REBUILD; ') 
        PRINT 'Concluindo a recriação do índice ' + @indexName + 'da tabela ' + @tableName 
    END  
    FETCH NEXT FROM FragmentedTableList  
    INTO @tableName, @indexName, @percentFragment,@page_count
  END 
CLOSE FragmentedTableList 
DEALLOCATE FragmentedTableList

 

Agora vejam o exemplo completo do nosso script:

DECLARE @tableName nvarchar(500) 
DECLARE @indexName nvarchar(500) 
DECLARE @percentFragment decimal(11,2) 
DECLARE @page_count int
 
DECLARE FragmentedTableList cursor for 
SELECT  dbtables.[name] AS 'Table',
    dbindexes.[name] AS 'Index',
    indexstats.avg_fragmentation_in_percent,
    indexstats.page_count
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
INNER JOIN sys.tables dbtables 
  ON dbtables.[object_id] = indexstats.[object_id]
INNER JOIN sys.schemas dbschemas 
  ON dbtables.[schema_id] = dbschemas.[schema_id]
INNER JOIN sys.indexes dbindexes 
  ON dbindexes.[object_id] = indexstats.[object_id]
  AND indexstats.index_id = dbindexes.index_id
  AND dbindexes.[name] IS NOT NULL
WHERE indexstats.database_id = DB_ID()
    AND indexstats.avg_fragmentation_in_percent > 05
    AND indexstats.page_count  > 10 
ORDER BY indexstats.page_count DESC, indexstats.avg_fragmentation_in_percent DESC
 
OPEN FragmentedTableList 
FETCH NEXT FROM FragmentedTableList  
INTO @tableName, @indexName, @percentFragment, @page_count
 
WHILE @@FETCH_STATUS = 0 
  BEGIN 
    PRINT 'Processando ' + @indexName + ' na tabela ' + @tableName + ' com ' + CAST(@percentFragment AS NVARCHAR(50)) + '% fragmentado' 
       
    IF(@percentFragment BETWEEN 05 AND 30) 
      BEGIN 
        
        EXEC( 'ALTER INDEX ' +  @indexName + ' ON ' + @tableName + ' REORGANIZE;') 
        PRINT 'Concluindo a reorganização do índice ' + @indexName + ' da tabela ' + @tableName 
      END 
    ELSE IF (@percentFragment > 30)
      BEGIN 
        EXEC( 'ALTER INDEX ' +  @indexName + ' ON ' + @tableName + ' REBUILD; ') 
        PRINT 'Concluindo a recriação do índice ' + @indexName + 'da tabela ' + @tableName 
    END  
    FETCH NEXT FROM FragmentedTableList  
    INTO @tableName, @indexName, @percentFragment,@page_count
  END 
CLOSE FragmentedTableList 
DEALLOCATE FragmentedTableList

 

Agora o mesmo pode ser executado periodicamente, ajudando a melhorar a performance do banco de dados.

Espero que gostem!!!

Até a próxima !!!