信息來源:
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