功能:
如果输入为15位,如果能转换成相应的18位,则转换并返回18位身份证;
如果输入为18位,经过校验通过后返回18位身份证
如果输入的是非法身份证号,返回‘000’
CREATE OR REPLACE FUNCTION fc_checkid
-- *************************************************************************
-- 功能: 如果输入为15位,如果能转换成相应的18位,则转换并返回18位;如果输入为18位,经过校验通过后返回
-- 输出: 判断居民身份证号码的合法性,将合法的15位身份证号码转换为18位
-- 目前所知的居民身份证号码规则为:
-- 1、长度为18位(新)或者15位(旧)
-- 2、18位的居民身份证最后一位可能是字母'X',其余17位为数字;15位的居民身份证全部由数字组成
-- 3、根据 "ISO7064:1983 MOD11-2" 校验码系统规定的数学关系式计算校验码
-- 输入: 15位或者18位的身份证号码
-- 返回: 18位长度的居民身份证号码
-- *************************************************************************
(
PI_IDIN IN VARCHAR2 -- 身份证号码
) RETURN VARCHAR2
AS
VC_CHARACTER CHAR(1);
VC_DAY VARCHAR2(2);
VC_MONTH VARCHAR2(2);
VC_YEAR VARCHAR2(4);
VC_VERIFYBIT CHAR(1);
VN_SUM NUMBER;
VN_CHECK NUMBER;
VC_IDOUT VARCHAR2(18); --输出的18位
VC_ERRCODE VARCHAR2(8);
VC_ERRMSG VARCHAR2(320);
VE_EXCEPTION EXCEPTION; --创建一个异常
BEGIN
VC_IDOUT := PI_IDIN;
-- *********************************
-- 总体概要判断(是否为空、长度等等)
-- *********************************
IF VC_IDOUT IS NULL THEN
VC_ERRCODE := '0100';
VC_ERRMSG := '输入身份证号码是空值';
RAISE VE_EXCEPTION;
END IF;
IF LENGTHB(VC_IDOUT) <> 15 AND LENGTHB(VC_IDOUT) <> 18 THEN
VC_ERRCODE := '0100';
VC_ERRMSG := '居民身份证号码位数不合法';
RAISE VE_EXCEPTION;
END IF;
-- ****************************
-- 对前面17位的非数字字符的合法性判断, 48---57, 一共是10个数字
-- ****************************
FOR I IN 1..17
LOOP
VC_CHARACTER := SUBSTRB(VC_IDOUT,I,1);
IF ASCII(VC_CHARACTER) < 48 OR ASCII(VC_CHARACTER) > 57 THEN
VC_ERRCODE := '0100';
VC_ERRMSG := '居民身份证号码第'||I||'位存在非数字字符';
RAISE VE_EXCEPTION;
END IF;
END LOOP;
-- ****************************
-- 出生日期的合法性判断
-- ****************************
IF LENGTHB(VC_IDOUT) = 15 THEN --如果为15位,这里构造成17位,然后进行校验
VC_IDOUT := SUBSTR(VC_IDOUT,1,6)||'19'||SUBSTR(VC_IDOUT,7,9);
END IF;
VC_YEAR := SUBSTR(VC_IDOUT,7,4);
VC_MONTH := SUBSTR(VC_IDOUT,11,2);
VC_DAY := SUBSTR(VC_IDOUT,13,2);
IF VC_MONTH > 12 OR
VC_DAY > 31 OR
(VC_MONTH NOT IN ('01','03','05','07','08','10','12') AND VC_DAY = 31) OR
(VC_MONTH = '02' AND VC_DAY > 29) THEN
VC_ERRCODE := '0100';
VC_ERRMSG := '居民身份证号码中出生日期不合法';
RAISE VE_EXCEPTION;
END IF;
-- 闰年的判断
/*
判断闰年的方法是:能被400整除的年是闰年;除能被400整除的年以外,凡是能被4整除,
但不能被100整除的年是闰年。其余年份是平年。
*/
IF NOT (MOD(VC_YEAR,400) = 0 OR ( MOD(VC_YEAR,4) = 0 AND MOD(VC_YEAR,100) <> 0))
AND VC_MONTH = '02'
AND VC_DAY = 29 THEN
VC_ERRCODE := '0100';
VC_ERRMSG := '居民身份证号码中出生日期不合法';
RAISE VE_EXCEPTION;
END IF;
-- ****************************
-- 生成校验位并判断其合法性判断
-- ****************************
-- 取校验码
VN_SUM := 0; --求和
FOR I IN 1..17
LOOP
VN_SUM := VN_SUM + SUBSTR(VC_IDOUT,I,1) * MOD(POWER(2,((19-I)-1)),11);
END LOOP;
VN_SUM := MOD(VN_SUM,11);--取模
VN_CHECK := MOD((12 - VN_SUM),11);--得到校验码
--得到校验码
IF VN_CHECK = 10 THEN
VC_VERIFYBIT := 'X';
ELSE
VC_VERIFYBIT := VN_CHECK;
END IF;
-- 如果是18位,则判断取校验码合法性
IF SUBSTR(VC_IDOUT,18,1) IS NOT NULL AND UPPER(SUBSTR(VC_IDOUT,18,1)) <> VC_VERIFYBIT THEN
VC_ERRCODE := '0100';
VC_ERRMSG := '居民身份证号码中校验位不合法';
RAISE VE_EXCEPTION;
END IF;
-- 将合法的15位身份证号码转换为18位
VC_IDOUT := SUBSTR(VC_IDOUT,1,17)||VC_VERIFYBIT;
-- *******************
-- 成功返回
-- *******************
RETURN VC_IDOUT;
EXCEPTION
WHEN OTHERS THEN
RETURN '000';
END fc_checkid;