比较 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”后,查询成功返回了结果。
我有一个查询,我在其中连接日、月、年的各个列以形成 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”后,查询成功返回了结果。