CPF (calculo do digito verificador)

Dúvidas, dicas e truques de PL/SQL. Aqui também vão assuntos relacionados a pacotes, triggers, funções, Java-Stored Procedures, etc
Responder
paulaholti
Rank: Programador Pleno
Rank: Programador Pleno
Mensagens: 43
Registrado em: Sex, 29 Jan 2010 4:02 pm
Localização: sp
iniciante oracle pl/sql forms reports

Tava lendo alguma coisa aqui no fórum a respeito, mas perdi qual era o tópico. Resolvi da uma consultada de como valida o digito verificador de um CPF. Achei um tutorial das regras(validação) nesse site:
http://imasters.uol.com.br/artigo/2410 (nem sei se pode "divulgar" outros sites)

então comecei a tentar a fazer a validacao do DV atráves de um só select. Depois de um bom tmepo consegui chegar a esse resultado ( baseado no CPF de numero 222333666 assim como está no site)

Segue o select:

Selecionar tudo

SELECT (222333666||'-'||DIG1||DIG2) CPF, DIG1||DIG2 "DIGITO VERIFICADOR"
 FROM
 (SELECT DECODE(M2,0,0,1,0,2,0,(11-M2)) DIG2, DIG1
 FROM
 (SELECT MOD((SUBSTR(222333666||DIG1,1,1)*11)+
             (SUBSTR(222333666||DIG1,2,1)*10)+
             (SUBSTR(222333666||DIG1,3,1)*9)+
             (SUBSTR(222333666||DIG1,4,1)*8)+
             (SUBSTR(222333666||DIG1,5,1)*7)+
             (SUBSTR(222333666||DIG1,6,1)*6)+
             (SUBSTR(222333666||DIG1,7,1)*5)+
             (SUBSTR(222333666||DIG1,8,1)*4)+
             (SUBSTR(222333666||DIG1,9,1)*3)+
             (SUBSTR(222333666||DIG1,10,1)*2),11) M2, DIG1
 FROM
 (SELECT DECODE(M1,0,0,1,0,2,0,(11-M1)) DIG1
 FROM
 (select MOD((substr(222333666,1,1)*10)+
             (substr(222333666,2,1)*9)+
             (substr(222333666,3,1)*8)+
             (substr(222333666,4,1)*7)+
             (substr(222333666,5,1)*6)+
             (substr(222333666,6,1)*5)+
             (substr(222333666,7,1)*4)+
             (substr(222333666,8,1)*3)+
             (substr(222333666,9,1)*2),11) M1
from dual))))
/
O resultado saiu direitinho do jeito das especificaçoes das regras, no caso o digito verificar para o numero 222333666 é 38 (222333666-38)
Queria saber se tem outros caminhos para fazer esse select ou só do jeito que está já está bom.?? . Gosto sempre de saber das outras alternativas.

O B R I G A D A A T O D O S !!!
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Muito bacana mesmo, muito bem pensado. :D Tinha rolado num outro tópico onde o assunto foi mudando e acabou caindo em validação de CPF, mas não me passou pela cabeça calcular em SQL mesmo.

http://glufke.net/oracle/viewtopic.php?t=5874&start=0

Só tenho uma observaçãozinha, nos casos de zeros a esquerda tava dando problema, então para corrigir você tem que tratar como caractere em vez de número senão o SUBSTR dá pau. É só colocar um LPAD com zeros preenchendo. Minha sugestão é o seguinte, só refatorei seu SQL para colocar o CPF de input num lugar só e coloquei o LPAD:

Selecionar tudo

