比较 DB2 中的日期

Comparing dates in DB2

我有一个查询,我在其中连接日、月、年的各个列以形成 MM/DD/YYYY 格式的日期,然后使用新连接的列获取 2021 年 12 月 16 日之后的记录( 2021 年 12 月 16 日)。

我曾多次尝试比较日期,但都没有成功。这是我的查询:

select x.* from
(
Select date(to_date(p.PLDRM || '/' || p.PLDRD || '/' || p.PLDRY, 'MM/DD/YYYY')) as Departure_Date,
       date(to_date(p.PLARM || '/' || p.PLARD || '/' || p.PLARY, 'MM/DD/YYYY')) as Arrival_Date,
       date(to_date(p.PLLCM || '/' || p.PLLCD || '/' || p.PLLCY, 'MM/DD/YYYY')) as Change_Date,
       p.*
from post_table p
) x
where x.change_date > date('12/16/2021')

这会导致错误 - 日期、时间或时间戳字符串中的值无效

我敢打赌你的表中有一些无效数据...

例如 0 的月份,或 >= 13。

另一个可能的错误是 02/30 或 02/31 的 MM/DD,甚至是 non-leap 年的 02/29。

最好的办法是定义一个用户定义函数 (UDF) 来为您构建日期,这样您就可以 return NULL 表示无效日期。

您可以选择检查特定的无效日期和return您的用例的有效值。例如,02/30 ==> 02/28 或 02/29(如果是闰年)。

我手边没有任何代码示例,但如果我有时间,我会把一些东西放在一起并编辑这个答案。

UDF 示例

CREATE OR REPLACE FUNCTION DateBuilder (
            mm INTEGER, dd INTEGER, yyyy INTEGER
    )
    RETURNS DATE
    LANGUAGE SQL
    NO EXTERNAL ACTION
    DETERMINISTIC
    RETURNS NULL ON NULL INPUT
    BEGIN
        DECLARE invalidDate CONDITION FOR '22007';
        DECLARE EXIT HANDLER for invalidDate return NULL;
        return to_date(char(yyyy) concat '-' concat char(mm) concat '-' concat char(dd), 'YYYY-MM-DD');
    END;

与@Charles 的想法相同,但使用了一个过程,因为当时我无法在函数主体中使用处理程序(现在还没有检查它是否有效):

CREATE OR REPLACE PROCEDURE castalesce_date_check_(IN strval VARCHAR(100))
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
READS SQL DATA
BEGIN
    DECLARE retval INT DEFAULT 1;
    DECLARE dateval DATE;
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET retval=-1;
    SET dateval=DATE(strval);
    RETURN retval;
END @

CREATE OR REPLACE FUNCTION castalesce_date(strval VARCHAR(100))
RETURNS DATE
DETERMINISTIC
NO EXTERNAL ACTION
READS SQL DATA
BEGIN ATOMIC
  DECLARE retval INT;
  -- The following is needed because declaration of SQLEXECPTION handlers
  -- isn't allowed in UDFs:
  CALL castalesce_date_check_(strval);
  GET DIAGNOSTICS retval = DB2_RETURN_STATUS;
  IF retval = 1 THEN RETURN DATE(strval);
  ELSE RETURN NULL;
  END IF;
END @

db2 connect to ...
db2 -td@ -f ...

db2 "with post_table (PLDRY, PLDRM, PLDRD) as ( 
       values (1999, 12, 28),(1999,0,31),(2001,2,29) 
     ) select p.PLDRY, p.PLDRM, p.PLDRD 
     from post_table p 
     where castalesce_date(p.PLDRY || '-' || p.PLDRM || '-' || p.PLDRD) IS NULL"

PLDRY       PLDRM       PLDRD      
----------- ----------- -----------
       1999           0          31
       2001           2          29

2 record(s) selected.

原来这几天可以大大简化:

CREATE OR REPLACE FUNCTION castalesce_date(strval VARCHAR(100))
     RETURNS DATE
BEGIN
        DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
        BEGIN
                RETURN NULL;
        END;
        RETURN date(strval);
END @

FWIW,我有几个类似的函数用于其他类型,例如 XML。在必须清理暂存数据时,它真的很方便。

更新:

当查询 PLLCM、PLLCD、PLLCY 的不同值时,我发现值之一是“0”(可能是为了避免出现 NULLS)。

在调整查询以避免这三列中出现“0”后,查询成功返回了结果。