Pular para o conteúdo
Visualizando 15 posts - 1 até 15 (de 17 do total)
  • Autor
    Posts
  • #87224
    facc
    Participante

      Bom dia a todos.

      Estou com um problemão nas mãos.

      É o seguinte, a empresa que trabalho, comprou 100.000 números para sorteio de premios junto com a Caixa Federal. Esses números são únicos (não se repetem), então criei uma base e exportei esses numeros para uma tabela em um servidor Central, onde todas as filiais (67 para ser exato) acessam essa tabela através de uma procedure para reservar essa numeração. Vou tentar explicar melhor esse procedimento.

      1 – A loja acessa essa tabela (através de uma procedure) dizendo que filial é e a quantidade de numeros que ela está vendendo retornando os números “gerados”.

      2 – Essa procedure se encarrega de reservar esses números e retorna-los para o sistema PDV (onde vendeu), porém em alguns casos esses números acabam se repetindo, o que não pode acontecer.

      3 – A procedure grava o número da loja, PDV que vendeu e a hora da venda e altera uma flag para o número que o SELECT achou livre.

      Abaixo segue a procedure que faz essa reserva.

      CREATE OR REPLACE PROCEDURE CYBELAR_RES_NRSORTE(P_LOJA IN varchar2,
      P_PDV IN VARCHAR2,
      P_QTD IN NUMBER,
      P_NROSORTE OUT varchar2,
      P_CONFIRMA OUT NUMBER) is
      /***********************************************************
      * PROCEDURE : CYBELAR_RES_NRSORTE *
      * OBJETIVO : RESERVAR O NRSORTE P/ A LOJA E "ESCONDER" *
      DAS DEMAIS LOJAS E OUTRAS RESERVAS *
      * CRIACAO : 08/05/2009 *
      * VERSAO : 1.0 *
      * AUTOR : FABIO A. CAMPOS CRUZ - fabioc@cybelar.com.br *
      ***********************************************************/

      pragma autonomous_transaction;

      retorno_nrsorte varchar2(5);
      ListaNrsorte varchar2(1000);
      RETORNOCONFIRMA NUMBER;
      erro_int varchar2(1000);
      vc_dir_log varchar2(100);
      vc_id_log varchar2(7) := 'CYBELAR';
      vc_arq_log varchar2(15) := 'NRSORTE.LOG';
      vc_nome_pgm varchar2(50) := 'PDV_NRSORTE';
      vu_file utl_file.file_type;

      VN_QTREG NUMBER := 0;

      /*cursor cur_nrosorte is
      /*SELECT NROSORTE INTO VG_NRSORTE
      FROM CYBELAR_NROSORTE
      WHERE FLGUSO = 0 AND (LOJA IS NULL OR LOJA = '')
      AND ROWNUM < P_QTD + 1 FOR UPDATE OF LOJA NOWAIT; select nrosorte from cybelar_nrosorte where flguso = 0 AND (LOJA IS NULL OR LOJA = '') and rownum < P_QTD + 1; res cur_nrosorte%rowtype; */ begin BEGIN SELECT PINT_NM_DIRETORIO_LOG INTO VC_DIR_LOG FROM GEMCO_PARAMETRO_INTERFACE PINT, GEMCO_SISTEMA SIST WHERE PINT.PINT_CD_SISTEMA = SIST.SIST_CD_SISTEMA AND SIST.SIST_DS_SISTEMA = vc_nome_pgm; EXCEPTION -- SE NAO EXISTIR INFORMAR O DIRETORIO ONDE DEVERA SER -- GERADO O LOG DE OCORRENCIAS WHEN NO_DATA_FOUND THEN VC_DIR_LOG := '/integra/Log'; WHEN TOO_MANY_ROWS THEN VC_DIR_LOG := '/integra/Log'; WHEN OTHERS THEN VC_DIR_LOG := '/integra/Log'; END; begin vu_file := utl_file.fopen(vc_dir_log, vc_arq_log, 'r'); utl_file.fclose(vu_file); exception when others then sp_int_gemco_gera_log('INICIO DO LOG', vc_dir_log, vc_id_log, vc_arq_log, sysdate, null, vc_nome_pgm, 0, 0, 0); end; sp_int_gemco_gera_log('GERA LOG', vc_dir_log, vc_id_log, vc_arq_log, sysdate, 'INICIO DO LOG', vc_nome_pgm, 0, 0, 0); --open cur_nrosorte; FOR QTD IN 1 .. P_QTD loop --fetch cur_nrosorte --into res; /*if cur_nrosorte%notfound then ERRO_INT := NULL; ERRO_INT := 'ERRO AO RESERVAR O NRSORTE PARA A LOJA ' || P_LOJA || '.' || sqlerrm; RETORNOCONFIRMA := 1; ROLLBACK; exit; ELSE*/ UPDATE CYBELAR_NROSORTE SET FLGUSO = 1, LOJA = P_LOJA, PDV_CAIXA = P_PDV, DATANRSORTE = SYSDATE WHERE NROSORTE = (SELECT NROSORTE FROM CYBELAR_NROSORTE WHERE FLGUSO = 0 AND (LOJA IS NULL OR LOJA = '')) RETURNING NROSORTE INTO retorno_nrsorte; COMMIT; ListaNrsorte := retorno_nrsorte || '|' || ListaNrsorte; RETORNOCONFIRMA := 0; --end if; VN_QTREG := VN_QTREG + 1; end loop; IF VN_QTREG = 0 THEN ERRO_INT := 'ERRO AO RESERVAR O NRSORTE (' || P_NROSORTE || ') PARA A LOJA ' || P_LOJA || '.'; RETORNOCONFIRMA := 1; ELSE ERRO_INT := 'RESERVADO COM SUCESSO (' || ListaNrsorte || '). LOJA ' || P_LOJA; RETORNOCONFIRMA := 0; END IF; sp_int_gemco_gera_log('GERA LOG', vc_dir_log, vc_id_log, vc_arq_log, sysdate, erro_int, vc_nome_pgm, 0, 0, 0); sp_int_gemco_gera_log('GERA LOG', vc_dir_log, vc_id_log, vc_arq_log, sysdate, 'FIM DO LOG', vc_nome_pgm, 0, 0, 0); sp_int_gemco_gera_log('FIM LOG', vc_dir_log, vc_id_log, vc_arq_log, sysdate, null, vc_nome_pgm, 0, 0, 0); --close cur_nrosorte; COMMIT; P_CONFIRMA := RETORNOCONFIRMA; P_NROSORTE := ListaNrsorte; end cybelar_res_nrsorte;

      Lembrando que as 67 lojas podem acessar ao mesmo tempo essa procedure.

      #87225
      lipcurl
      Participante

        Bom dia Meu amigo,

        Não entendi a sua dúvida ainda.

        #87226
        facc
        Participante

          Deixa eu tentar explicar melhor

          Tenho uma tabela com 100.000 registros e preciso “bloquear” uma certa quantidade (a loja irá dizer) e esconder esses numeros das demais lojas.

          #87229
          Avatar photoRegis Araujo
          Participante

            Ola Facc, bom dia!

            Bom, pelo que eu entendi.. você precisa separar registros para determinadas lojas..

            Bom, creio que a maneira mais fácil é você criar um campo em sua tabela para fazer o controle destes registros, tipo, criar um PT_LOJA e neste campo você informa a qual loja ele pertence e no seu select de consulta você pode colocar como clausula onde o campo PT_LOJA for nulo e/ou igual ao valor determinado para cada loja.

            Espero que isto lhe ajude.

            Abraços..

            #87230
            lipcurl
            Participante

              Exato.

              Também concordo.

              #87231
              facc
              Participante

                [quote=”Thunder_Catz”:3uefnx5d]Ola Facc, bom dia!

                Bom, pelo que eu entendi.. você precisa separar registros para determinadas lojas..

                Bom, creio que a maneira mais fácil é você criar um campo em sua tabela para fazer o controle destes registros, tipo, criar um PT_LOJA e neste campo você informa a qual loja ele pertence e no seu select de consulta você pode colocar como clausula onde o campo PT_LOJA for nulo e/ou igual ao valor determinado para cada loja.

                Espero que isto lhe ajude.

                Abraços..[/quote]

                Já pensei nessa possibilidade, mas caso a empresa abra uma nova filial, isso se torna inviavel.
                Na tabela onde se encontram esses 100.000 registros, possui um campos chamado Loja (grava a filial) e flguso (para dizer se está “bloqueado” ou não) mas o que dá impressão que o select está ignorando em alguns casos esses campos.

                #87232
                eversonpiza
                Participante

                  Quando uma loja reserva uma quantidade de números, eles tem que ser sequenciais?
                  Se não, minha sugestão é a seguinte.

                  1-Fazer o lock de apenas um registro.
                  “select * from tabela where PT_LOJA is null and rownum = 1 FOR UPDATE NOWAIT”.
                  2-Fazer o update colocando o valor em PT_LOJA
                  3-Quardar o número reservado
                  4-Ficar em um loop até terminar a quantidade solicitada
                  5-dar commit.
                  6-Retornar todos os reservados.

                  No passo 1, vc faria um tratamento da exception, e quando o registro estiver locado, vc parte para o próximo, e assim por diante.

                  #87233
                  Avatar photoRegis Araujo
                  Participante

                    Opa..

                    Agora que percebi que você já faz isto que lhe falei..

                    E entendi o que ocorre. Isto ocorre devido a você não travar o registro antes de realizar o UPDATE, você da um select para retornar o valor, mas não da um LOCK neste valor, coloque junto do seu select um “for update skip locked” ou crie uma função que locke o registro e trabalhe com este registro, assim você terá a certeza que ninguem irá acessar este registro atraves de outra sessão..

                    Mais ou menos assim a função..


                    FUNCTION FC_IsLocked(pVALOR IN NUMBER) RETURN PLS_INTEGER IS
                    iResult PLS_INTEGER := 0;
                    BEGIN
                    SELECT VALOR INTO iResult FROM TABELA p WHERE p.VALOR= pVALOR FOR UPDATE NOWAIT;

                    RETURN(iResult);
                    

                    EXCEPTION
                    WHEN OTHERS THEN
                    RETURN(iResult);
                    END FC_IsLocked;

                    Ai em um bloco da sua procedure.. você ficaria mais ou menos desta maneira… Tem como ajustar melhor isto.. fiz como gambiarra.. mas acho que dá para vc entender a lógica…

                    CURSOR cDados IS
                      SELECT NROSORTE
                            FROM CYBELAR_NROSORTE
                             WHERE FLGUSO = 0
                               AND (LOJA IS NULL OR LOJA = '')
                               AND ROWNUM  0 THEN
                    
                      UPDATE CYBELAR_NROSORTE
                       SET FLGUSO      = 1,
                           LOJA        = P_LOJA,
                           PDV_CAIXA   = P_PDV,
                           DATANRSORTE = SYSDATE
                      WHERE NROSORTE    = cDados.NROSORTE; 
                    
                    RETURNING NROSORTE INTO retorno_nrsorte;
                    

                    END LOOP;

                    Abraços..

                    #87235
                    facc
                    Participante

                      Fiz isso que vc me sugeriu, mas não está retornando a qntdd solicitada

                      #87241
                      Marcio68Almeida
                      Participante

                        [quote=”facc”:mwact5q4]Fiz isso que vc me sugeriu, mas não está retornando a qntdd solicitada[/quote]
                        Se não está retornando a quantidade solicitada é por que todos estão fazendo o mesmo processo e não há número suficientes para todos…
                        Quantos números está reservando para cada loja ???

                        #87242
                        facc
                        Participante

                          numeros á sim, a tabela tem 100.000 registros.

                          em testes aqui (2 computadores) ela não me retornou a quantidade solicitada, nos testes fizemos pedimos 5 em um computador e mais 5 no outro.
                          No cupom ela repetiu a numeração.

                          Mas já estamos num caminho pra a resolução final.

                          #87243
                          facc
                          Participante

                            Estou enviando a procedure para a analise

                            CREATE OR REPLACE PROCEDURE CYBELAR_RES_NRSORTE(P_LOJA IN varchar2,
                            P_PDV IN VARCHAR2,
                            P_QTD IN NUMBER,
                            P_NROSORTE OUT varchar2,
                            P_CONFIRMA OUT NUMBER) is
                            /***********************************************************
                            * PROCEDURE : CYBELAR_RES_NRSORTE *
                            * OBJETIVO : RESERVAR O NRSORTE P/ A LOJA E "ESCONDER" *
                            DAS DEMAIS LOJAS E OUTRAS RESERVAS *
                            * CRIACAO : 08/05/2009 *
                            * VERSAO : 1.0 *
                            * AUTOR : FABIO A. CAMPOS CRUZ - fabioc@cybelar.com.br *
                            ***********************************************************/

                            pragma autonomous_transaction;

                            retorno_nrsorte varchar2(5);
                            ListaNrsorte varchar2(1000);
                            RETORNOCONFIRMA NUMBER;
                            erro_int varchar2(1000);
                            vc_dir_log varchar2(100);
                            vc_id_log varchar2(7) := 'CYBELAR';
                            vc_arq_log varchar2(60) := 'NRSORTE_' || to_char(sysdate, 'DDMMYY') ||
                            '.LOG';
                            vc_nome_pgm varchar2(50) := 'PDV_NRSORTE';
                            vu_file utl_file.file_type;

                            VN_QTREG NUMBER := 0;

                            cursor cur_nrosorte is
                            --cursor pega numeros "livres"
                            select nrosorte
                            from cybelar_nrosorte
                            where flguso = 0
                            AND (LOJA IS NULL OR LOJA = '')
                            and rownum = P_QTD + 1;

                            res cur_nrosorte%rowtype;

                            begin
                            BEGIN
                            SELECT PINT_NM_DIRETORIO_LOG
                            INTO VC_DIR_LOG
                            FROM GEMCO_PARAMETRO_INTERFACE PINT, GEMCO_SISTEMA SIST
                            WHERE PINT.PINT_CD_SISTEMA = SIST.SIST_CD_SISTEMA
                            AND SIST.SIST_DS_SISTEMA = vc_nome_pgm;
                            EXCEPTION
                            -- SE NAO EXISTIR INFORMAR O DIRETORIO ONDE DEVERA SER
                            -- GERADO O LOG DE OCORRENCIAS
                            WHEN NO_DATA_FOUND THEN
                            VC_DIR_LOG := '/integra/Log';
                            WHEN TOO_MANY_ROWS THEN
                            VC_DIR_LOG := '/integra/Log';
                            WHEN OTHERS THEN
                            VC_DIR_LOG := '/integra/Log';
                            END;

                            begin
                            vu_file := utl_file.fopen(vc_dir_log, vc_arq_log, 'r');
                            utl_file.fclose(vu_file);
                            exception
                            when others then
                            sp_int_gemco_gera_log('INICIO DO LOG',
                            vc_dir_log,
                            vc_id_log,
                            vc_arq_log,
                            sysdate,
                            null,
                            vc_nome_pgm,
                            0,
                            0,
                            0);
                            end;

                            FOR rNrSorte IN cur_nrosorte loop

                            if CYBELAR_LCK_REGISTRO(rNrSorte.nrosorte) &gt; 0 then
                            
                              UPDATE CYBELAR_NROSORTE
                                 SET FLGUSO      = 1,
                                     LOJA        = P_LOJA,
                                     PDV_CAIXA   = P_PDV,
                                     DATANRSORTE = SYSDATE
                               WHERE NROSORTE = rNrSorte.nrosorte
                              RETURNING NROSORTE INTO retorno_nrsorte;
                              COMMIT;
                            
                              ListaNrsorte    := retorno_nrsorte || '|' || ListaNrsorte;
                              RETORNOCONFIRMA := 0;
                            end if;
                            VN_QTREG := VN_QTREG + 1;
                            

                            end loop;
                            close cur_nrosorte;

                            IF VN_QTREG = 0 THEN
                            ERRO_INT := 'ERRO AO RESERVAR O NRSORTE (' || P_NROSORTE ||
                            ') PARA A LOJA ' || P_LOJA || '.';
                            RETORNOCONFIRMA := 1;
                            ELSE
                            ERRO_INT := 'RESERVADO COM SUCESSO (' || ListaNrsorte ||
                            '). LOJA ' || P_LOJA;
                            RETORNOCONFIRMA := 0;
                            END IF;

                            sp_int_gemco_gera_log('GERA LOG',
                            vc_dir_log,
                            vc_id_log,
                            vc_arq_log,
                            sysdate,
                            erro_int,
                            vc_nome_pgm,
                            0,
                            0,
                            0);

                            sp_int_gemco_gera_log('FIM LOG',
                            vc_dir_log,
                            vc_id_log,
                            vc_arq_log,
                            sysdate,
                            null,
                            vc_nome_pgm,
                            0,
                            0,
                            0);
                            COMMIT;

                            P_CONFIRMA := RETORNOCONFIRMA;
                            P_NROSORTE := ListaNrsorte;

                            end cybelar_res_nrsorte;

                            #87249
                            facc
                            Participante

                              uma coisa que descobri que se eu solicitar em um computador 4 numeros e em outro eu solicitar 3, no qual soluciou 4, este recebe apenas 3 dos 4 e no outro apenas 1 numero, totalizando os 4 solicitados no primeiro computador.

                              Como posso rodar essa procedure “concorrente”, ou seja independente de quem solicitou primeiro.

                              #87250
                              facc
                              Participante

                                [quote=”eversonpiza”:2pylfw96]Quando uma loja reserva uma quantidade de números, eles tem que ser sequenciais?
                                Se não, minha sugestão é a seguinte.

                                1-Fazer o lock de apenas um registro.
                                “select * from tabela where PT_LOJA is null and rownum = 1 FOR UPDATE NOWAIT”.
                                2-Fazer o update colocando o valor em PT_LOJA
                                3-Quardar o número reservado
                                4-Ficar em um loop até terminar a quantidade solicitada
                                5-dar commit.
                                6-Retornar todos os reservados.

                                No passo 1, vc faria um tratamento da exception, e quando o registro estiver locado, vc parte para o próximo, e assim por diante.[/quote]

                                vc poderia me dar um exemplo pratico?

                                #87251
                                eversonpiza
                                Participante

                                  Não cheguei a testar, mas seria algo mais ou menos assim:


                                  tabela:
                                  TAB_NUMEROS
                                  (NUMERO NUMBER
                                  LOJA NUMBER);

                                  PROCEDURE PRC_RESERVA_NUMERO(iQtd NUMBER, iLoja NUMBER, iLista out varchar2) IS

                                  lock_error exception;
                                  pragma exception_init(lock_error,-54);

                                  vLista varchar2(4000);
                                  vNumero number;

                                  BEGIN
                                  FOR C IN 1.. iQtd LOOP
                                  BEGIN
                                  SELECT T.NUMERO INTO vNumero
                                  FROM TAB_NUMEROS
                                  WHERE LOJA IS NULL
                                  AND ROWNUM <= 1
                                  FOR UPDATE NOWAIT;
                                  vLista := vLista || '|' || vNumero;
                                  UPDATE TAB_NUMEROS SET LOJA = iLoja WHERE NUMERO = vNumero;
                                  commit;
                                  EXCEPTION
                                  WHEN lock_error then null;
                                  END;
                                  END LOOP;
                                  END;
                                  /

                                  Neste exemplo ele pega um por um e já dá o commit, se der algum erro inesperado no meio vc vai perder os números já selecionados, outra forma é já selecionar todas de uma vez.

                                Visualizando 15 posts - 1 até 15 (de 17 do total)
                                • Você deve fazer login para responder a este tópico.