sábado, 13 de maio de 2017

Commit encerra uso do Cursor

Olá!

Ao ser necessário realizar a persistência de vários registros no banco de dados (DB) é uma boa prática realizar Commit (salvar alterações que são feitas no DB) após uma quantidade registros processados.

Pois, com essa prática caso ocorra algum erro durante a execução do programa é possível realizar o restart da aplicação a partir do último registro processado, assim ganhando processamento pelo fato de não ter que processar todos os registros novamente.

Exemplo com o processamento de um arquivo:
Ler o arquivo com as informações dos clientes e atualizar o DB com esses dados. Considerando que o arquivo tenha 1 milhão de registros, o Commit deve ser feito a cada 1.000 registros atualizados.

Para esse exemplo o fluxo de processamento é bem simples, sendo criado uma estrutura de repetição para ler o arquivo de entrada e atualizar o DB, e a cada 1.000 registros atualizados executar o Commit para salvar os dados dos cliente já atualizados.

Nada de mais, né? Então, vamos para outro exemplo.

Exemplo de processamento para vários registros de uma tabela - cursor:
Realizar a leitura de todos os saldos da tabela de cliente (cliente.saldos), e adicionar R$ 100 de limite de crédito (cliente.limite_credito) onde o saldo do cliente for maior que R$ 500. De modo que a cada 1.000 clientes atualizados realizar Commit no DB.

Nesse exemplo o fluxo de processamento é semelhante ao do primeiro exemplo, pois também é necessário uma estrutura de repetição para ler o saldo de cada cliente armazenado na tabela, e se esse saldo for superior a R$ 500 adicionar R$ 100 ao limite de crédito do cliente, e a cada 1.000 clientes atualizados realizar Commit para salvar os clientes já atualizados.

Entretanto, se criado o seguinte fluxo:
...
     Abrir cursor
     Ler cursor
     Loop até fim de cursor
         Se saldo cliente > 500 adicionar 100 ao limite de crédito
         Se quantidade de clientes atualizados > que 1.000 fazer Commit
         Ler cursor para ver saldo do próximo cliente
...

Será reportado erro ao tentar ler o saldo do próximo cliente após ter executado a instrução Commit dos clientes já atualizados.

Pois, ao executar o comando Commit o cursor é automaticamente fechado. Assim, quando o programa tentar ler o saldo do próximo cliente será retornado erro pela tentativa de ler o cursor fechado.

Umas das possíveis soluções é: abrir o cursor, realizar a leitura de todos os clientes e armazenar em memória (tabela interna Cobol) aqueles que satisfação a condição definida, fechar o cursor. Agora, com os clientes que estão em memória fazer a persistência dos novos dados na tabela e a cada 1.000 atualizações fazer Commit.

Note que essa é somente uma das várias soluções, pois dependendo da quantidade de registros não será possível armazenar eles em memoria, de modo a ter que usar outra forma de processamento para realizar a aplicação.

Enfim, tenha em mente que após a execução da instrução Commit o cursor que esteja aberto é automaticamente encerrado, desse modo impossibilitando a leitura do próximo registro.


Consultar a relação de Termos e Abreviaturas acesse aqui.

FELIPE BARBOSA FERREIRA
Até o próximo post!

domingo, 23 de abril de 2017

Mostrar o valor do índex de uma tabela

Olá!

Uma das estruturas básicas para a declaração de uma tabela no COBOL, é:

           03 NOME-TABELA OCCURS  0 TO QUANTIDADE-REGISTROS TIMES
                          DEPENDING ON QUANTIDADE-REGISTROS-INSERIDOS.
               05 VAR-1                 PICTURE
               05 VAR-2                 PICTURE
               05 VAR-n                 PICTURE

Entretanto, dependendo da aplicação a ser realizada, pode ser necessário trabalhar com o índex da tabela, desde modo a declaração da tabela deve ser feita conforme:

           03 NOME-TABELA OCCURS  0 TO QUANTIDADE-REGISTROS TIMES
                      DEPENDING ON QUANTIDADE-REGISTROS-INSERIDOS
                        INDEXED BY NOME-INDEX.
               05 VAR-1                 PICTURE
               05 VAR-2                 PICTURE
               05 VAR-n                 PICTURE

O detalhe é que esse índex é para utilização de processamento lógico, o que quero dizer é: a variável índex da tabela, não é uma variável comum e requer um tratamento específico. Pois, por exemplo, os comandos: 

