oracle 身份证校验函数

来源:互联网 发布:数据分析的方法论 编辑:程序博客网 时间:2024/04/27 22:24

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;

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; 


原创粉丝点击