SQL> SELECT (cpf || '-' || dig1 || dig2) cpf, cast(dig1 || dig2 as varchar2(2)) "DIGITO VERIFICADOR"
  2    FROM (SELECT decode(m2, 0, 0, 1, 0, 2, 0, (11 - m2)) dig2, dig1, cpf
  3            FROM (SELECT MOD((substr(cpf || dig1, 1, 1) * 11) + (substr(cpf || dig1, 2, 1) * 10) +
  4                             (substr(cpf || dig1, 3, 1) * 9) + (substr(cpf || dig1, 4, 1) * 8) +
  5                             (substr(cpf || dig1, 5, 1) * 7) + (substr(cpf || dig1, 6, 1) * 6) +
  6                             (substr(cpf || dig1, 7, 1) * 5) + (substr(cpf || dig1, 8, 1) * 4) +
  7                             (substr(cpf || dig1, 9, 1) * 3) + (substr(cpf || dig1, 10, 1) * 2), 11) m2, dig1, cpf
  8                    FROM (SELECT decode(m1, 0, 0, 1, 0, 2, 0, (11 - m1)) dig1,
  9                                 cpf
 10                            FROM (SELECT MOD((substr(cpf, 1, 1) * 10) + (substr(cpf, 2, 1) * 9) +
 11                                             (substr(cpf, 3, 1) * 8) + (substr(cpf, 4, 1) * 7) +
 12                                             (substr(cpf, 5, 1) * 6) + (substr(cpf, 6, 1) * 5) +
 13                                             (substr(cpf, 7, 1) * 4) + (substr(cpf, 8, 1) * 3) +
 14                                             (substr(cpf, 9, 1) * 2),
 15                                             11) m1, cpf
 16                                    FROM (SELECT lpad(000333666, 9, '0') cpf FROM dual)))));
 
CPF          DIGITO VERIFICADOR
------------ ------------------
000333666-24 24
 
SQL> 
Gostei tanto da sua ideia que resolvi escrever uma versão com a cláusula model para praticar. O SQL ficou meio nervoso mas ficou "pequeno":

Selecionar tudo

SQL> select cpf, cast(dig1 || dig2 as varchar2(2)) dv
  2    from dual
  3   model dimension by (1 as x)
  4   measures (lpad(000333666, 9, '0') as cpf, 0 as m1, 0 as dig1, 0 as m2, 0 as dig2, cast(null as varchar2(10)) as cpfdv)
  5   rules iterate (10)
  6   (  m1[1] = m1[1] + (nvl(substr(cpf[1], iteration_number + 1, 1), 0) * (10 - iteration_number)),
  7    dig1[1] = case when mod(m1[1], 11) <= 2 then 0 else 11 - mod(m1[1], 11) end,
  8   cpfdv[1] = cpf[1] || dig1[1],
  9      m2[1] = m2[1] + (nvl(substr(cpfdv[1], iteration_number + 1, 1), 0) * (11 - iteration_number)),
 10    dig2[1] = case when mod(m2[1], 11) <= 2 then 0 else 11 - mod(m2[1], 11) end);
 
CPF       DV
--------- --
000333666 24
 
SQL> 
diegolenhardt
Moderador
Moderador
Mensagens: 1177
Registrado em: Qui, 15 Out 2009 10:28 am
Localização: Recife

jizuis que locuragem.. uiahauia
paulaholti
Rank: Programador Pleno
Rank: Programador Pleno
Mensagens: 43
Registrado em: Sex, 29 Jan 2010 4:02 pm
Localização: sp
iniciante oracle pl/sql forms reports

Obrigada por ajudar na aprimoracao do código. Refazendo sem os erros. Aprendi bastante.

Em cima do seu exemplo eu dei uma alterada, porque eu tinha percebido que tinhas alguns cpf's que o digito não estava batendo. então o codigo ficou assim :

Selecionar tudo