FELIPE BARBOSA FERREIRA - Erro ao usar o index da tabela em comandos
Erro com a variável índex da tabela

Retornam erro relativo ao uso ilegal dessa variável.

  • Note que se utilizado diretamente no comando Display é retornado erro. Então como mostrar o valor do índex da tabela?

Para exibir o valor dessa variável é necessário criar uma auxiliar numérica PIC 9(n) e atribuir o valor do índex para ela. E para realizar a movimentação do valor, deve ser usado o comando SET, veja:

           SET VAR-AUXILIAR TO NOME-INDEX.

Exemplo prático:
O comando Search é utilizado para realizar a pesquisa de um registro em uma tabela, e para usar esse comando é necessário realizar a declaração da tabela com o índex.

No programa de exemplo foi criado uma tabela para armazenar os alunos ganhadores de uma competição, sendo que a ordem de colocação do aluno é definida pela ordem de cadastrado na tabela, ou seja, o primeiro registro é equivalente ao ganhador do primeiro lugar da competição. Assim, com o uso do Search é possível apresentar a posição de um determinado aluno.

Então, quando o Search encontrar o aluno, o valor contido no índex da tabela é referente à posição do registro.
Veja abaixo as declarações básicas e comandos principais para o código de exemplo:
  • Declaração das variáveis:
      *
      * -- Quantidade de alunos
       77 GDA-QT-ALU                    PIC  9(004).
      *
      * -- Index para loop
       77 NDX                           PIC  9(001) VALUE ZEROS.
      *
      * -- Para ser usado no SEARCH
       77 MATRICULA-ALU                 PIC  9(004) VALUE ZEROS.
      *
      * -- Armazenar a posicao do aluno na premiacao da competicao
       77 POSICAO-PREMIACAO             PIC  9(004) VALUE ZEROS.
      *
      *----------------------------------------------------------------*
      * -- Tabela para armazenar os alunos ganhadores
      *----------------------------------------------------------------*
      *
      * -- Tabela ALUNO: Matricula - Nome - Idade
       01 TABELA-ALUNO-PREMIADOS.
           03 TAB-ALU OCCURS  0 TO 5 TIMES
                      DEPENDING ON GDA-QT-ALU
                        INDEXED BY NDX-TAB-ALU.
               05 TAB-ALU-MTC           PIC  9(004).
               05 TAB-ALU-NM            PIC  X(050).
               05 TAB-ALU-IDD           PIC  9(004).
      *
  • Comando Search
      * -- Realiza a pesquisa na tabela
           SEARCH TAB-ALU
      *        Quando nao encontrado
               AT END
                   SET POSICAO-PREMIACAO TO 9999
      *
      *        Quando encontrado
               WHEN TAB-ALU-MTC(NDX-TAB-ALU) EQUAL MATRICULA-ALU
                   SET POSICAO-PREMIACAO TO NDX-TAB-ALU
      *
           END-SEARCH.
      *
Note que quando o aluno é encontrado o valor do índex da tabela (NDX-TAB-ALU) é movimentado para a variável (POSICAO-PREMIACAO) por meio do comando SET, está variável é usada de forma auxiliar para exibir o valor contido no índex da tabela.
  • Mostrar o valor do índex da tabela, e demais dados do aluno
      * -- Mostrar os dados do aluno premiado
      *
           IF POSICAO-PREMIACAO EQUAL 9999
               DISPLAY 'Não foi premiado o aluno com matrícula: ' 
                        MATRICULA-ALU
           ELSE
               DISPLAY 'Posição ' POSICAO-PREMIACAO ' - '
                        TAB-ALU-NM(POSICAO-PREMIACAO)
           END-IF.

Resposta da execução do programa para o exemplo:
FELIPE BARBOSA FERREIRA - Resposta programa exemplo mostrar valor do index da tabela
Resposta da execução do código de exemplo







a
Enfim, quando a aplicação requer a utilização do índex da tabela, tenha cuidado e atenção com os comandos que serão utilizados para manipular o valor dessa variável.

Para Ctrl + C do código acesse aqui.
Consultar a relação de Termos e Abreviaturas acesse aqui.
FELIPE BARBOSA FERREIRA

Até o próximo post!

domingo, 9 de abril de 2017

PICTURE SV9(n) - Números após a vírgula

Olá!

