oracle 身份证校验函数

1、正则表达式写法:

CREATE OR REPLACE FUNCTION fn_checkidcard (p_idcard IN VARCHAR2) RETURN INT
 IS
    v_regstr      VARCHAR2 (2000);
    v_sum         NUMBER;
    v_mod         NUMBER;
    v_checkcode   CHAR (11)       := '10X98765432';
    v_checkbit    CHAR (1);
    v_areacode    VARCHAR2 (2000) := '11,12,13,14,15,21,22,23,31,32,33,34,35,36,37,41,42,43,44,45,46,50,51,52,53,54,61,62,63,64,65,71,81,82,91,';
 BEGIN
    CASE LENGTHB (p_idcard)
       WHEN 15
       THEN                                                            -- 15位
          IF INSTRB (v_areacode, SUBSTR (p_idcard, 1, 2) || ',') = 0 THEN
             RETURN 0;
          END IF;
 
          IF MOD (TO_NUMBER (SUBSTRB (p_idcard, 7, 2)) + 1900, 400) = 0
             OR 
             (
                 MOD (TO_NUMBER (SUBSTRB (p_idcard, 7, 2)) + 1900, 100) <> 0
                 AND 
                 MOD (TO_NUMBER (SUBSTRB (p_idcard, 7, 2)) + 1900, 4) = 0
             )
          THEN                                                          -- 闰年
             v_regstr :=
                '^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$';
          ELSE
             v_regstr :=
                '^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$';
          END IF;
 
          IF REGEXP_LIKE (p_idcard, v_regstr) THEN
             RETURN 1;
          ELSE
             RETURN 0;
          END IF;
       WHEN 18
       THEN                                                             -- 18位
          IF INSTRB (v_areacode, SUBSTRB (p_idcard, 1, 2) || ',') = 0 THEN
             RETURN 0;
          END IF;
         
          IF MOD (TO_NUMBER (SUBSTRB (p_idcard, 7, 4)), 400) = 0
             OR 
             (
                 MOD (TO_NUMBER (SUBSTRB (p_idcard, 7, 4)), 100) <> 0
                 AND 
                 MOD (TO_NUMBER (SUBSTRB (p_idcard, 7, 4)), 4) = 0
             )
          THEN                                                          -- 闰年
             v_regstr :=
                '^[1-9][0-9]{5}(19|20)[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}[0-9Xx]$';
          ELSE
             v_regstr :=
                '^[1-9][0-9]{5}(19|20)[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}[0-9Xx]$';
          END IF;
 
          IF REGEXP_LIKE (p_idcard, v_regstr) THEN
             v_sum :=
                    (  TO_NUMBER (SUBSTRB (p_idcard, 1, 1))
                     + TO_NUMBER (SUBSTRB (p_idcard, 11, 1))
                    )
                  * 7
                +   (  TO_NUMBER (SUBSTRB (p_idcard, 2, 1))
                     + TO_NUMBER (SUBSTRB (p_idcard, 12, 1))
                    )
                  * 9
                +   (  TO_NUMBER (SUBSTRB (p_idcard, 3, 1))
                     + TO_NUMBER (SUBSTRB (p_idcard, 13, 1))
                    )
                  * 10
                +   (  TO_NUMBER (SUBSTRB (p_idcard, 4, 1))
                     + TO_NUMBER (SUBSTRB (p_idcard, 14, 1))
                    )
                  * 5
                +   (  TO_NUMBER (SUBSTRB (p_idcard, 5, 1))
                     + TO_NUMBER (SUBSTRB (p_idcard, 15, 1))
                    )
                  * 8
                +   (  TO_NUMBER (SUBSTRB (p_idcard, 6, 1))
                     + TO_NUMBER (SUBSTRB (p_idcard, 16, 1))
                    )
                  * 4
                +   (  TO_NUMBER (SUBSTRB (p_idcard, 7, 1))
                     + TO_NUMBER (SUBSTRB (p_idcard, 17, 1))
                    )
                  * 2
                + TO_NUMBER (SUBSTRB (p_idcard, 8, 1)) * 1
                + TO_NUMBER (SUBSTRB (p_idcard, 9, 1)) * 6
                + TO_NUMBER (SUBSTRB (p_idcard, 10, 1)) * 3;
             v_mod := MOD (v_sum, 11);
             v_checkbit := SUBSTRB (v_checkcode, v_mod + 1, 1);
 
             IF v_checkbit = upper(substrb(p_idcard,18,1)) THEN
                RETURN 1;
             ELSE
                RETURN 0;
             END IF;
          ELSE
             RETURN 0;
          END IF;
       ELSE
          RETURN 0;                                      -- 身份证号码位数不对
    END CASE;
 EXCEPTION
    WHEN OTHERS
    THEN
       RETURN 0;
 END fn_checkidcard;
 /
 Show Err;

