ORA-01841:(完整)年份必须介于 -4713 和 +9999 之间,并且不能为 0 提示
Posted
技术标签:
【中文标题】ORA-01841:(完整)年份必须介于 -4713 和 +9999 之间,并且不能为 0 提示【英文标题】:ORA-01841: (full) year must be between -4713 and +9999, and not be 0 tips 【发布时间】:2020-12-22 16:14:29 【问题描述】:我想对表 test_tbl
的列 DATUM
中大于 01.01.2020 的所有值进行分组。当我运行查询时:
SELECT to_date("DATUM", 'YYYYMM')
FROM test_tbl
WHERE to_date("DATUM", 'YYYYMM') >= to_date('2020-01-01' ,'YYYY-MM-DD')
GROUP BY to_date("DATUM", 'YYYYMM')
我收到以下错误
ORA-01841:(完整)年份必须介于 -4713 和 +9999 之间,并且不能为 0。
表格test_tbl
看起来像:
DATUM (varchar2) |
---|
201701 |
202001 |
201901 |
201801 |
202003 |
当我只运行没有 WHERE CLAUSE 的 GROUP BY 时,日期转换有效,并且没有 NULL 值或类似的东西
SELECT to_date("DATUM", 'YYYYMM')
FROM test_tbl
GROUP BY to_date("DATUM", 'YYYYMM')
`
【问题讨论】:
请用英文转发。 DATUM的数据类型是什么?如果它不是 VARCHAR2,那么您不应该使用 TO_DATE,它将 varchar2 作为其第一个输入参数。 它的 VARCHAR2,当我将列转换为 DATE 数据类型时,我也会收到错误 列DATUM
的数据类型是什么?如果它是VARCHAR2
或数字,那么:为什么要将数据值存储为字符串,请使用正确的DATE
格式。如果它是 DATE
,那么:永远不要在已经是 DATE
的值上调用 TO_DATE
。请详细说明您的问题。
测试数据真的只有5行吗?我问是因为我能够创建您的表、添加 5 行并毫无问题地运行您的查询。结果是 2020-01-01 和 2020-03-01。另外,这里 GROUP BY 的目的是什么?
【参考方案1】:
这是一个数据错误。在 DATUM 列的某处,您有一个无法转换为日期的字符串。当我们将数据存储为错误的数据类型时,这总是存在风险。
如果您使用的是 Oracle 12c R2 或更高版本,您可以使用如下查询轻松定位错误行:
select * from your_table
where validate_conversion(datum as date, 'yyyymm') = 0
如果您使用的是早期版本的数据库,您可以创建一个执行类似操作的函数......
create or replace function is_date(p_str in varchar2
,p_mask in varchar2 := 'yyyymm' ) return number is
n pls_integer;
begin
declare
dt date;
begin
dt := to_date(p_str, p_mask);
n := 1;
exception
when others then
n := 0;
end;
return n;
end;
/
像 validate_conversion()
这样返回 1 表示有效日期,0 表示无效日期。
select * from your_table
where is_date(datum, 'yyyymm') = 0
这种方法更安全,因为它应用了 Oracle 的实际日期验证机制。然而,使用模式匹配正则表达式等让我们对传递无法转换为日期的字符串的弱模式开放。
【讨论】:
++ 我同意 VALIDATE_CONVERSION 是一个更优雅的解决方案。 Validate_Conversion 正在工作,但我只得到一个空结果。所以这意味着它只返回“1”的有效日期。我还能做什么? 第二个解决方案也导致空结果【参考方案2】:您的数据列只需要包含数字数据,以便以您指定的格式作为日期处理。加上最后两位数字需要介于 01 和 12 之间;但这是一个单独的问题,因为您的错误消息是抱怨年份的值。
因此您可以使用以下方法检查无效值:
SELECT
datum
,LENGTH(REGEXP_REPLACE(datum,'[0-9]','')) as char_count
FROM test_tbl
WHERE LENGTH(REGEXP_REPLACE(datum,'[0-9]','')) > 0
;
应该很快地通过 300k 行。
【讨论】:
使用WHERE LENGTH(REGEXP_REPLACE(datum,'[0-9]','')) > 0
可能是最慢的解决方案之一。以上是关于ORA-01841:(完整)年份必须介于 -4713 和 +9999 之间,并且不能为 0 提示的主要内容,如果未能解决你的问题,请参考以下文章
ORA-01841 :(full) year 必须在 -4713 和 +9999 之间,并且在使用 DBMS_SQL 绑定到动态 sql 时不能为 0
oracle 全年度值没有为零 为啥还出 ora-01841