oracle 身份证校验函数

1、正则表达式写法:

  1 CREATE OR REPLACE FUNCTION fn_checkidcard (p_idcard IN VARCHAR2) RETURN INT
2 IS
3 v_regstr VARCHAR2 (2000);
4 v_sum NUMBER;
5 v_mod NUMBER;
6 v_checkcode CHAR (11) := '10X98765432';
7 v_checkbit CHAR (1);
8 v_areacode VARCHAR2 (2000) := '11,12,13,14,15,21,22,23,31,32,33,34,35,36,37,41,42,43,44,45,46,50,51,52,53,54,61,62,63,64,65,71,81,82,91,';
9 BEGIN
10 CASE LENGTHB (p_idcard)
11 WHEN 15
12 THEN -- 15位
13 IF INSTRB (v_areacode, SUBSTR (p_idcard, 1, 2) || ',') = 0 THEN
14 RETURN 0;
15 END IF;
16
17 IF MOD (TO_NUMBER (SUBSTRB (p_idcard, 7, 2)) + 1900, 400) = 0
18 OR
19 (
20 MOD (TO_NUMBER (SUBSTRB (p_idcard, 7, 2)) + 1900, 100) <> 0
21 AND
22 MOD (TO_NUMBER (SUBSTRB (p_idcard, 7, 2)) + 1900, 4) = 0
23 )
24 THEN -- 闰年
25 v_regstr :=
26 '^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$';
27 ELSE
28 v_regstr :=
29 '^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$';
30 END IF;
31
32 IF REGEXP_LIKE (p_idcard, v_regstr) THEN
33 RETURN 1;
34 ELSE
35 RETURN 0;
36 END IF;
37 WHEN 18
38 THEN -- 18位
39 IF INSTRB (v_areacode, SUBSTRB (p_idcard, 1, 2) || ',') = 0 THEN
40 RETURN 0;
41 END IF;
42
43 IF MOD (TO_NUMBER (SUBSTRB (p_idcard, 7, 4)), 400) = 0
44 OR
45 (
46 MOD (TO_NUMBER (SUBSTRB (p_idcard, 7, 4)), 100) <> 0
47 AND
48 MOD (TO_NUMBER (SUBSTRB (p_idcard, 7, 4)), 4) = 0
49 )
50 THEN -- 闰年
51 v_regstr :=
52 '^[1-9][0-9]{5}(19|20)[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}[0-9Xx]$';
53 ELSE
54 v_regstr :=
55 '^[1-9][0-9]{5}(19|20)[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}[0-9Xx]$';
56 END IF;
57
58 IF REGEXP_LIKE (p_idcard, v_regstr) THEN
59 v_sum :=
60 ( TO_NUMBER (SUBSTRB (p_idcard, 1, 1))
61 + TO_NUMBER (SUBSTRB (p_idcard, 11, 1))
62 )
63 * 7
64 + ( TO_NUMBER (SUBSTRB (p_idcard, 2, 1))
65 + TO_NUMBER (SUBSTRB (p_idcard, 12, 1))
66 )
67 * 9
68 + ( TO_NUMBER (SUBSTRB (p_idcard, 3, 1))
69 + TO_NUMBER (SUBSTRB (p_idcard, 13, 1))
70 )
71 * 10
72 + ( TO_NUMBER (SUBSTRB (p_idcard, 4, 1))
73 + TO_NUMBER (SUBSTRB (p_idcard, 14, 1))
74 )
75 * 5
76 + ( TO_NUMBER (SUBSTRB (p_idcard, 5, 1))
77 + TO_NUMBER (SUBSTRB (p_idcard, 15, 1))
78 )
79 * 8
80 + ( TO_NUMBER (SUBSTRB (p_idcard, 6, 1))
81 + TO_NUMBER (SUBSTRB (p_idcard, 16, 1))
82 )
83 * 4
84 + ( TO_NUMBER (SUBSTRB (p_idcard, 7, 1))
85 + TO_NUMBER (SUBSTRB (p_idcard, 17, 1))
86 )
87 * 2
88 + TO_NUMBER (SUBSTRB (p_idcard, 8, 1)) * 1
89 + TO_NUMBER (SUBSTRB (p_idcard, 9, 1)) * 6
90 + TO_NUMBER (SUBSTRB (p_idcard, 10, 1)) * 3;
91 v_mod := MOD (v_sum, 11);
92 v_checkbit := SUBSTRB (v_checkcode, v_mod + 1, 1);
93
94 IF v_checkbit = upper(substrb(p_idcard,18,1)) THEN
95 RETURN 1;
96 ELSE
97 RETURN 0;
98 END IF;
99 ELSE
100 RETURN 0;
101 END IF;
102 ELSE
103 RETURN 0; -- 身份证号码位数不对
104 END CASE;
105 EXCEPTION
106 WHEN OTHERS
107 THEN
108 RETURN 0;
109 END fn_checkidcard;
110 /
111 Show Err;

2、非正则表达式写法

