SqlServer2000+ 身份证合法校验函数的代码实例

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

SqlServer2000+ 身份证合法校验函数的代码实例

java爱好者   2020-12-16 我要评论
这篇文章主要介绍了SqlServer2000+ SFZ合法校验函数,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

下面看下sqlserver2000SFZ校验的代码,具体代码如下所示:

/*
身份校验行数
*/
if exists(select * from sysobjects where name='fun_utils_idnumberoprater' and type='FN')
	drop function fun_utils_idnumberoprater
go
create function fun_utils_idnumberoprater
(
@idnumber varchar(50)=''
) 
returns varchar(500)
as
/*
公民身份号码是由17位数字码和1位校验码组成。排列顺序从左至右分别为:6位地址码,8位出生日期码,3位顺序码和1位校验码。
地址码(SFZ地址码对照表见下面附录)和出生日期码很好理解,顺序码表示在同一地址码所标识的区域范围内,对同年同月同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配给女性。
SFZ最后一位校验码算法如下:
1. 将SFZ号码前17位数分别乘以不同的系数,从第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这些个数字,其对应的SFZ最后一位校验码为1 0 X 9 8 7 6 5 4 3 2。
function:
	1.校验SFZ有效性
	2.15位SFZ转18位
*/
begin

	declare @ReturnText varchar(1000) --返回值
			,@Separator varchar(1) --分隔符
			
			,@idnumberElement varchar(1) --SFZ每位元素
			,@CurrentIndex int --SFZ号当前索引位
			,@NextIndex int --SFZ号下一个索引位
			
			,@xsnumber varchar(50) --系数
			,@xsElement varchar(2) --系数每位元素
			,@xsCurrentIndex int --系数当前索引位
			,@xsNextIndex int --系数下一个索引位
			
			,@jym varchar(11) --校验码
			,@sum int --SFZ元素*系数求和
			,@div int --合计对11求余数
			
			,@CurrentJym varchar(1) --当前校验码
			,@CurrentWs int --当前SFZ位数
			,@NewJym varchar(1000) --新校验码
			,@NewWs int --新SFZ位数
			,@oldId varchar(20)

	--处理SFZ号并校验位数有效性
	set @Separator =',';
	set @CurrentIndex = 1;
	set @xsnumber = '7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2';
	set @xsCurrentIndex = 1;
	set @jym = '10X98765432';
	set @sum = 0;
	set @CurrentWs = 0;
	set @CurrentJym = '';
	set @NewJym = '';
	set @NewWs = 0;
	set @CurrentWs=len(@idnumber);
	set @oldId = @idnumber;
	
	
	if @CurrentWs=15
	begin
		set @idnumber=stuff(@idnumber,7,0,case when substring(@idnumber,13,3) in ('999','998','997','996') then '18' else '19' end);
		
		SET @CurrentJym = '';
	end
	else if @CurrentWs>=18
	begin
		set @CurrentJym=substring(@idnumber,18,1);
		set @idnumber=substring(@idnumber,1,17);
	end 
	else
	begin
		set @ReturnText='校验失败_'
		goto TheEnd;
	end
	if isdate(substring(@idnumber,7,8))=0 
	begin
		set @ReturnText='校验失败_'
		goto TheEnd;
	end
	--计算SFZ校验位
	while(@CurrentIndex<=len(@idnumber))
	begin
	 set @NextIndex=@CurrentIndex+1;
		set @xsNextIndex=charindex(@Separator,@xsnumber,@xsCurrentIndex);
		
		if(@xsNextIndex=0 OR @xsNextIndex IS NULL)
			set @xsNextIndex=len(@xsnumber)+1;
		
		set @idnumberElement=substring(@idnumber,@CurrentIndex,@NextIndex-@CurrentIndex);
		set @xsElement=substring(@xsnumber,@xsCurrentIndex,@xsNextIndex-@xsCurrentIndex);
		
		if ISNUMERIC(@idnumberElement) > 0
			set @sum=@sum+cast(@idnumberElement as int)*cast(@xsElement as int)
		else
			begin
				set @ReturnText='校验失败_';
				goto TheEnd
			end

	
		set @CurrentIndex=@CurrentIndex+1;
		set @xsCurrentIndex=@xsNextIndex+1;
		
	end	
	set @div=@sum%11;
	set @NewJym=substring(@jym,@div+1,1);
	--校验SFZ校验位是否出错
	if (@CurrentJym<>'') and (@NewJym<>@CurrentJym)
	begin
		set @ReturnText='校验失败_';
		goto TheEnd
	end
	--输出新的SFZ号
	if len(@oldId) > 18
		set @ReturnText='校验通过,原始SFZ长度非15位或18位_'+(@idnumber+@NewJym)
	else
		set @ReturnText='校验通过,原始SFZ长度为'+cast(len(@oldId) as varchar)+'位_'+(@idnumber+@NewJym)
	goto TheEnd	