2、非正则表达式写法

--[Func_checkIdcard]-- 
Create Or Replace Function Func_checkIdcard (p_idcard in varchar2) Return Number 
Is
    v_sum         Number; 
    v_mod         Number; 
    v_length      Number; 
    v_date        Varchar2(10); 
    v_isDate      Boolean; 
    v_isNumber    Boolean; 
    v_isNumber_17 Boolean; 
    v_checkbit    CHAR (1); 
    v_checkcode   CHAR (11)       := '10X98765432'; 
    v_areacode    VARCHAR2 (2000) := '11,12,13,14,15,21,22,23,31,32,33,34,35,36,37,41,42,43,44,45,46,50,51,52,53,54,61,62,63,64,65,71,81,82,91,'; 
      
    --[isNumber]-- 
    Function isNumber (p_string in varchar2) Return Boolean 
    Is
        i           number; 
        k           number; 
        flag        boolean; 
        v_length    number; 
    Begin
        /* 
        算法: 
            通过ASCII码判断是否数字,介于[48, 57]之间。 
            select ascii('0'),ascii('1'),ascii('2'),ascii('3'),ascii('4'),ascii('5'),ascii('6'),ascii('7'),ascii('8'),ascii('9') from dual; 
        */ 
          
        flag := True; 
        select length(p_string) into v_length from dual; 
          
        for i in 1..v_length loop 
            k := ascii(substr(p_string,i,1)); 
            if k < 48 or k > 57 then
                flag := False; 
                Exit; 
            end if; 
        end loop; 
          
        Return flag; 
    End isNumber; 
      
    --[isDate]-- 
    Function isDate (p_date in varchar2) Return Boolean 
    Is
        v_flag          boolean; 
        v_year          number; 
        v_month         number; 
        v_day           number; 
        v_isLeapYear    boolean; 
    Begin
        --[初始化]-- 
        v_flag := True; 
          
        --[获取信息]-- 
        v_year  := to_number(substr(p_date,1,4)); 
        v_month := to_number(substr(p_date,5,2)); 
        v_day   := to_number(substr(p_date,7,2)); 
          
        --[判断是否为闰年]-- 
        if (mod(v_year,400) = 0) Or (mod(v_year,100) <> 0 And mod(v_year,4) = 0) then
            v_isLeapYear := True; 
        else
            v_isLeapYear := False; 
        end if; 
          
        --[判断月份]-- 
        if v_month < 1 Or v_month > 12 then
            v_flag := False; 
            Return v_flag; 
        end if; 
          
        --[判断日期]-- 
        if v_month in (1,3,5,7,8,10,12) and (v_day < 1 or v_day > 31) then
            v_flag := False; 
        end if; 
        if v_month in (4,6,9,11) and (v_day < 1 or v_day > 30) then
            v_flag := False; 
        end if; 
        if v_month in (2) then
            if (v_isLeapYear) then
                --[闰年]-- 
                if (v_day < 1 or v_day > 29) then
                    v_flag := False; 
                end if; 
            else
                --[非闰年]-- 
                if (v_day < 1 or v_day > 28) then
                    v_flag := False; 
                end if; 
            end if; 
        end if; 
          
        --[返回结果]-- 
        Return v_flag; 
    End isDate; 
