Eu tenho tabelas no Oracle que contém os dias da semana em que uma determinada cobrança deve ser gerada, que possui o seguinte formato: 2;4;6. Isso significa que esta cobrança deve ser gerada nas segundas, quartas e sextas-feiras
Para que eu possa gerar a cobrança no dia correto eu preciso saber se o dia de hoje se encontra em um dos dias listados. O script abaixo é uma simulação do cenário no Oracle:
set serveroutput on DECLARE -------------------------------------------------- --> Array para simular uma tabela -------------------------------------------------- type r_dias is record (dias varchar2(10)); type t_dias is table of r_dias index by binary_integer; v_dias t_dias; -------------------------------------------------- --> Dia corrente -------------------------------------------------- v_hoje varchar2(1) := TO_CHAR(sysdate,'D'); BEGIN -------------------------------------------------- --> Alimentando o array -------------------------------------------------- v_dias(1).dias := '2;4;6'; v_dias(2).dias := '3;5'; v_dias(3).dias := '2;3;4;5;6'; -------------------------------------------------- --> Processando o array -------------------------------------------------- DBMS_OUTPUT.put_line ('Imprimindo registros a processars'); FOR x IN 1..V_DIAS.count LOOP DBMS_OUTPUT.put_line ('Dias da semana: '||V_DIAS(x).dias); --> SE o dia de hoje estiver no dia listado --> Gerar a cobrança --> FIM SE END LOOP; END; /
O requisito exige que, se o dia corrente estiver em um dos dias listados, a cobrança para o estabelecimento deve ser gerada. Porém, como saber se o dia de hoje se encaixa na lista de dias válidos?
Existem várias maneiras de fazer isso porém o objetivo aqui é solucionar este problema utilizando-se do recurso de expressões regulares, portanto, vamos a ela:
O primeiro passo é criar uma expressão regular que permita separar os registros. Execute o script abaixo:
set serveroutput on; DECLARE v_dias varchar2(10) := '2;4;6'; BEGIN DBMS_OUTPUT.put_line ('Primeira Posição: '||REGEXP_SUBSTR(v_dias,'[^;]+',1,1)); DBMS_OUTPUT.put_line ('Segunda Posição.: '||REGEXP_SUBSTR(v_dias,'[^;]+',1,2)); DBMS_OUTPUT.put_line ('Terceira Posição: '||REGEXP_SUBSTR(v_dias,'[^;]+',1,3)); END; /
O segundo passo é criar uma expressão que permita de forma automática qualificar a posição da informação desejada e converter linhas em colunas. Execute o script abaixo várias vezes com diferentes separadores como Ponto e Vírgula(;), ponto (.), vírgula(,) e pipe(|) para ver as consequências:
DECLARE v_dias varchar2(100) := '&dias_separados_ponto_e_virgula'; BEGIN FOR x IN (select REGEXP_SUBSTR(str, exp, 1, level) dias_validos from (select v_dias str , '[^;]+' exp from dual) connect by REGEXP_SUBSTR(str, exp, 1, level) is not null) LOOP DBMS_OUTPUT.put_line (X.dias_validos); END LOOP; END; /
Desta forma temos a linha convertida em coluna utilizando-se de uma expressão regular a um custo baixo. A partir dai basta adicionar a lógica para geração da cobrança:
set serveroutput on DECLARE -------------------------------------------------- --> Array para simular uma tabela -------------------------------------------------- type r_dias is record (dias varchar2(20)); type t_dias is table of r_dias index by binary_integer; v_dias t_dias; -------------------------------------------------- --> Dia corrente -------------------------------------------------- v_hoje varchar2(1) := TO_CHAR(sysdate,'D'); BEGIN -------------------------------------------------- --> Alimentando o array -------------------------------------------------- v_dias(1).dias := '2;4;6'; --> Cenário 1 v_dias(2).dias := '1;3;5'; --> Cenário 2 v_dias(3).dias := '3;5;7'; --> Cenário 3 v_dias(4).dias := '1;2;3;4;5;6;7'; --> Cenário 4 -------------------------------------------------- --> Processando o array -------------------------------------------------- FOR x IN 1..V_DIAS.count LOOP ----------------------------------------------- --> Convertendo linhas em colunas ----------------------------------------------- FOR y IN (select REGEXP_SUBSTR(str, exp, 1, level) dias_validos from (select V_DIAS(x).dias str , '[^;]+' exp from dual) connect by REGEXP_SUBSTR(str, exp, 1, level) is not null) LOOP -------------------------------------------- --> Checando o dia -------------------------------------------- IF Y.dias_validos = v_hoje THEN DBMS_OUTPUT.put_line ('Para o cenário '||x||' Seria gerada cobrança hoje'); END IF; END LOOP; END LOOP; END; /
O grande benefício dessa técnica é converter uma linha delimitada por um separador em colunas a um custo baixo, conforme abaixo:
select REGEXP_SUBSTR(str, exp, 1, level) dias_validos from (select '1;2;3;4;5;6;7' str , '[^;]+' exp from dual) connect by REGEXP_SUBSTR(str, exp, 1, level) is not null
----------------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ----------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 2 (0)| 00:00:01 | |* 1 | CONNECT BY WITHOUT FILTERING| | | | | | 2 | FAST DUAL | | 1 | 2 (0)| 00:00:01 | ----------------------------------------------------------------------------- Estatística ---------------------------------------------------------- 1 recursive calls 0 db block gets 0 consistent gets 0 physical reads 0 redo size 406 bytes sent via SQL*Net to client 346 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 1 sorts (memory) 0 sorts (disk) 7 rows processed
Leave a Comment