18位身份证和组织机构代码校验ORACLE函数

前提是你 提交于 2020-03-02 17:13:35

 
    18位身份证标准在国家质量技术监督局于1999年7月1日实施的gb11643-1999《公民身份号码》中做了明确规定。
  gb11643-1999《公民身份号码》为gb11643-1989《社会保障号码》的修订版,其中指出将原标准名称“社会保障号码”更名为“公民身份号码”,另外gb11643-1999《公民身份号码》从实施之日起代替gb11643-1989。
  公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位校验码。其含义如下:
  1. 地址码:表示编码对象常住户口所在县(市、旗、区)的行政区划代码,按gb/t2260的规定执行。
  2. 出生日期码:表示编码对象出生的年、月、日,按gb/t7408的规定执行,年、月、日分别用4位、2位、2位数字表示,之间不用分隔符。
  3. 顺序码:表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配给女性。
  校验的计算方式:
  1. 对前17位数字本体码加权求和
  公式为:s = sum(ai * wi), i = 0, ... , 16
  其中ai表示第i位置上的身份证号码数字值,wi表示第i位置上的加权因子,其各位对应的值依次为: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
  2. 以11对计算结果取模
  y = mod(s, 11)
  3. 根据模的值得到对应的校验码
  对应关系为:
   y值:   0 1 2 3 4 5 6 7 8 9 10
  校验码: 1 0 X 9 8 7 6 5 4 3 2


  地址码含义

    身份证前六位是地区代码,代码的解释规则如下:
    abcdef

    a:国内区域
    1 华北 三省二市
    2 东北 三省
    3 华东 六省一市
    4 华南 六省
    5 西南 四省一市
    6 西北 五省
    7 台湾
    8 港澳

    b:省代码
    按照a划定的分区定义省代码,
    有直辖市的,直辖市列前,
    其余按离直辖市的距离排序,
    没有直辖市的,按离北京的远近排序。

    11-15 京 津 冀 晋 蒙
    21-23 辽 吉 黑
    31-37 沪 苏 浙 皖 闽 赣 鲁
    41-46 豫 鄂 湘 粤 桂 琼
    50-54 渝 川 贵 云 藏
    61-65 陕 甘 青 宁 新
    81-82 港 澳

    cd:城市代码
    从01开始排,对于直辖市,cd=01表示市辖区,cd=02表示辖县;
    省的城市代码从省会开始排,其余依92式机动车号牌的顺序排列,
    比如2101=沈阳 2102=大连……
    只有地级城市有独立的城市代码,县级市没有。

    ef:市辖区、郊区、郊县、县级市代码
    如果ef=00,指代这个城市,不特定区县;
    对于非直辖市,如ef=01,指代市辖区(任意一个区),02开始指代特定的区。
    其中:
    e=0代表市辖区,
    e=1代表郊区,
    e=2代表郊县,
    e=8代表县级市。
    对于直辖市,从01开始就依次排区,没有市区和郊区的代码区分。

  关于18位身份证号码尾数是“x”的解释
   居民身份证的号码是按照国家的标准编制的,由18位组成:前六位为行政区划代码,第七至第十四位为出生日期码,第15至17位为顺序码,第18位为校验码。作为尾号的校验码,是由号码编制单位按统一的公式计算出来的,如果某人的尾号是0-9,都不会出现x,但如果尾号是10,那么就得用x来代替,因为如果用10做尾号,那么此人的身份证就变成了19位,而19位的号码违反了国家标准,并且我国的计算机应用系统也不承认19位的身份证号码。ⅹ是罗马数字的10,用x来代替10,可以保证公民的身份证符合国家标准。但是我国的居民身份证在升位后,一些人的尾号变成了x,这部分人在工作生活中,例如去银行存取钱、去汽车公司租赁汽车或者报名参加考试等等过程中,往往不被检验者理解,认为是假身份证,这样的误会给很多人的生活带来不便。公安局的同志希望领到x身份证的同志正确理解这个数字的含义,查验身份证的机关和单位更应该清楚这一点。

 

    下面举例说明校验码的计算方法
    15位的身份证编码首先把出生年扩展为4位,简单的就是增加一个19,但是这对于1900年出生的人不使用(这样的寿星不多了)
    某男性公民身份号码本体码为34052419800101001,首先按照公式(1)计算:
    ∑(ai×wi) mod 11……………………………………(1)
    公式(1)中:
    i----表示号码字符从右至左包括校验码在内的位置序号;
    ai----表示第i位置上的号码字符值;
    wi----示第i位置上的加权因子,其数值依据公式wi=(2 的 i-1 次幂)(mod 11)计算得出。

    i 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
    ai 3 4 0 5 2 4 1 9 8 0 0 1 0 1 0 0 1 a1
    wi 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 1
    ai×wi 21 36 0 25 16 16 2 9 48 0 0 9 0 5 0 0 2 a1

    根据公式(1)进行计算:
    ∑(ai×wi) =(21+36+0+25+16+16+2+9+48++0+0+9+0+5+0+0+2) = 189
    189 ÷ 11 = 17 + 2/11
    ∑(ai×wi) mod 11 = 2
    然后根据计算的结果,从下面的表中查出相应的校验码,其中x表示计算结果为10(男性为大写x;女性为小写x):
    ∑(ai×wi)(mod 11) 0 1 2 3 4 5 6 7 8 9 10
    校验码字符值ai 1 0 x 9 8 7 6 5 4 3 2
    根据上表,查出计算结果为2的校验码为所以该人员的公民身份号码应该为 34052419800101001X。

 

 

 

 