SELECT (cpf || '-' || dig1 || dig2) cpf, dig1 || dig2 "DIGITO VERIFICADOR"
      FROM (SELECT decode(m2, 0, 0, 1, 0, (11 - m2)) dig2, dig1, cpf
              FROM (SELECT MOD((substr(cpf || dig1, 1, 1) * 11) + (substr(cpf || dig1, 2, 1) * 10) +
                               (substr(cpf || dig1, 3, 1) * 9) + (substr(cpf || dig1, 4, 1) * 8) +
                               (substr(cpf || dig1, 5, 1) * 7) + (substr(cpf || dig1, 6, 1) * 6) +
                               (substr(cpf || dig1, 7, 1) * 5) + (substr(cpf || dig1, 8, 1) * 4) +
                               (substr(cpf || dig1, 9, 1) * 3) + (substr(cpf || dig1, 10, 1) * 2), 11) m2, dig1, cpf
                      FROM (SELECT decode(m1, 0, 0, 1, 0, (11 - m1)) dig1,
                                   cpf
                              FROM (SELECT MOD((substr(cpf, 1, 1) * 10) + (substr(cpf, 2, 1) * 9) +
                                               (substr(cpf, 3, 1) * 8) + (substr(cpf, 4, 1) * 7) +
                                               (substr(cpf, 5, 1) * 6) + (substr(cpf, 6, 1) * 5) +
                                               (substr(cpf, 7, 1) * 4) + (substr(cpf, 8, 1) * 3) +
                                               (substr(cpf, 9, 1) * 2),
                                               11) m1, cpf
                                      FROM (SELECT lpad(333666, 9, 0) cpf FROM dual))))) 

Eu não tinha lido direito as regras de validacao então pensei que o resto da divisao até DOIS o digito v. seria ZERO. Mas é só até Um (zero e um), então tirei do decode (2, 0) .

O SUBST deixei como numerico e não teve problemas (aparentemente).

Não entendi essa parte :

Selecionar tudo

cast(dig1 || dig2 as varchar2(2)) "DIGITO VERIFICADOR"
Deixei apenas como :

Selecionar tudo

dig1 || dig2 "DIGITO VERIFICADOR'
E surtiu o mesmo efeito . ???

O teu segundo select é casca grossa rs, ainda não tenho conhecimento para entender ou muito menos fazer desse jeito hehe. (tenho muito a aprender)

O B R I G A D A A T O D O S !!
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Boa observação... sendo assim o meu sinal deixa de ser <=2 e vira <2 também.

Selecionar tudo

select cpf, cast(dig1 || dig2 as varchar2(2)) dv
  from dual
 model dimension by (1 as x)
 measures (lpad(000333666, 9, '0') as cpf, 0 as m1, 0 as dig1, 0 as m2, 0 as dig2, cast(null as varchar2(10)) as cpfdv)
 rules iterate (10)
 (  m1[1] = m1[1] + (nvl(substr(cpf[1], iteration_number + 1, 1), 0) * (10 - iteration_number)),
  dig1[1] = case when mod(m1[1], 11) < 2 then 0 else 11 - mod(m1[1], 11) end,
 cpfdv[1] = cpf[1] || dig1[1],
    m2[1] = m2[1] + (nvl(substr(cpfdv[1], iteration_number + 1, 1), 0) * (11 - iteration_number)),
  dig2[1] = case when mod(m2[1], 11) < 2 then 0 else 11 - mod(m2[1], 11) end);
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Sobre o cast, é só para formatação mesmo... bobagem minha. :oops:
Avatar do usuário
fsitja
Rank: OraSauro
Rank: OraSauro
Mensagens: 611
Registrado em: Seg, 19 Jan 2009 4:29 pm
Localização: Gaúcho no Rio de Janeiro - RJ
"The scars exist to remind us that the past was real"
Campanha: Como fazer uma pergunta e obter uma resposta.
http://tkyte.blogspot.com/2005/06/how-t ... tions.html

OCA & OCP Developer — OCE SQL Expert — OCS Data Warehousing Specialist

Sobre o MODEL, ele pode ser útil em cálculos aritméticos, principalmente onde envolve iteração ou recursão, que são coisas geralmente complicadas de se fazer em SQL (onde só se tem Connect By e no 11g criaram o With recursivo, muito semelhante).

