楼主: joy0519
825 0

oracle 身份证校正函数 [推广有奖]

  • 3关注
  • 1粉丝

副教授

16%

还不是VIP/贵宾

-

威望
0
论坛币
1740 个
通用积分
98.4184
学术水平
4 点
热心指数
3 点
信用等级
0 点
经验
219 点
帖子
292
精华
0
在线时间
503 小时
注册时间
2015-9-26
最后登录
2024-3-29

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
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;


二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝


您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-4-24 22:16