create or replace function f_id_verify(pid varchar2) return varchar2 is
  result varchar2(58);
  type char_tabletype is table of varchar2(1) not null index by binary_integer;
  type num_tabletype is table of number not null index by binary_integer;
  tab_a char_tabletype;
  tab_w num_tabletype;
  tab_i char_tabletype;
  i     number(2) := 0;
  len   number(2) := length(rtrim(ltrim(pid)));
  sigma number(4) := 0;
begin
  tab_i(0) := '1';
  tab_i(1) := '0';
  tab_i(2) := 'x';
  tab_i(3) := '9';
  tab_i(4) := '8';
  tab_i(5) := '7';
  tab_i(6) := '6';
  tab_i(7) := '5';
  tab_i(8) := '4';
  tab_i(9) := '3';
  tab_i(10) := '2';
  --pid := trim(pid);
  if len = 18 then
    for i in 1 .. 17 loop
      tab_w(i) := mod(power(2, ((19 - i) - 1)), 11);
      tab_a(i) := substr(pid, i, 1);
      sigma := sigma + tab_w(i) * tab_a(i);
    end loop;
    result := substr(pid, 1, 17) || tab_i(mod(sigma, 11));
  end if;
  if result = pid then
    return('正确');
  else
    return('错误,应该是:' || result);
  end if;
exception
  when others then
    begin
      return('错误');
      dbms_output.put_line('发生了异常的错误');
    end;
end f_id_verify;
/

 

    组织机构代码是每一个机关、社会团体、企事业单位在全国范围内唯一的、始终不变的法定代码标识。
    最新使用的组织机构代码在1997年颁布实施,由8位数字(或大写拉丁字母)本体代码和1位数字(或大写拉丁字母)校验码组成。本体代码采用系列(即分区段)顺序编码方法。校验码按下列公式计算:
    8
    c9 = 11 - mod ( ∑ci * wi ,11) … (2)
    i=1
    其中:mod —— 表示求余函数;
    i —— 表示代码字符从左到右位置序号;
    ci —— 表示第i位置上的代码字符的值,采用附录a“代码字符集”所列字符;
    c9 —— 表示校验码;
    wi —— 表示第i位置上的加权因子,其数值如下表:
    i 1 2 3 4 5 6 7 8
    wi 3 7 9 10 5 8 4 2
    当mod函数值为1(即 c9 = 10)时,校验码用字母x表示。

create or replace function jgid_verify(pid varchar2) return varchar2 is
  result varchar2(58);
  type char_tabletype is table of varchar2(1) not null index by binary_integer;
  type num_tabletype is table of number not null index by binary_integer;
  tab_a char_tabletype;
  tab_w num_tabletype;
  tab_i char_tabletype;
  i     number(2) := 0;
  len   number(2) := length(rtrim(ltrim(pid)));
  sigma number(4) := 0;