Begin
    /* 
    返回值说明: 
        -1      身份证号码位数不对 
        -2      身份证号码出生日期超出范围 
        -3      身份证号码含有非法字符 
        -4      身份证号码校验码错误 
        -5      身份证号码地区码非法 
        1       身份证号码通过校验 
    */ 
    --[长度校验]-- 
    select lengthb(p_idcard) into v_length from dual; 
    if v_length not in (15,18) then
        return -1; 
    end if; 
      
    --[区位码校验]-- 
    if instrb(v_areacode, substr(p_idcard, 1, 2)||',') = 0 then
        return -5; 
    end if; 
      
    --[格式化校验]-- 
    if v_length = 15 then
        v_isNumber := isNumber (p_idcard); 
        if not (v_isNumber) then
            return -3; 
        end if; 
    elsif v_length = 18 then
        v_isNumber    := isNumber (p_idcard); 
        v_isNumber_17 := isNumber (substr(p_idcard,1,17)); 
        if not ((v_isNumber) or (v_isNumber_17 and upper(substr(p_idcard,18,1)) = 'X')) then
            return -3; 
        end if; 
    end if; 
      
    --[出生日期校验]-- 
    if v_length = 15 then
        select '19'||substr(p_idcard,7,6) into v_date from dual; 
    elsif v_length = 18 then
        select substr(p_idcard,7,8) into v_date from dual; 
    end if; 
    v_isDate := isDate (v_date); 
    if not (v_isDate) then
        return -2; 
    end if; 
      
    --[校验码校验]-- 
    if v_length = 18 then
        v_sum := 
               (  TO_NUMBER (SUBSTRB (p_idcard, 1, 1)) 
                + TO_NUMBER (SUBSTRB (p_idcard, 11, 1)) 
               ) 
             * 7 
           +   (  TO_NUMBER (SUBSTRB (p_idcard, 2, 1)) 
                + TO_NUMBER (SUBSTRB (p_idcard, 12, 1)) 
               ) 
             * 9 
           +   (  TO_NUMBER (SUBSTRB (p_idcard, 3, 1)) 
                + TO_NUMBER (SUBSTRB (p_idcard, 13, 1)) 
               ) 
             * 10 
           +   (  TO_NUMBER (SUBSTRB (p_idcard, 4, 1)) 
                + TO_NUMBER (SUBSTRB (p_idcard, 14, 1)) 
               ) 
             * 5 
           +   (  TO_NUMBER (SUBSTRB (p_idcard, 5, 1)) 
                + TO_NUMBER (SUBSTRB (p_idcard, 15, 1)) 
               ) 
             * 8 
           +   (  TO_NUMBER (SUBSTRB (p_idcard, 6, 1)) 
                + TO_NUMBER (SUBSTRB (p_idcard, 16, 1)) 
               ) 
             * 4 
           +   (  TO_NUMBER (SUBSTRB (p_idcard, 7, 1)) 
                + TO_NUMBER (SUBSTRB (p_idcard, 17, 1)) 
               ) 
             * 2 
           + TO_NUMBER (SUBSTRB (p_idcard, 8, 1)) * 1 
           + TO_NUMBER (SUBSTRB (p_idcard, 9, 1)) * 6 
           + TO_NUMBER (SUBSTRB (p_idcard, 10, 1)) * 3; 
        v_mod := MOD (v_sum, 11); 
        v_checkbit := SUBSTRB (v_checkcode, v_mod + 1, 1); 
          
        if v_checkbit = upper(substrb(p_idcard,18,1)) then
           return 1; 
        else
           return -4; 
        end if; 
    else
        return 1; 
    end if; 
End Func_checkIdcard; 
/ 
Show Err;
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值