我有一列以{LossDate
)格式保存yyyymmdd
。我需要验证如果该月在30天内结束,那么没有报告损失日期为31的损失。我有数百万条记录。非常感谢您的帮助。
LossDate
--------
20120128
20150520
20180631
查询应返回最后一个无效记录,因为200806在30天内结束。
答案 0 :(得分:1)
您可以在下面创建一个ISDATE函数,然后在诸如SELECT * FROM TABLE WHERE DB_IS_DATE(LOSSDATE) = 0
之类的查询中使用它来查找所有无效日期
CREATE OR REPLACE FUNCTION IS_DATE(YYYYMMDD INTEGER)
RETURNS SMALLINT
LANGUAGE SQL CONTAINS SQL DETERMINISTIC NO EXTERNAL ACTION
RETURN
CASE
WHEN YYYYMMDD/10000 BETWEEN 1 AND 9999
AND( ( MOD(YYYYMMDD/100, 100) IN (1,3,5,7,8,10,12) AND MOD(YYYYMMDD,100) BETWEEN 1 AND 31 ) -- Jan,Mar,May,Jul,Aug,Oct,Dec have 31 days
OR ( MOD(YYYYMMDD/100, 100) IN (4,6,9,11) AND MOD(YYYYMMDD,100) BETWEEN 1 AND 30 ) -- Apr,Jun,Sep,Nov have 30 days
OR ( MOD(YYYYMMDD/100, 100) = 2 AND MOD(YYYYMMDD,100) BETWEEN 1 AND 28 ) -- Feb has 28 days
OR ( MOD(YYYYMMDD/100, 100) = 2 AND MOD(YYYYMMDD,100) BETWEEN 1 AND 29 -- unless is a leap year. i.e.
AND ( ( MOD(YYYYMMDD/10000,4) = 0 AND MOD(YYYYMMDD/10000,100) <> 0) -- year is divisable by 4 but not 100
OR MOD(YYYYMMDD/10000,400) = 0 ) -- or year is divisable by 400
)
)
THEN 1
ELSE 0
END
如果您正在使用Db2 Warehouse,则可以从函数中返回BOOLEAN
。例如
CREATE OR REPLACE FUNCTION IS_DATE(YYYYMMDD INTEGER)
RETURNS BOOLEAN
LANGUAGE SQL CONTAINS SQL DETERMINISTIC NO EXTERNAL ACTION
RETURN
YYYYMMDD/10000 BETWEEN 1 AND 9999
AND( ( MOD(YYYYMMDD/100, 100) IN (1,3,5,7,8,10,12) AND MOD(YYYYMMDD,100) BETWEEN 1 AND 31 ) -- Jan,Mar,May,Jul,Aug,Oct,Dec have 31 days
OR ( MOD(YYYYMMDD/100, 100) IN (4,6,9,11) AND MOD(YYYYMMDD,100) BETWEEN 1 AND 30 ) -- Apr,Jun,Sep,Nov have 30 days
OR ( MOD(YYYYMMDD/100, 100) = 2 AND MOD(YYYYMMDD,100) BETWEEN 1 AND 28 ) -- Feb has 28 days
OR ( MOD(YYYYMMDD/100, 100) = 2 AND MOD(YYYYMMDD,100) BETWEEN 1 AND 29 -- unless is a leap year. i.e.
AND ( ( MOD(YYYYMMDD/10000,4) = 0 AND MOD(YYYYMMDD/10000,100) <> 0) -- year is divisable by 4 but not 100
OR MOD(YYYYMMDD/10000,400) = 0 ) -- or year is divisable by 400
)
)
该函数可用于将输入转换为DATE(如果它是有效日期)。例如
SELECT i, IS_DATE(i) AS IS_DATE
, CASE WHEN IS_DATE(i) = 1 THEN DATE(TO_DATE(DIGITS(DECIMAL(i,8,0)),'YYYYMMDD')) END AS DATE
FROM TABLE(VALUES(-999),(0),(1),(00010101),(99991231),(20180101),(20180228),(20160229),(20180229),(20000229),(19000229)) as D(i)
返回
I IS_DATE DATE
-------- ------- ----------
-999 0 NULL
0 0 NULL
1 0 NULL
10101 1 0001-01-01
99991231 1 9999-12-31
20180101 1 2018-01-01
20180228 1 2018-02-28
20160229 1 2016-02-29
20180229 0 NULL
20000229 1 2000-02-29
19000229 0 NULL
该函数还将接受“ YYYYMMDD”格式的字符串。 db2将为您将字符串转换为整数。 如果您有一个字符串例如“ YYYY-MM-DD”格式,则可以创建调用上述函数的函数的字符版本,例如
CREATE OR REPLACE FUNCTION IS_DATE(YYYYMMDD VARCHAR(10))
RETURNS INTEGER
LANGUAGE SQL CONTAINS SQL DETERMINISTIC NO EXTERNAL ACTION
RETURN
CASE WHEN REGEXP_LIKE(YYYYMMDD,'[0-9]{4}?-[0-9]{2}?-[0-9]{2}?') = 1
THEN IS_DATE(INTEGER(REPLACE(YYYYMMDD,'-',''))) ELSE 0 END
;
答案 1 :(得分:0)
对于您的特定问题,以下内容将返回错误的行:
select *
from table
where substr(lossdate,5,2) in ('04','06','09','11')
and substr(lossdate,7,2) > '30'
根据您的输入界面,您可能需要重复31个月才能显示大于31的值。
select *
from table
where substr(lossdate,5,2) in ('01','03','07','08','10','12')
and substr(lossdate,7,2) > '31'
二月有点棘手。逐步开始,确定29天内的所有2月条目,您可以立即删除/修复这些条目。
select *
from table
where substr(lossdate,5,2) = '02'
and substr(lossdate,7,2) > '29'
然后,您需要对2月日期大于28且不是year年的其余行重复此操作。在过去的100年中,任何可被4整除的年份都是a年,因此您可以使用此标识剩余的年份(假设您更正/删除了已经找到的不良2月条目):
select *
from table
where substr(lossdate,5,2) = '02'
and mod(substr(lossdate,1,4),4)) <> 0
and substr(lossdate,7,2) > '28'