-- 声明数组变量
-- 声明 N 数组 用于存放身份证系数(加权因子)7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2
TYPE N IS VARRAY(18) OF INTEGER;
-- 声明 S 数组 用于存放求 MOD 得的余数'1','0','X','9','8','7','6','5','4','3','2'
- TYPE S IS VARRAY(11) OF VARCHAR2(11);
- I INTEGER;
ID_MONTH NUMBER; -- 记录身份证上的月份
ID_DAY NUMBER; -- 记录身份证上的日期
JQYZ_N N; -- 将数组 N 的值赋予 JQYZ_N(校验因子)
YS_S S; -- 将数组 S 的值赋予 YS_S(校验余数)
ID_SUM INTEGER; -- 身份证号分别乘以加权因子的总和
ID_TMP_15_18 VARCHAR2(18); -- 存储 15 位身份证转 18 位身份证年龄前 + 19
ID_SUM_MOD VARCHAR2(2); -- 存储加权因子总和 MOD11 取余数, 得到身份证最后一位检验位
- BEGIN
- ID_CODE := 1;
- ID_ERROR := NULL;
- ID_DAY := 0;
- ID_MONTH := 0;
- JQYZ_N := N(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
- YS_S := S('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
- ID_SUM := 0;
- IF LENGTHB(ID_NUMBER) = 15 THEN
- BEGIN
- ID_TMP_15_18 := SUBSTRB(ID_NUMBER, 0, 6) || '19' ||
SUBSTRB(ID_NUMBER, 7); -- 得到 18 位身份证
-- 循环计算身份证前 17 位和权加因子的相乘得到的总合
- FOR I IN 1 .. 17 LOOP
- ID_SUM := ID_SUM +
- TO_NUMBER(SUBSTRB(ID_TMP_15_18, I, 1)) * JQYZ_N(I);
- END LOOP;
-- 将得到的总合除以 11 得到一个余数, 余数对应相应值
ID_SUM_MOD := YS_S(MOD(ID_SUM, 11) + 1);
-- 性别取值
- SELECT DECODE(MOD(TO_NUMBER(SUBSTRB(ID_NUMBER, 15, 1)), 2),
- 0,
- '女',
- '男')
- INTO ID_SEX
- FROM DUAL;
-- 出生时间取值
- ID_MONTH := TO_NUMBER(SUBSTRB(ID_TMP_15_18, 11, 2));
- ID_DAY := TO_NUMBER(SUBSTRB(ID_TMP_15_18, 13, 2));
- IF (ID_MONTH> 0) AND (ID_MONTH <13) THEN
- IF (ID_DAY> 0) AND (ID_DAY <= 31) THEN
- BEGIN
- ID_BRITHDAY := TO_DATE(SUBSTRB(ID_TMP_15_18, 7, 8), 'YYYYMMDD');
- EXCEPTION
- WHEN OTHERS THEN
- ID_CODE := -1;
- ID_ERROR := '出生时间格式有误, 请核实.';
- END;
- ELSE
- ID_CODE := -3;
- ID_ERROR := '您输入日 (' || ID_DAY || ') 格式不符合要求(1-31 号)';
- END IF;
- ELSE
- ID_CODE := -3;
- ID_ERROR := '您输入月 (' || ID_MONTH || ') 格式不符合要求(1-12 月份)';
- END IF;
-- 计算年龄
ID_AGE := TRUNC(MONTHS_BETWEEN(SYSDATE, ID_BRITHDAY) / 12);
-- 得出最后身份证号
- ID_NUMBER_END := ID_TMP_15_18 || UPPER(ID_SUM_MOD);
- END;
- ELSIF LENGTHB(ID_NUMBER) = 18 THEN
- BEGIN
-- 循环计算身份证前 17 位和权加因子的相乘得到的总合
- FOR I IN 1 .. 17 LOOP
- ID_SUM := ID_SUM + TO_NUMBER(SUBSTRB(ID_NUMBER, I, 1)) * JQYZ_N(I);
- END LOOP;
-- 将得到的总合除以 11 得到一个余数, 余数对应相应值
- ID_SUM_MOD := YS_S(MOD(ID_SUM, 11) + 1);
- IF UPPER(SUBSTRB(ID_NUMBER, 18, 1)) != upper(ID_SUM_MOD) THEN
- ID_CODE := -4;
- ID_ERROR := '身份证最后一位校验位有误, 应为(' || ID_SUM_MOD || ')';
- END IF;
-- 性别取值
- SELECT DECODE(MOD(TO_NUMBER(SUBSTRB(ID_NUMBER, 17, 1)), 2),
- 0,
- '女',
- '男')
- INTO ID_SEX
- FROM DUAL;
-- 出生时间取值
- ID_MONTH := TO_NUMBER(SUBSTRB(ID_NUMBER, 11, 2));
- ID_DAY := TO_NUMBER(SUBSTRB(ID_NUMBER, 13, 2));
- IF (ID_MONTH> 0) AND (ID_MONTH <13) THEN
- IF (ID_DAY> 0) AND (ID_DAY <= 31) THEN
- BEGIN
- ID_BRITHDAY := TO_DATE(SUBSTRB(ID_NUMBER, 7, 8), 'YYYYMMDD');
- EXCEPTION
- WHEN OTHERS THEN
- ID_CODE := -1;
- ID_ERROR := '出生时间格式有误, 请核实.';
- END;
- ELSE
- ID_CODE := -3;
- ID_ERROR := '您输入日 (' || ID_DAY || ') 格式不符合要求(1-31 号)';
- END IF;
- ELSE
- ID_CODE := -3;
- ID_ERROR := '您输入月 (' || ID_MONTH || ') 格式不符合要求(1-12 月份)';
- END IF;
-- 计算年龄
ID_AGE := TRUNC(MONTHS_BETWEEN(SYSDATE, ID_BRITHDAY) / 12);
-- 得出最后身份证号
- ID_NUMBER_END := substrb(ID_NUMBER, 1, 17) || upper(ID_SUM_MOD);
- END;
- ELSE
- ID_CODE := -2;
- ID_ERROR := '该身份证号:' || ID_NUMBER || '不符合要求';
- END IF;
- EXCEPTION
- WHEN OTHERS THEN
- ID_CODE := -1;
ID_ERROR := '系统发生未知错误'; -- 一般不会发生该错误
END PRC_身份证校验;
来源: http://www.linuxidc.com/Linux/2018-07/153130.htm