--[Func_checkIdcard]--
Create Or Replace Function Func_checkIdcard (p_idcard in varchar2) Return Number
Is
	v_sum         Number;
	v_mod         Number;
	v_length      Number;
	v_date        Varchar2(10);
	v_isDate      Boolean;
	v_isNumber    Boolean;
	v_isNumber_17 Boolean;
	v_checkbit    CHAR (1);
	v_checkcode   CHAR (11)       := '10X98765432';
	v_areacode    VARCHAR2 (2000) := '11,12,13,14,15,21,22,23,31,32,33,34,35,36,37,41,42,43,44,45,46,50,51,52,53,54,61,62,63,64,65,71,81,82,91,';
	
	--[isNumber]--
	Function isNumber (p_string in varchar2) Return Boolean
	Is
		i			number;
		k			number;
		flag		boolean;
		v_length	number;
	Begin
		/*
		算法:
			通过ASCII码判断是否数字,介于[48, 57]之间。
			select ascii('0'),ascii('1'),ascii('2'),ascii('3'),ascii('4'),ascii('5'),ascii('6'),ascii('7'),ascii('8'),ascii('9') from dual;
		*/
		
		flag := True;
		select length(p_string) into v_length from dual;
		
		for i in 1..v_length loop
			k := ascii(substr(p_string,i,1));
			if k < 48 or k > 57 then
				flag := False;
				Exit;
			end if;
		end loop;
		
		Return flag;
	End isNumber;
	
	--[isDate]--
	Function isDate (p_date in varchar2) Return Boolean
	Is
		v_flag			boolean;
		v_year			number;
		v_month			number;
		v_day			number;
		v_isLeapYear	boolean;
	Begin
		--[初始化]--
		v_flag := True;
		
		--[获取信息]--
		v_year  := to_number(substr(p_date,1,4));
		v_month := to_number(substr(p_date,5,2));
		v_day   := to_number(substr(p_date,7,2));
		
		--[判断是否为闰年]--
		if (mod(v_year,400) = 0) Or (mod(v_year,100) <> 0 And mod(v_year,4) = 0) then
			v_isLeapYear := True;
		else
			v_isLeapYear := False;
		end if;
		
		--[判断月份]--
		if v_month < 1 Or v_month > 12 then
			v_flag := False;
			Return v_flag;
		end if;
		
		--[判断日期]--
		if v_month in (1,3,5,7,8,10,12) and (v_day < 1 or v_day > 31) then
			v_flag := False;
		end if;
		if v_month in (4,6,9,11) and (v_day < 1 or v_day > 30) then
			v_flag := False;
		end if;
		if v_month in (2) then
			if (v_isLeapYear) then
				--[闰年]--
				if (v_day < 1 or v_day > 29) then
					v_flag := False;
				end if;
			else
				--[非闰年]--
				if (v_day < 1 or v_day > 28) then
					v_flag := False;
				end if;
			end if;
		end if;
		
		--[返回结果]--
		Return v_flag;
	End isDate;
Begin
	/*
	返回值说明:
		-1		身份证号码位数不对
		-2		身份证号码出生日期超出范围
		-3		身份证号码含有非法字符
		-4		身份证号码校验码错误
		-5		身份证号码地区码非法
		1		身份证号码通过校验
	*/
	--[长度校验]--
	select lengthb(p_idcard) into v_length from dual;
	if v_length not in (15,18) then
		return -1;
	end if;
	
	--[区位码校验]--
	if instrb(v_areacode, substr(p_idcard, 1, 2)||',') = 0 then
		return -5;
	end if;
	
	--[格式化校验]--
	if v_length = 15 then
		v_isNumber := isNumber (p_idcard);
		if not (v_isNumber) then
			return -3;
		end if;
	elsif v_length = 18 then
		v_isNumber    := isNumber (p_idcard);
		v_isNumber_17 := isNumber (substr(p_idcard,1,17));
		if not ((v_isNumber) or (v_isNumber_17 and upper(substr(p_idcard,18,1)) = 'X')) then
			return -3;
		end if;
	end if;
	
	--[出生日期校验]--
	if v_length = 15 then
		select '19'||substr(p_idcard,7,6) into v_date from dual;
	elsif v_length = 18 then
		select substr(p_idcard,7,8) into v_date from dual;
	end if;
	v_isDate := isDate (v_date);
	if not (v_isDate) then
		return -2;
	end if;
	
	--[校验码校验]--
	if v_length = 18 then
		v_sum :=
		       (  TO_NUMBER (SUBSTRB (p_idcard, 1, 1))
		        + TO_NUMBER (SUBSTRB (p_idcard, 11, 1))
		       )
		     * 7
		   +   (  TO_NUMBER (SUBSTRB (p_idcard, 2, 1))
		        + TO_NUMBER (SUBSTRB (p_idcard, 12, 1))
		       )
		     * 9
		   +   (  TO_NUMBER (SUBSTRB (p_idcard, 3, 1))
		        + TO_NUMBER (SUBSTRB (p_idcard, 13, 1))
		       )
		     * 10
		   +   (  TO_NUMBER (SUBSTRB (p_idcard, 4, 1))
		        + TO_NUMBER (SUBSTRB (p_idcard, 14, 1))
		       )
		     * 5
		   +   (  TO_NUMBER (SUBSTRB (p_idcard, 5, 1))
		        + TO_NUMBER (SUBSTRB (p_idcard, 15, 1))
		       )
		     * 8
		   +   (  TO_NUMBER (SUBSTRB (p_idcard, 6, 1))
		        + TO_NUMBER (SUBSTRB (p_idcard, 16, 1))
		       )
		     * 4
		   +   (  TO_NUMBER (SUBSTRB (p_idcard, 7, 1))
		        + TO_NUMBER (SUBSTRB (p_idcard, 17, 1))
		       )
		     * 2
		   + TO_NUMBER (SUBSTRB (p_idcard, 8, 1)) * 1
		   + TO_NUMBER (SUBSTRB (p_idcard, 9, 1)) * 6
		   + TO_NUMBER (SUBSTRB (p_idcard, 10, 1)) * 3;
		v_mod := MOD (v_sum, 11);
		v_checkbit := SUBSTRB (v_checkcode, v_mod + 1, 1);
		
		if v_checkbit = upper(substrb(p_idcard,18,1)) then
		   return 1;
		else
		   return -4;
		end if;
	else
		return 1;
	end if;
End Func_checkIdcard;
/
Show Err;
原文地址:https://www.cnblogs.com/advocate/p/2312805.html