Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/77.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL中的有效日期验证_Sql_Db2 - Fatal编程技术网

SQL中的有效日期验证

SQL中的有效日期验证,sql,db2,Sql,Db2,我有一列以(yyyymmdd)的格式保存LossDate。我需要核实,如果该月在30天内结束,则在损失日期为31天的情况下未报告任何损失。我有数百万张唱片。我们将非常感谢您的帮助 LossDate -------- 20120128 20150520 20180631 查询应返回最后一条无效记录,因为200806将在30天后结束。您可以创建一个ISDATE函数,如下所示,然后在查询中使用它,如SELECT*FROM TABLE WHERE DB_IS_DATE(LOSSDATE)=0,以查找所

我有一列以(
yyyymmdd
)的格式保存
LossDate
。我需要核实,如果该月在30天内结束,则在损失日期为31天的情况下未报告任何损失。我有数百万张唱片。我们将非常感谢您的帮助

LossDate
--------
20120128
20150520
20180631

查询应返回最后一条无效记录,因为200806将在30天后结束。

您可以创建一个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
如果输入是有效日期,则可以使用该函数将其转换为日期。例如

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
另一种选择是创建一个UDF,该UDF使用内置Db2函数,但捕获它们可能生成的任何错误。例如

CREATE OR REPLACE FUNCTION IS_DATE(input VARCHAR(32), format VARCHAR(32)) 
RETURNS INTEGER
LANGUAGE SQL CONTAINS SQL DETERMINISTIC ALLOW PARALLEL NO EXTERNAL ACTION
BEGIN 
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING
    RETURN 0;
  RETURN CASE WHEN TO_DATE(input, format) >= '0001-01-01' THEN 1 ELSE 0 END;
END
@

对于您的特定问题,以下将返回错误行:

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且不是闰年的其余行重复此操作。在过去的100年中,任何可以被4整除的年份都是闰年,因此您可以用它来识别剩余的年份(假设您更正/删除了已发现的错误条目):

选择*
从桌子上
其中substr(lossdate,5,2)='02'
和mod(substr(lossdate,1,4),4))0
和substr(lossdate,7,2)>'28'

Column数据类型?它是数值型的,在db2DB2中有一个
LAST_DAY()
函数(),可以让您确定您的
LossDate
是否等于当月的
LAST_DAY
。但是因为它是数值的,所以我认为您必须将它转换为实际日期或正确表示日期的字符串。DB2对待数字实体不同于字符串实体,因为它与“日期”有关,所以20180631可能与“20180631”不同。可以使用
到字符(LossDate)
时间戳格式(到字符(LossDate),'YYYYMMDD')
。但是为什么“日期”值为
20180631
?那不是一个有效的日期?那么,你为什么要在每月最后一天之后的某个日期报告亏损呢?2月份呢?正确,旧系统,数据输入错误,因为没有触发器。因此,我们正在清理无效数据。非常感谢。请注意,如果您正在处理数百万行,我不确定这将如何执行。执行所有mod()和substr()将需要tablescan和一些cpu。为了避免4次不同的扫描,我把WHERE或WHERE条件放在一起(为了避免您的查询将其他查询锁定在外,也许可以使用UR运行它)。我对我的帖子做了一些编辑。上面的一个应该是最终版本(我希望)
select * 
from table 
where substr(lossdate,5,2) = '02' 
    and substr(lossdate,7,2) > '29'
select * 
from table 
where substr(lossdate,5,2) = '02' 
    and mod(substr(lossdate,1,4),4)) <> 0 
    and substr(lossdate,7,2) > '28'