1. 程式人生 > >Oracle身份證校驗函式

Oracle身份證校驗函式

  • Oracle身份證校驗函式
CREATE OR REPLACE FUNCTION FUN_CHECK_SFZ(PRM_SFZ IN VARCHAR2)

  /*---------------------------------------------------------------------------
  *業務環節 :校驗身份證
  * 過程名稱 :FUN_CHECK_SFZ
  * 使用場合 :對身份證號碼進行校驗,通過校驗後返回值為1,也可以返回對應正確的身份證修改205行程式碼
  * 其它說明 :返回值組成 ERRCOD+連線符(-)+表名+編號
  *                      ERRCODE-AC01000:身份證號碼為空錯誤
  *                      ERRCODE-AC01001:身份證號碼地區碼非法
  *                      ERRCODE-AC01002:身份證號碼位數非法
  *                      ERRCODE-AC01003:身份證號碼含有非法字元
  *                      ERRCODE-AC01004:身份證出生日期非法
  *                      ERRCODE-AC01005:身份證號碼校驗碼錯誤
  *
  *
  * 使用要求 :
  * 作    者 :AnQIang
  * 完成日期 :2018年11月07日 11:33:24
  *---------------------------------------------------------------------------
  *---------------------------------------------------------------------------
  * 修 改 人 :                      修改日期 :
  *修改描述 :
  *-------------------------------------------------------------------------*/

 RETURN VARCHAR2 IS

  --變數宣告
  S_SFZ       VARCHAR2(30) DEFAULT ' ';
  I_LEN       INTEGER DEFAULT 0;
  I_VALID     INTEGER DEFAULT 0;
  I_FOR       INTEGER;
  S_VALIDCODE CHAR(1);
  S_BDATE     VARCHAR2(8);
  S_SFZ18     VARCHAR2(18);
  S_SFZ15     VARCHAR2(15);
  S_SFZ17     VARCHAR2(17);
  S_RESULT    VARCHAR2(200);
  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,';
  ----[isDate]----
  FUNCTION FUN_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 FUN_ISDATE;
BEGIN
  S_SFZ    := TRIM(PRM_SFZ);
  I_LEN    := LENGTH(S_SFZ);
  S_RESULT := '1';
  ----------------
  IF S_SFZ IS NULL THEN
    S_RESULT := 'ERRCODE-AC01000:身份證號碼為空錯誤';
    GOTO LABEL_END;
  END IF;
  ----------------------
  ----[地區碼校驗]----
  IF INSTRB(V_AREACODE, SUBSTR(S_SFZ, 1, 2) || ',') = 0 THEN
    S_RESULT := 'ERRCODE-AC01001:身份證號碼地區碼非法';
    GOTO LABEL_END;
  END IF;
  ----[位數校驗]----
  IF I_LEN <> 15 AND I_LEN <> 18 THEN
    S_RESULT := 'ERRCODE-AC01002:身份證號碼位數非法';
    GOTO LABEL_END;
  END IF;
  ----[格式化校驗]----
  IF TRANSLATE(S_SFZ, CHR(0) || '0123456789xX', CHR(0)) IS NOT NULL OR
     TRANSLATE(SUBSTR(S_SFZ, 1, 17), CHR(0) || '0123456789', CHR(0)) IS NOT NULL THEN
    S_RESULT := 'ERRCODE-AC01003:身份證號碼含有非法字元';
    GOTO LABEL_END;
  END IF;
  ----[出生日期校驗]-------
  IF I_LEN = 15 THEN
    IF NOT (FUN_ISDATE('19' || SUBSTR(S_SFZ, 7, 6))) THEN
      S_RESULT := 'ERRCODE-AC01004:身份證出生日期非法';
      GOTO LABEL_END;
    END IF;
  
  END IF;

  IF I_LEN = 18 THEN
    IF NOT (FUN_ISDATE(SUBSTR(S_SFZ, 7, 8))) THEN
      S_RESULT := 'ERRCODE-AC01004:身份證出生日期非法';
      GOTO LABEL_END;
    END IF;
  
  END IF;
  ----[檢查校驗碼]----
  IF I_LEN = 18 THEN
  
    I_FOR := 17;
    WHILE I_FOR > 0 LOOP
      I_VALID := I_VALID + MOD(POWER(2, I_FOR), 11) *
                 TO_NUMBER(SUBSTR(S_SFZ, 18 - I_FOR, 1));
      I_FOR   := I_FOR - 1;
    END LOOP;
    I_VALID := MOD(I_VALID, 11);
    IF I_VALID = 0 THEN
      S_VALIDCODE := '1';
    ELSIF I_VALID = 1 THEN
      S_VALIDCODE := '0';
    ELSIF I_VALID = 2 THEN
      S_VALIDCODE := 'X';
    ELSIF I_VALID = 3 THEN
      S_VALIDCODE := '9';
    ELSIF I_VALID = 4 THEN
      S_VALIDCODE := '8';
    ELSIF I_VALID = 5 THEN
      S_VALIDCODE := '7';
    ELSIF I_VALID = 6 THEN
      S_VALIDCODE := '6';
    ELSIF I_VALID = 7 THEN
      S_VALIDCODE := '5';
    ELSIF I_VALID = 8 THEN
      S_VALIDCODE := '4';
    ELSIF I_VALID = 9 THEN
      S_VALIDCODE := '3';
    ELSIF I_VALID = 10 THEN
      S_VALIDCODE := '2';
    END IF;
    IF S_VALIDCODE <> UPPER(SUBSTR(S_SFZ, 18, 1)) THEN
      S_RESULT := 'ERRCODE-AC01005:身份證號碼校驗碼錯誤';
      GOTO LABEL_END;
    END IF;
  END IF;
  --升位
  IF I_LEN = 15 THEN
    S_SFZ17 := SUBSTR(S_SFZ, 1, 6) || '19' || SUBSTR(S_SFZ, 7, 9);
    I_FOR   := 17;
    WHILE I_FOR > 0 LOOP
      I_VALID := I_VALID + MOD(POWER(2, I_FOR), 11) *
                 TO_NUMBER(SUBSTR(S_SFZ17, 18 - I_FOR, 1));
      I_FOR   := I_FOR - 1;
    END LOOP;
    I_VALID := MOD(I_VALID, 11);
    IF I_VALID = 0 THEN
      S_VALIDCODE := '1';
    ELSIF I_VALID = 1 THEN
      S_VALIDCODE := '0';
    ELSIF I_VALID = 2 THEN
      S_VALIDCODE := 'X';
    ELSIF I_VALID = 3 THEN
      S_VALIDCODE := '9';
    ELSIF I_VALID = 4 THEN
      S_VALIDCODE := '8';
    ELSIF I_VALID = 5 THEN
      S_VALIDCODE := '7';
    ELSIF I_VALID = 6 THEN
      S_VALIDCODE := '6';
    ELSIF I_VALID = 7 THEN
      S_VALIDCODE := '5';
    ELSIF I_VALID = 8 THEN
      S_VALIDCODE := '4';
    ELSIF I_VALID = 9 THEN
      S_VALIDCODE := '3';
    ELSIF I_VALID = 10 THEN
      S_VALIDCODE := '2';
    END IF;
    S_SFZ18 := S_SFZ17 || S_VALIDCODE;
  ELSE
    S_SFZ18 := UPPER(S_SFZ);
  END IF;
  /*IF S_RESULT = '1' THEN
    S_RESULT := S_SFZ18;
  END IF;*/
  <<LABEL_END>>
  RETURN S_RESULT;
END FUN_CHECK_SFZ;