Segue a documentação para atiçar a curiosidade. É no mínimo curioso, mas pode ser divertido para quebrar a cabeça :P

http://download.oracle.com/docs/cd/E118 ... #DWHSG8764
Avatar do usuário
dr_gori
Moderador
Moderador
Mensagens: 5024
Registrado em: Seg, 03 Mai 2004 3:08 pm
Localização: Portland, OR USA
Contato:
Thomas F. G

Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered

Esse tópico virou uma "pérola" a ser guardada com carinho... hehehe
Muito bom mesmo!! Parabéns galera...
bia3105
Rank: Estagiário Pleno
Rank: Estagiário Pleno
Mensagens: 3
Registrado em: Qui, 26 Ago 2010 3:43 pm
Localização: Belo Horizonte - MG

Selecionar tudo

SELECT (cnpj || dig1 || dig2) cnpj 
    into aidentificador
    FROM (SELECT decode(m2, 0, 0, 1, 0, (11 - m2)) dig2, dig1, cnpj 
            FROM (SELECT MOD((substr(cnpj || dig1, 1 , 1) * 6) + (substr(cnpj || dig1, 2 , 1) * 5) + 
                             (substr(cnpj || dig1, 3 , 1) * 4) + (substr(cnpj || dig1, 4 , 1) * 3) + 
                             (substr(cnpj || dig1, 5 , 1) * 2) + (substr(cnpj || dig1, 6 , 1) * 9) + 
                             (substr(cnpj || dig1, 7 , 1) * 8 ) + (substr(cnpj || dig1, 8 , 1) * 7) + 
                             (substr(cnpj || dig1, 9 , 1) * 6) + (substr(cnpj || dig1, 10, 1) * 5) + 
                             (substr(cnpj || dig1, 11, 1) * 4) + (substr(cnpj || dig1, 12, 1) * 3) +
                             (dig1 * 2), 11) m2, dig1, cnpj                           
                        FROM (SELECT decode(m1, 0, 0, 1, 0, (11 - m1)) dig1, cnpj
                                FROM (SELECT MOD((substr(cnpj, 1 , 1) * 5) + (substr(cnpj, 2 , 1) * 4) + 
                                                 (substr(cnpj, 3 , 1) * 3) + (substr(cnpj, 4 , 1) * 2) + 
                                                 (substr(cnpj, 5 , 1) * 9) + (substr(cnpj, 6 , 1) * 8 ) + 
                                                 (substr(cnpj, 7 , 1) * 7) + (substr(cnpj, 8 , 1) * 6) + 
                                                 (substr(cnpj, 9 , 1) * 5) + (substr(cnpj, 10, 1) * 4) + 
                                                 (substr(cnpj, 11, 1) * 3) + (substr(cnpj, 12, 1) * 2), 11) m1, cnpj 
                                        FROM (SELECT lpad(AIdentifSemDV, 12, 0) cnpj FROM dual))))); 
Diego_Mello
Rank: DBA Júnior
Rank: DBA Júnior
Mensagens: 229
Registrado em: Sex, 05 Set 2008 2:59 pm
Localização: Igrejinha - RS
Diego Mello
Igrejinha - RS
www.twitter.com/diegolmello

O fsitja me dá medo às vezes! ahuahuahua
victorhugomuniz
Moderador
Moderador
Mensagens: 1396
Registrado em: Sex, 01 Fev 2008 2:06 pm
Localização: Rio de Janeiro - RJ
Contato:
:D

Diego_Mello escreveu:O fsitja me dá medo às vezes! ahuahuahua
se assunto for pl sql, fsitja é meu idolo.. o cara sempre revela o oculto
rsrsrsrsrsrs
Responder
  • Informação
  • Quem está online

    Usuários navegando neste fórum: Nenhum usuário registrado e 18 visitantes