Oracle 关于身份证校验规则详细说明(附有代码复制可执行)
身份证号码组成
15位身份证号组成:
省份(2位)市(2位)区[县](2位)年(2位)月(2位)日(2位)+3位序列号 [奇数给男性/偶数给女性]
18位身份证号组成:
省份(2位)市(2位)区[县](2位)年(4位)月(2位)日(2位)+2位序列号+1位性别[奇数给男性/偶数给女性]+1位校验码
注意:
1)(身份证号码第七位到第十四位)表示编码对象出生的年、月、日,其中年份用四位数字表示,年、月、日之间不用分隔符。
2)(身份证号码第十五位到十七位)地址码所标识的区域范围内,对同年、月、日出生的人员编定的顺序号。其中第十七位奇数分给男性,偶数分给女性。
3)(身份证号码最后一位)是根据前面十七位数字码,按照ISO 7064:1983.MOD 11-2校验码计算出来的检验码。作为尾号的校验码,主要是为了校验计算机输入公民身份证号码的前17位数字是否正确,是由号码编制单位按统一的公式计算出来的,如果某人的尾号是0-9,都不会出现X,但如果尾号是10,那么就得用X来代替,因为如果用10做尾号,那么此人的身份证就变成了19位,而19位的号码违反了国家标准,并且中国的计算机用用系统也不承认19位的身份证号码。Ⅹ是罗马数字的10,用X来代替10,可以保证公民的身份证符合国家标准。
三、校验码的计算方法
1、将前面的身份证号码17位数分别乘以不同的系数。从第一位到第十七位的系数分别为:7-9-10-5-8-4-2-1-6-3-7-9-10-5-8-4-2。
2、将这17位数字和系数相乘的结果相加。
3、用加出来和除以11,看余数是多少?
4、余数只可能有0-1-2-3-4-5-6-7-8-9-10这11个数字。其分别对应的最后一位身份证的号码为1-0-X -9-8-7-6-5-4-3-2。
5、通过上面得知如果余数是2,身份证的最后一位号码就是罗马数字x。如果余数是10,就会在身份证的第18位数字上出现的是2。
例如:某男性的身份证号码 我们要看看这个身份证是不是合法的身份证。45010119890620001X(仅测试使用)
首先我们得出前17位的乘积和是244,然后用244除以11得出的结果是17+2/11,也就是说其余数是2。最后通过对应规则就可以知道余数2对应的是罗马数字X。可以判定这是一个合格的身份证号码。
1 CREATE OR REPLACE PROCEDURE PRC_身份证校验(ID_NUMBER IN VARCHAR2, --身份证号的输入 2 ID_SEX OUT VARCHAR2, --性别 3 ID_AGE OUT NUMBER, --年龄 4 ID_BRITHDAY OUT DATE, --出生时间 5 ID_NUMBER_END OUT VARCHAR2, --最后校验的身份证 6 ID_CODE OUT NUMBER, 7 ID_ERROR OUT VARCHAR2) IS 8 9 --15位身份证号组成: 10 --省份(2位)市(2位)区[县](2位)年(2位)月(2位)日(2位)+3位序列号 [奇数给男性/偶数给女性] 11 12 --18位身份证号组成: 13 --省份(2位)市(2位)区[县](2位)年(4位)月(2位)日(2位)+2位序列号+1位性别[奇数男/偶数女]+1位校验码 14 15 --ID_CODE返回值分别为1、-1、-2、-3、-4五类信息,负值表示身份证信息有误 16 --返回1:表示身份证正确。 17 --返回-1:表示系统错误,一般不会出现这个值。 18 --返回-2:表示身份证位数有误。 19 --返回-3:表示出生日期有误或者身份证含有不正确的信息。 20 --返回-4:表示身份证最后一位校验位有误。 21 22 --声明数组变量 23 --声明N数组 用于存放身份证系数(加权因子)7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2 24 TYPE N IS VARRAY(18) OF INTEGER; 25 --声明S数组 用于存放求MOD得的余数\'1\',\'0\',\'X\',\'9\',\'8\',\'7\',\'6\',\'5\',\'4\',\'3\',\'2\' 26 TYPE S IS VARRAY(11) OF VARCHAR2(11); 27 I INTEGER; 28 ID_MONTH NUMBER; --记录身份证上的月份 29 ID_DAY NUMBER; --记录身份证上的日期 30 JQYZ_N N; --将数组N的值赋予JQYZ_N(校验因子) 31 YS_S S; --将数组S的值赋予YS_S(校验余数) 32 ID_SUM INTEGER; --身份证号分别乘以加权因子的总和 33 ID_TMP_15_18 VARCHAR2(18); --存储15位身份证转18位身份证年龄前+19 34 ID_SUM_MOD VARCHAR2(2); --存储加权因子总和MOD11取余数,得到身份证最后一位检验位 35 BEGIN 36 ID_CODE := 1; 37 ID_ERROR := NULL; 38 ID_DAY := 0; 39 ID_MONTH := 0; 40 JQYZ_N := N(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2); 41 YS_S := S(\'1\', \'0\', \'X\', \'9\', \'8\', \'7\', \'6\', \'5\', \'4\', \'3\', \'2\'); 42 ID_SUM := 0; 43 IF LENGTHB(ID_NUMBER) = 15 THEN 44 BEGIN 45 ID_TMP_15_18 := SUBSTRB(ID_NUMBER, 0, 6) || \'19\' || 46 SUBSTRB(ID_NUMBER, 7); --得到18位身份证 47 --循环计算身份证前17位和权加因子的相乘得到的总合 48 FOR I IN 1 .. 17 LOOP 49 ID_SUM := ID_SUM + 50 TO_NUMBER(SUBSTRB(ID_TMP_15_18, I, 1)) * JQYZ_N(I); 51 END LOOP; 52 --将得到的总合除以11得到一个余数,余数对应相应值 53 ID_SUM_MOD := YS_S(MOD(ID_SUM, 11) + 1); 54 --性别取值 55 SELECT DECODE(MOD(TO_NUMBER(SUBSTRB(ID_NUMBER, 15, 1)), 2), 56 0, 57 \'女\', 58 \'男\') 59 INTO ID_SEX 60 FROM DUAL; 61 --出生时间取值 62 ID_MONTH := TO_NUMBER(SUBSTRB(ID_TMP_15_18, 11, 2)); 63 ID_DAY := TO_NUMBER(SUBSTRB(ID_TMP_15_18, 13, 2)); 64 IF (ID_MONTH > 0) AND (ID_MONTH < 13) THEN 65 IF (ID_DAY > 0) AND (ID_DAY <= 31) THEN 66 BEGIN 67 ID_BRITHDAY := TO_DATE(SUBSTRB(ID_TMP_15_18, 7, 8), \'YYYYMMDD\'); 68 EXCEPTION 69 WHEN OTHERS THEN 70 ID_CODE := -1; 71 ID_ERROR := \'出生时间格式有误,请核实。\'; 72 END; 73 ELSE 74 ID_CODE := -3; 75 ID_ERROR := \'您输入日(\' || ID_DAY || \')格式不符合要求(1-31号)\'; 76 END IF; 77 ELSE 78 ID_CODE := -3; 79 ID_ERROR := \'您输入月(\' || ID_MONTH || \')格式不符合要求(1-12月份)\'; 80 END IF; 81 --计算年龄 82 ID_AGE := TRUNC(MONTHS_BETWEEN(SYSDATE, ID_BRITHDAY) / 12); 83 --得出最后身份证号 84 ID_NUMBER_END := ID_TMP_15_18 || UPPER(ID_SUM_MOD); 85 END; 86 ELSIF LENGTHB(ID_NUMBER) = 18 THEN 87 BEGIN 88 --循环计算身份证前17位和权加因子的相乘得到的总合 89 FOR I IN 1 .. 17 LOOP 90 ID_SUM := ID_SUM + TO_NUMBER(SUBSTRB(ID_NUMBER, I, 1)) * JQYZ_N(I); 91 END LOOP; 92 --将得到的总合除以11得到一个余数,余数对应相应值 93 ID_SUM_MOD := YS_S(MOD(ID_SUM, 11) + 1); 94 IF UPPER(SUBSTRB(ID_NUMBER, 18, 1)) != upper(ID_SUM_MOD) THEN 95 ID_CODE := -4; 96 ID_ERROR := \'身份证最后一位校验位有误,应为(\' || ID_SUM_MOD || \')\'; 97 END IF; 98 --性别取值 99 SELECT DECODE(MOD(TO_NUMBER(SUBSTRB(ID_NUMBER, 17, 1)), 2), 100 0, 101 \'女\', 102 \'男\') 103 INTO ID_SEX 104 FROM DUAL; 105 --出生时间取值 106 ID_MONTH := TO_NUMBER(SUBSTRB(ID_NUMBER, 11, 2)); 107 ID_DAY := TO_NUMBER(SUBSTRB(ID_NUMBER, 13, 2)); 108 IF (ID_MONTH > 0) AND (ID_MONTH < 13) THEN 109 IF (ID_DAY > 0) AND (ID_DAY <= 31) THEN 110 BEGIN 111 ID_BRITHDAY := TO_DATE(SUBSTRB(ID_NUMBER, 7, 8), \'YYYYMMDD\'); 112 EXCEPTION 113 WHEN OTHERS THEN 114 ID_CODE := -1; 115 ID_ERROR := \'出生时间格式有误,请核实。\'; 116 END; 117 ELSE 118 ID_CODE := -3; 119 ID_ERROR := \'您输入日(\' || ID_DAY || \')格式不符合要求(1-31号)\'; 120 END IF; 121 ELSE 122 ID_CODE := -3; 123 ID_ERROR := \'您输入月(\' || ID_MONTH || \')格式不符合要求(1-12月份)\'; 124 END IF; 125 --计算年龄 126 ID_AGE := TRUNC(MONTHS_BETWEEN(SYSDATE, ID_BRITHDAY) / 12); 127 --得出最后身份证号 128 ID_NUMBER_END := substrb(ID_NUMBER, 1, 17) || upper(ID_SUM_MOD); 129 END; 130 ELSE 131 ID_CODE := -2; 132 ID_ERROR := \'该身份证号:\' || ID_NUMBER || \' 不符合要求\'; 133 END IF; 134 EXCEPTION 135 WHEN OTHERS THEN 136 ID_CODE := -1; 137 ID_ERROR := \'系统发生未知错误\'; --一般不会发生该错误 138 END PRC_身份证校验;