TheEnd:
	return @ReturnText
end
go

-- ----------------------以下存储过程是遍历整个表,添加字段并修改校验------------------------


/*
* 一下存储过程是在原表的基础上,添加字段保存校验结果,需要替换掉表明和字段名
*/
-- 表名:a_idcard , 列 idcard 原SFZ, card 标准(新添加),result校验结果(新添加)

-- 添加标准SFZ字段
begin
begin
if not exists (select * from syscolumns where id=object_id('a_idcard') and name='card') 
		alter table a_idcard add [card] varchar(20);
end
-- 添加校验结果字段
begin
if not exists (select * from syscolumns where id=object_id('a_idcard') and name='result') 
alter table a_idcard add [result] nvarchar(20);
end
end
go

--遍历结果
BEGIN
declare @id_card varchar(100), @res varchar(200),@c_index int
declare cur cursor 

for 
	select idcard from a_idcard -- 这里需要替换

open cur
fetch next from cur into @id_card
while @@FETCH_STATUS = 0 
begin 
set @res = dbo.fun_utils_idnumberoprater(@id_card)
set @c_index = charindex('_',@res)
print substring(@res,0,@c_index)
print substring(@res, @c_index+1, len(@res))

-- 这里需要替换
update a_idcard set card=substring(@res, @c_index+1, len(@res)),result=substring(@res,0,@c_index)
where idcard=@id_card

fetch next from cur into @id_card
end 
close cur
deallocate cur
end 
go

PS:下面看下SFZ合法性校验模板

//这个可以验证15位和18位的SFZ,并且包含生日和校验位的验证。 
//如果有兴趣,还可以加上SFZ所在地的验证,就是前6位有些数字合法有些数字不合法。 
function isIdCardNo(num) {
  if(num.indexOf("x")!=-1){
   return false;
  }

 num = num.toUpperCase();
 //SFZ号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X。   
 if (!(/(^\d{15}$)|(^\d{17}([0-9]|X)$)/.test(num))) {
  alert('输入的SFZ号长度不对,或者号码不符合规定!\n15位号码应全为数字,18位号码末位可以为数字或X。');
  return false;
 }
 //校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
 //下面分别分析出生日期和校验位
 var len, re;
 len = num.length;
 if (len == 15) {
  re = new RegExp(/^(\d{6})(\d{2})(\d{2})(\d{2})(\d{3})$/);
  var arrSplit = num.match(re);
  //检查生日日期是否正确
  var dtmBirth = new Date('19' + arrSplit[2] + '/' + arrSplit[3] + '/' + arrSplit[4]);
  var bGoodDay;
  bGoodDay = (dtmBirth.getYear() == Number(arrSplit[2]))
     && ((dtmBirth.getMonth() + 1) == Number(arrSplit[3]))
     && (dtmBirth.getDate() == Number(arrSplit[4]));
  if (!bGoodDay) {
   alert('输入的SFZ号里出生日期不对!');
   return false;
  } else {
   //将15位SFZ转成18位
   //校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。   
   var arrInt = new Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
   var arrCh = new Array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
   var nTemp = 0, i;
   num = num.substr(0, 6) + '19' + num.substr(6, num.length - 6);
   for (i = 0; i < 17; i++) {
    nTemp += num.substr(i, 1) * arrInt[i];
   }
   num += arrCh[nTemp % 11];
   return num;
  }
 }
 if (len == 18) {
  re = new RegExp(/^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/);
  var arrSplit = num.match(re);
  //检查生日日期是否正确
  var dtmBirth = new Date(arrSplit[2] + "/" + arrSplit[3] + "/" + arrSplit[4]);
  var bGoodDay;
  bGoodDay = (dtmBirth.getFullYear() == Number(arrSplit[2]))
     && ((dtmBirth.getMonth() + 1) == Number(arrSplit[3]))
     && (dtmBirth.getDate() == Number(arrSplit[4]));
  if (!bGoodDay) {
   alert(dtmBirth.getYear());
   alert(arrSplit[2]);
   alert('输入的SFZ号里出生日期不对!');
   return false;
  } else {
   //检验18位SFZ的校验码是否正确。
   //校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
   var valnum;
   var arrInt = new Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
   var arrCh = new Array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
   var nTemp = 0, i;
   for (i = 0; i < 17; i++) {
    nTemp += num.substr(i, 1) * arrInt[i];
   }
   valnum = arrCh[nTemp % 11];
   if (valnum != num.substr(17, 1)) {
    alert('18位SFZ的校验码不正确!应该为:' + valnum);
    return false;
   }
   return num;
  }
 }
 return false;
}

总结

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们