Ao trabalhar com variados cálculos há o momento que ocorre a necessidade de utilizar/manipular somente os valores que estão após a vírgula. Exemplo, verificar se o resultado de um cálculo vai gerar um número inteiro ou não, algo simples que pode ser feito de diversas formas.

E uma das maneiras de manipular esses valores, é realizar a definição de um item de grupo composto de duas variáveis, uma para armazenar valores inteiros e a outra para os valores após a vírgula. Ou seja, se o resultado de um cálculo está na variável:

       77  RESULTADO-CALCULO            PIC S9(005)V9(02) VALUE ZEROS.

Temos que realizar a definição de um item de grupo, conforme:

       01  RESULTADO.
           03 RESULTADO-CALC-PARTE-1    PIC S9(005) VALUE ZEROS.
           03 RESULTADO-CALC-PARTE-2    PIC  9(002) VALUE ZEROS.

Assim, se o valor de RESULTADO-CALCULO = 123,45 for movimentado para RESULTADO, respectivamente o valor de cada parte é:
RESULTADO-CALC-PARTE-1 = 123
RESULTADO-CALC-PARTE-2 = 45

Ok, o valor após a vírgula está separado e pronto para ser manipulado, é até um processo bem simples. Entretanto, tendo o objetivo de trabalhar especificamente com os números após a vírgula, este processo de criar um item de grupo não é o melhor.
Pois, veja a quantidade de passos realizados para chegar até o ponto do valor separado.
  1. Criar uma variável para armazenar o valor
  2. Criar um item de grupo para separar o valor em duas partes
  3. Atribuir valor a variável
  4. Movimentar o valor da variável para o item de grupo
Como melhorar?


  • PIC SV9(n)
A picture SV9(n) é exatamente para armazenar somente os números após a vírgula. Assim, valores decimais atribuídos a uma variável declarada com está definição terá o valor inteiro desprezado e considerado somente os números após a vírgula.

Exemplo:
       77  RESULTADO-CALCULO            PIC SV9(002) VALUE ZEROS.
      *
      * -- Divisao de 15 / 4 = 3,75
           DIVIDE 15
               BY 4
           GIVING RESULTADO-CALCULO
           END-DIVIDE

O valor da resposta da divisão acima é atribuído a variável RESULTADO-CALCULO, mas note que a declaração dessa variável é com SV9(002), deste modo é desprezado a parte inteira da resposta da divisão e somente guardado os valores após a vírgula, assim o valor final de RESULTADO-CALCULO = 75.

Para mais exemplos veja o código do programa a seguir:
(no final do post há o link para ver o código completo).

  • Declaração das variáveis:
      *
      *----------------------------------------------------------------*
       LOCAL-STORAGE                    SECTION.
      *----------------------------------------------------------------*
      *
      * -- Armazenar o resultado da operacao matematica
       77  RESULTADO                    PIC S9(004)V9(04) VALUE ZEROS.
      *
      * -- Item de grupo para separar o valor do resultado
       01  TESTE.
           03 TESTE-PARTE-1             PIC S9(004) VALUE ZEROS.
           03 TESTE-PARTE-2             PIC S9(004) VALUE ZEROS.
      *
      * -- Armazenar somente os numeros apos a virgula
       77  TESTE-SV9                    PIC SV9(04) VALUE ZEROS.

  • Comandos executados:
      *
           DISPLAY 'Valores iniciais das variáveis: '
           DISPLAY 'RESULTADO.: ' RESULTADO
           DISPLAY 'TESTE-SV9.: ' TESTE-SV9
           DISPLAY '.'
      *
      * -- Divisao de 9 / 4 = 2,25
           DIVIDE 9
               BY 4
           GIVING RESULTADO
           END-DIVIDE
      *
           DISPLAY 'Resultado de 9 / 4 = ' RESULTADO
           DISPLAY '.'
      *
      * -- Com item de grupo
           MOVE RESULTADO               TO TESTE
           DISPLAY 'O resultado separado no item de grupo'
           DISPLAY 'TESTE-PARTE-1.: ' TESTE-PARTE-1
           DISPLAY 'TESTE-PARTE-2.: ' TESTE-PARTE-2
           DISPLAY '.'.
      *
      * -- Somente os valores apos a virgula com SV9
           MOVE RESULTADO               TO TESTE-SV9
           DISPLAY 'Os números após a vírgula: ' TESTE-SV9
           DISPLAY '.'.
           DISPLAY '.'.
      *
      * -- Divisao de 15 / 4 = 3,75
           MOVE ZEROS                   TO TESTE-SV9
           DIVIDE 15
               BY 4
           GIVING TESTE-SV9
           END-DIVIDE
           DISPLAY 'Os números após a vírgula de 15 / 4 = ' TESTE-SV9
           DISPLAY '.'.
           DISPLAY '.'.

  • Resposta da execução do programa:
