oracle_身份证有效性校验

正则表达式写法

CREATE OR REPLACE FUNCTION Func_check_id_card(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 Func_check_id_card;
/

非正则表达式写法

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, '身份证号码通过校验'
    */
    --[长度校验]--
    if p_idcard is null then return -1; end if;
    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;
/
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值