信息来源:
drop function if EXISTS f_base_check_id_number ; create function `f_base_check_id_number`(number varchar(18)charset utf8) returns int /* -- 作者:黄海 -- 时间:2018-08-21 -- 原理:第一代身份证十五位数升为第二代身份证十八位数的一般规则是:第一步,在原十五位数身份证的第六位数后面插入19 ,这样身份证号码即为十七位数;第二步,按照国家规定的统一公式计算出第十八位数,作为校验码放在第二代身份证的尾号。 -- 校验码计算方法:将身份证前十七位数分别乘以不同系数,从第一至十七位的系数分别为7、9、10、5、8、4、2、1、6、3、7、9、10、5、8、4、2,将这十七位数字和系数相乘的结果相加,用加出来的和除以11,看看余数是多少。余数只可能有0、1、2、3、4、5、6、7、8、9、10这十一个数字,其分别对应的最后一位身份证的号码为1、0、X、9、8、7、6、5、4、3、2,这样就得出了第二代身份证第十八位数的校验码。 -- 测试用例 select f_base_check_id_number('511423198808200077'); */ BEGIN -- 区域码检查结果 declare v_area_result int; -- 出生日期年 declare v_year int; -- 出生日期月 declare v_month int; -- 出生日期日 declare v_date int; -- 判断闰月 declare v_checkdate datetime; -- 前17位 declare v_17 varchar(17); -- 临时变量 declare v_temp int; -- 前17位的系数 declare v_17_xishu varchar(256); -- 前17位乘以系数后的和 declare v_sum_17 int; DECLARE v_i INT ; declare v_current_xishu int; declare v_current_number int; declare v_yushu int; declare v_jiaoyanma VARCHAR(256); declare v_last_jiaoyanma varchar(1); set v_sum_17=0; -- 系数 set v_17_xishu='7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2'; -- 校验码 set v_jiaoyanma='1,0,X,9,8,7,6,5,4,3,2'; set v_i=1; -- 1、判断是不是15位或者18位 IF LENGTH(number)<>18 and LENGTH(number)<>15 then -- -1 代表身份证号长度不是15位,也不是18位 return -1; end if; -- 2、前6位判断 select count(*) into v_area_result from t_dm_region where `code`=substring(number,1,6); if v_area_result<>1 then -- -2 代表地区码错误 return -2; end if; -- 3、如果是18位判断是不是都是数字,如果不都是数字,那前17位是不是数字。 IF LENGTH(number)=18 then SELECT substring(number,1,17) into v_17; end if ; IF LENGTH(number)=15 then SELECT CONCAT(substring(number,1,6),'19',substring(number,7,15)) into v_17; end if ; -- 判断前面N-1位是不是数字 select v_17 REGEXP '[^0-9.]' into v_temp; if v_temp=1 then return -3; end if; -- 4、判断出生年月日 select substring(number,7,4) into v_year; select substring(number,11,2) into v_month; select substring(number,13,2) into v_date; if not (v_year>=1900 and v_year<=DATE_FORMAT(NOW(), '%Y')) then -- -4代表是出生年份错误 return -4; end if; if not (v_month>=1 and v_month<=12) then -- -5代表是出生月份错误 return -5; end if; if not (v_date>=1 and v_date<=31) then -- -6代表是出生日期错误 return -6; end if; -- 判断是不是闰年的日期 SELECT DATE_FORMAT(substring(number,7,8), '%Y-%m-%d') into v_checkdate; if ifnull(v_checkdate,-7)=-7 then return -7; end if; -- 5、判断是不是符合校验码规则 -- 对于前17位,都要遍历一次计算出乘以系数的和 while v_i<=17 do select CAST(substring(number,v_i,1) as signed) into v_current_number; SELECT CAST(substring_index(substring_index(v_17_xishu,',', v_i), ',',-1) as signed) into v_current_xishu; set v_sum_17=v_sum_17+v_current_number*v_current_xishu; set v_i=v_i+1; end while; -- 余数 set v_yushu=v_sum_17 mod 11; SELECT UPPER(substring_index(substring_index(v_jiaoyanma,',', v_yushu+1), ',',-1)) into v_last_jiaoyanma; -- 如果是18位,那么最后一位的检验码是不是正确? IF LENGTH(number)=18 then if upper(substring(number,18,1))=v_last_jiaoyanma then return 1; else return -8; end if; end if ; return 1; END