zoukankan      html  css  js  c++  java
  • oracle 根据身份证号计算出生日期

    1.情景展示

      如何根据身份证号推算出出生日期? 

    2.解决方案

    --根据身份证号计算出生日期
    SELECT DECODE(LENGTH(ID_CARD),
                  18,
                  SUBSTR(ID_CARD, 7, 8),
                  15,
                  '19' || SUBSTR(ID_CARD, 7, 6)) 出生日期
      FROM VIRTUAL_CARD
     WHERE LENGTH(ID_CARD) = 18
        OR LENGTH(ID_CARD) = 15
    

    3.拓展

      根据身份证号,截取出生日期后,更新到该表的birthday(日期类型)字段

      第一步:一个SQL搞定

    UPDATE VIRTUAL_CARD
       SET BIRTHDAY = TO_DATE(DECODE(LENGTH(ID_CARD),
                                     18,
                                     SUBSTR(ID_CARD, 7, 8),
                                     15,
                                     '19' || SUBSTR(ID_CARD, 7, 6)),
                              'yyyymmdd')
     WHERE REMARK = '3';
    

      正常情况下,它会执行没有问题。(没有报错的不用再往下看了)

      但是,现实往往不按我们想象的路子走。

      这个错误的意思是:无效的月份,再直白点是:月份错误,换句话说就是:本来月份有01-12个月,但是按照身份证截取的出生月份超出了这个范围,所以在转换日期的时候报错。

      第二步:删除无效的月份所在行数据

    DELETE FROM VIRTUAL_CARD
     WHERE ID_CARD IN (SELECT ID_CARD
                         FROM (SELECT DECODE(LENGTH(ID_CARD),
                                             18,
                                             SUBSTR(ID_CARD, 11, 2),
                                             15,
                                             SUBSTR(ID_CARD, 9, 2)) MON,
                                      ID_CARD
                                 FROM VIRTUAL_CARD
                                WHERE REMARK = '3')
                        WHERE MON NOT IN ('01',
                                          '02',
                                          '03',
                                          '04',
                                          '05',
                                          '06',
                                          '07',
                                          '08',
                                          '09',
                                          '10',
                                          '11',
                                          '12')) 

      in()函数里,查询出来的是脏数据,我选择删掉。

      再次执行第一步的代码,还是报这个错误。

      既然月份存在的脏数据已经删除,那么是不是日期出了问题?即:天数超出了01-31天,这个范围 

      第三步:删除无效的天数

    DELETE FROM VIRTUAL_CARD
     WHERE ID_CARD IN (SELECT ID_CARD
                         FROM (SELECT /*DISTINCT*/
                                DECODE(LENGTH(ID_CARD),
                                       18,
                                       SUBSTR(ID_CARD, 13, 2),
                                       15,
                                       SUBSTR(ID_CARD, 11, 2)) DA,
                                ID_CARD
                                 FROM VIRTUAL_CARD
                                WHERE REMARK = '3')
                        WHERE DA != 01
                          AND DA != 02
                          AND DA != 03
                          AND DA != 04
                          AND DA != 05
                          AND DA != 06
                          AND DA != 07
                          AND DA != 08
                          AND DA != 09
                          AND DA != 10
                          AND DA != 11
                          AND DA != 12
                          AND DA != 13
                          AND DA != 14
                          AND DA != 15
                          AND DA != 16
                          AND DA != 17
                          AND DA != 18
                          AND DA != 19
                          AND DA != 20
                          AND DA != 21
                          AND DA != 22
                          AND DA != 23
                          AND DA != 24
                          AND DA != 25
                          AND DA != 26
                          AND DA != 27
                          AND DA != 28
                          AND DA != 29
                          AND DA != 30
                          AND DA != 31)

      说明:既可以用in()函数,也可以使用!=,in()方便一些,另外,oracle中的整数类数值型字符串,可以不加""。

      果不其然,日期也有脏数据,再次删掉,执行第一步的代码,还是报错。

      思考:既然日期也搞定了,还有哪会有问题?

      首先,闰年有366天,这说明闰年的2月份有29天,平年有365天,2月份对应28天。

      其次,1,3,5,7,8,10,12,这7个月有31天,4,6,9,11,这4个月有30天。

      to_date()函数,会对其进行严格校验,只有日期无效,就不予转换。

      2019年是平年,2月只有28天,当我设置成29天时,就会报月份无效。

      第四步:删除假闰年数据

    DELETE FROM VIRTUAL_CARD
     WHERE ID_CARD IN (SELECT ID_CARD
                         FROM (SELECT DECODE(LENGTH(ID_CARD),
                                             18,
                                             SUBSTR(ID_CARD, 7, 4),
                                             15,
                                             '19' || SUBSTR(ID_CARD, 7, 2)) YEA,
                                      DECODE(LENGTH(ID_CARD),
                                             18,
                                             SUBSTR(ID_CARD, 11, 2),
                                             15,
                                             SUBSTR(ID_CARD, 9, 2)) MON,
                                      DECODE(LENGTH(ID_CARD),
                                             18,
                                             SUBSTR(ID_CARD, 13, 2),
                                             15,
                                             SUBSTR(ID_CARD, 11, 2)) DA,
                                      ID_CARD
                                 FROM VIRTUAL_CARD
                                WHERE REMARK = '3')
                        WHERE MON = '02'
                          AND DA > 28 /*2月份超过28天*/
                          AND MOD(YEA, 4) != 0) /*余数不为0*/
    

      说明:闰年能够被4整除,2月份为29天,反之,平年超过28天的都是脏数据。

      第五步:删除4,6,9,11月超过30天的数据

    DELETE FROM VIRTUAL_CARD
     WHERE ID_CARD IN
           (SELECT ID_CARD
              FROM (SELECT DECODE(LENGTH(ID_CARD),
                                  18,
                                  SUBSTR(ID_CARD, 11, 2),
                                  15,
                                  SUBSTR(ID_CARD, 9, 2)) MON,
                           DECODE(LENGTH(ID_CARD),
                                  18,
                                  SUBSTR(ID_CARD, 13, 2),
                                  15,
                                  SUBSTR(ID_CARD, 11, 2)) DA,
                           ID_CARD
                      FROM VIRTUAL_CARD
                     WHERE REMARK = '3')
             WHERE (MON IN ('04', '06', '09', '11') AND DA > 30))
    

      再次执行第一步的更新代码,成功更新完毕。

      为了以防万一,先做检验,再提交数据。(在当前窗口执行查询SQL)

      没有毛病,提交数据,大功告成。 

      另外,看到这里,我们对身份证的有效性的校验就又多了一种方式。

      通过截取身份证号的出生日期,利用to_date()函数进行日期转换,转换失败的话,说明该身份证号绝壁有问题。

      还有一种方式是:系统游标批量更新法

      使用游标循环单行更新,捕获异常,继续执行下一条数据更新,直至更新完毕。 

      这样,最后birthday字段没有更新的行数据(字段为空),就是脏数据。

    4.拓展2

      保留身份证号的前4位和后4位,中间部位隐藏。

    SELECT SUBSTR(ID_CARD, 1, 4) ||/*截取前4位*/
           DECODE(LENGTH(ID_CARD), 18, '**********', 15, '*******') ||/*中间用*号代替*/
           SUBSTR(ID_CARD, -4) 身份证号/*截取后4位*/
      FROM VIRTUAL_CARD
     WHERE REMARK = 3
     ORDER BY ADDRESS
    

      

    写在最后

      哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!

     相关推荐:

  • 相关阅读:
    1031.查询-集合操作
    1030.查询-select子句
    1029.查询-复杂分组grouping子句
    1028.查询-group by和having子句
    1027.查询-where子句
    1026.查询-from子句2
    1025.查询-from子句
    1024.查询-概述
    1023.表-数据操作
    图片隐写之stegsolve使用(转载)
  • 原文地址:https://www.cnblogs.com/Marydon20170307/p/10978673.html
Copyright © 2011-2022 走看看