FELIPE BARBOSA FERREIRA
Resposta da execução do programa SV9(n)















Observe que com a utilização dessa Picture temos que ser precisos quanto a relação de casas numéricas a serem trabalhadas. Pois, veja que os zeros estão sendo posicionados a direita, fazendo que valor 25 ou 75 dos exemplos fique na unidade de milhar.

Com a utilização da PIC SV9(n) e tendo objetivo de trabalhar especificamente com os números após a vírgula, foi necessário de somente dois passos:

  1. Criar uma variável com a picture SV9(n)
  2. Realizar a operação para atribuir valor a variável
Note, que mesmo sendo exemplos de complexidade simples foi reduzido pela metade a quantidade de passos para obter o valor após a vírgula separado em uma variável.


Para Ctrl + C do código acesse aqui.
Consultar a relação de Termos e Abreviaturas acesse aqui.
FELIPE BARBOSA FERREIRA

Até o próximo post!

domingo, 26 de março de 2017

Variável host para coluna VARCHAR

Olá!

Um programa COBOL que persiste dados em uma tabela que contenha uma coluna do tipo varchar, deve estar preparado com uma variável host que seja um item de grupo que possua a quantidade de caracteres armazenada e o texto.

Tabela:
        CREATE TABLE INSCRICOES
           (
               CODIGO_PESSOA  INT         NOT NULL
           ,   NOME           CHAR(30)    NOT NULL
           ,   SOBRENOME      VARCHAR(50) WITH DEFAULT 'em branco'
           ,   DATA_INSCRICAO DATE        WITH DEFAULT GETDATE()
           ,   HORA_SAIDA     TIME
           ,   TS_CHEGADA     TIMESTAMP
           ,   VALOR          DOUBLE
           )

Então, para coluna SOBRENOME da tabela acima, a variável host pode ser implementada da seguinte forma:
           03  SOBRENOME-PESSOA.
               49 TAMANHO-SOBRENOME     PIC S9(004) USAGE BINARY.
               49 TEXTO-SOBRENOME       PIC  X(050).

Qual variável deve ser mencionada na instrução SQL? O nome do item de grupo ou a variável alpha Pic X?

  • Na instrução SQL deve ser mencionado o nome do item de grupo.

Suponha que se tenha um cursor para buscar todos os registros da tabela de INSCRICOES, assim o comando de leitura do cursor, é:

           EXEC SQL
               FETCH INSENSITIVE ABSOLUTE POSITION-READ CURSOR-NAME
                   INTO :CODIGO-PESSOA
                      , :NOME-PESSOA
                      , :SOBRENOME-PESSOA
                      , :DATA-INSCRICAO
                      , :HORA-SAIDA
                      , :TS-CHEGADA
                      , :VALOR-INSCRICAO
           END-EXEC

De modo que logo após a execução do Fetch o texto armazenado na tabela será movimentado para TEXTO-SOBRENOME, e a quantidade de caracteres será automaticamente contabilizada em TAMANHO-SOBRENOME.

Logo se o registro lido possuir o seguinte sobrenome: "Barbosa Ferreira". Os valores serão armazenados na variável host da seguinte forma:
TAMANHO-SOBRENOME = 16
TEXTO-SOBRENOME = Barbosa Ferreira

Para o processamento de leitura do banco de dados (DB) a variável que armazena o tamanho do texto possui o valor gerado automaticamente. Entretanto, para os processos de inserir ou atualizar dados no DB, deve ser calculado pelo COBOL a quantidade de caracteres que serão persistidas no registro em questão.


Para calcular a quantidade de caracteres de uma variável, veja o post: 


Onde, as variáveis do post citado terão respectivamente a seguinte movimentação:

           MOVE TAM-STRING              TO TAMANHO-SOBRENOME
           MOVE TEXTO                   TO TEXTO-SOBRENOME

Lembrando, que na instrução SQL é mencionado o nome do item de grupo da variável host.

Consultar a relação de Termos e Abreviaturas acesse aqui.
FELIPE BARBOSA FERREIRA

Até o próximo post!