身份证号归属地数据库

信息来源:

https://blog.raymondwu.net/2018/05/11/%E8%BA%AB%E4%BB%BD%E8%AF%81%E5%8F%B7%E5%BD%92%E5%B1%9E%E5%9C%B0%E6%95%B0%E6%8D%AE%E5%BA%93/

 

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

 

posted @ 2018-08-21 13:03  糖豆爸爸  阅读(3328)  评论(0编辑  收藏  举报
Live2D