begin

  if len = 9 then
    -- c9 = 11 - mod ( ∑ci * wi ,11) … (2)
    for i in 1 .. 8 loop
      tab_w(i) := mod(power(2, ((10 - i) - 1)), 11);
      --tab_w(i) := mod(power(2, ((10 - i) - 1)), 11); 就是加权算法值
      tab_a(i) := substr(pid, i, 1);
      sigma := sigma + tab_w(i) * tab_a(i);
    end loop;
    if mod(sigma, 11) = 1 then
      result := substr(pid, 1, 8) || 'x';
    else
      result := substr(pid, 1, 8) || to_char(11 - mod(sigma, 11));
    end if;
  end if;
  if result = pid then
    return('正确');
  else
    return('错误,应该是:' || result);
  end if;
exception
  when others then
    begin
      return('错误');
      dbms_output.put_line('发生了异常的错误');
    end;
end jgid_verify;
/

上边这个函数,经过验证,发现对于大部分组织机构代码,都是可以使用的,但是对于一小部分,却会出问题。

SELECT lower('766618250'),jgid_verify(lower('766618250')) FROM dual;

返回值是:错误,应该是:7666182511  --这个返回值是错误的,因为 7666182511 10位,明显有问题。

 

下面我提供两个另外的函数,分别针对10位组织机构代码和9为组织机构代码进行验证

针对10位组织机构代码:

--输入 10位的组织机构代码(含有-) 格式:12345678-9
--输出 是否验证通过,0 未通过,1 通过
create or replace function organizationCode10Verify(organizationCode varchar2)
  return smallint is
  len       number(3); --组织机构代码长度
  I         int;       
  J         int;
  K         int;
  N         int;
  C         char(1);
  valid     number(1); --是否验证通过,0 未通过,1 通过
begin
  valid := 0;
  len:= Length(trim(organizationCode));
  
  IF len != 10 then
    return valid;
  END IF;
  IF substr(organizationCode, 9, 1)!='-' then
    return valid;
  END IF;
  I := 1;
  J := 1;
  N := 0;
  while(I <= 8) loop
    K := ASCII(substr(organizationCode, 9-I, 1)) - 48;
    J := trunc(mod((J * 2), 11));
    N := N + J * K;
    I := I + 1;
  END loop;
  N := 11-trunc(mod(N, 11));
  C := substr(organizationCode, 10, 1);
  K := ASCII(C) - 48;
  if N=11 then 
  N:=0;
  END IF;
  IF C='x' OR C='X' THEN 
   K:=10;
  END IF;
  IF K != N then
    return valid;
  END IF;
  valid := 1;
  return valid;
end organizationCode10Verify;
  

 

针对9位组织机构代码:

 

--输入 9位的组织机构代码(不含-) 格式:123456789
--输出 是否验证通过,0 未通过,1 通过
create or replace function organizationCode9Verify(organizationCode varchar2)
  return smallint is
  len       number(3); --组织机构代码长度
  I         int;       
  J         int;
  K         int;
  N         int;
  C         char(1);
  valid     number(1); --是否验证通过,0 未通过,1 通过
begin
  valid := 0;
  len:= Length(trim(organizationCode));

  IF len != 9 then
    return valid;
  END IF;
  I := 1;
  J := 1;
  N := 0;
  while(I <= 8) loop
    K := ASCII(substr(organizationCode,9-I, 1)) - 48;
    J := trunc(mod((J * 2), 11));
    N := N + J * K;
    I := I + 1;
  END loop;
  N := 11-trunc(mod(N, 11));
  C := substr(organizationCode, 9, 1);
  K := ASCII(C) - 48;
  if N=11 then 
    N:=0;
  END IF;
  IF C='x' OR C='X' THEN 
  K:=10;
  END IF;
  IF K != N then
    return valid;
  END IF;
  valid := 1;
  return valid;
end organizationCode9Verify;

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!