【hive】异常日期查找

1.日期转化为时间戳

只取前面符合日期格式的内容转为时间戳,超出格式的部分忽略,少于格式则格式不符合,date_format也是一样的

select unix_timestamp('2022-2-2', 'yyyy-MM-dd') = unix_timestamp('2022-2-2-2', 'yyyy-MM-dd') --true
select unix_timestamp('2022-2', 'yyyy-MM-dd') --null

2.正则表达式

regexp和rlike一样,rlike与like不同的是可以匹配正则表达式

(1)位置匹配:
(^) 表示匹配字符串的开始,空值:^$
($) 表示匹配字符串的结束

^或者$写一个就够了

(2)元字符匹配
(.)   表示匹配除换行符以外的任意字符。
(\w) 表示匹配字母、下划线、数字或汉字(\\W)。
(\d) 表示匹配数字
(\s) 表示匹配任意的空白符
([ ])  表示匹配方括号中任一字符
([^匹配内容]) 表示不匹配方括号中任一字符

({ })重复几次

匹配日期:

//限制格式:XXXX-X(X)-X(X)
select birthday not rlike '^\\d{4}-\\d{1,2}-\\d{1,2}$'
//限制格式:19(或者20)XX-XX-XX(月、日)在正常范围内
select birthday not rlike '([1][9]|[2][0])([0-9]{2})-([1-9]|(0[1-9])|1[0-2])-([1-9]|(0[1-9])|([1-2][0-9])|30|31)$'

3.split、size

split可以切分日期,返回的是数组形式,可以取某一个的元素,split(birthday, '-')[0]

用size可以获取这个数组大小,也就可以判断是否符合日期格式

4.总体思路

日期为空值(null)或者空都是正常,其他为异常

分为四种情况考虑:

  1. 按 '-' 切分得到的切分数不为3
  2. 不符合规定的正则表达式,年份做了一点限制;月份和日限制在正常范围,但是有些月没有31号,需要之后再限制
  3. 月和日不符合正常日期,把有些月没有31号的情况等做限制

5.优化

分的情况分别做交叉,a left join b where a.accountname is null

两个数据集理论上存在几种关系
1, 没关系
2,部分包含(交集)
3,全包含(子集)

如果存在子集 ,子集对应的条件就能被替代掉。

这里切分数那种情况可以去掉,因为第二种情况已经确定好切分数是3了

with tmp1 as (
  select accountname, birthday
  from xsj_acc_real_identity_en
  where dt = '2022-07-10'
  and birthday is not null 
  and birthday != ''
  and size(split(birthday, '-')) = 3
  and birthday not rlike '([1][9]|[2][0])([0-9]{2})-([1-9]|(0[1-9])|1[0-2])-([1-9]|(0[1-9])|([1-2][0-9])|30|31)$'
  ),
  tmp2 as (
  select accountname, birthday
  from xsj_acc_real_identity_en
  where dt = '2022-07-10'
  and birthday is not null 
  and birthday != ''
  and size(split(birthday, '-')) = 3
  and unix_timestamp(date_format(birthday, 'yyyy-MM-dd'), 'yyyy-MM-dd') != unix_timestamp(birthday, 'yyyy-MM-dd')
  ),
  tmp3 as (
  select accountname, birthday
  from xsj_acc_real_identity_en
  where dt = '2022-07-10'
  and birthday is not null 
  and birthday != ''
  and size(split(birthday, '-')) = 3
  and split(birthday, '-')[0] not between 1900 and 2022
  )
select tmp3.birthday
from tmp3
left join tmp2
on tmp2.accountname = tmp3.accountname
where tmp2.accountname is null;

select birthday
from xsj_acc_real_identity_en
where dt = '2022-07-10'
and birthday is not null 
and birthday != ''
and size(split(birthday, '-')) = 3
and (
birthday not rlike '([1][9]|[2][0])([0-9]{2})-([1-9]|(0[1-9])|1[0-2])-([1-9]|(0[1-9])|([1-2][0-9])|30|31)$'
or split(birthday, '-')[0] not between 1900 and 2022
)

猜你喜欢

转载自blog.csdn.net/weixin_43955488/article/details/125891639