sql 验证身份证号码

功能:
如果输入为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;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值