Sql ORA-01841:(完整)年份必须介于-4713和+之间;9999,而不是0个提示

Sql ORA-01841:(完整)年份必须介于-4713和+之间;9999,而不是0个提示,sql,oracle,Sql,Oracle,我想对表test\u 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') 我得到以下错误 OR

我想对表
test\u 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\u tbl
如下所示:

基准面(varchar2) 201701 202001 201901 201801 202003
您的基准列只需要包含数字数据,就可以按照您指定的格式作为日期进行处理。加上最后两位数字需要介于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行。

这是一个数据错误。在基准列的某个地方,有一个不能转换为日期的字符串。当我们将数据存储为错误的数据类型时,这总是一个风险

如果您使用的是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\u conversion()
这将返回1表示有效日期,0表示无效日期

select * from your_table
where is_date(datum, 'yyyymm') = 0

这种方法更安全,因为它应用了Oracle的实际日期验证机制。然而,使用模式匹配正则表达式等使我们容易遇到弱模式,这些弱模式会传递无法转换为日期的字符串。

请用英语重新发布。数据的数据类型是什么?如果它不是VARCHAR2,那么您不应该使用TOU DATE,它将VARCHAR2作为其第一个输入参数。它的VARCHAR2,同样当我将列转换为日期数据类型时,我会得到错误列
数据的数据类型是什么?如果它是一个
VARCHAR2
或数字,那么:究竟为什么要将数据值存储为字符串,请使用适当的
DATE
格式。如果是
日期
,则:决不要对已经是
日期的值调用
TO_DATE
。请详细说明你的问题。真的只有5行测试数据吗?我之所以这样做,是因为我能够创建您的表,添加5行,并毫无疑问地运行您的查询。结果为2020-01-01和2020-03-01。另外,这里分组的目的是什么?++我同意VALIDATE_转换是一个更优雅的解决方案。VALIDATE_转换正在工作,但我只得到一个空结果。这意味着对于有效日期,它只返回“1”。我还能做什么?第二个解决方案也会导致一个空结果,因为
其中长度(REGEXP_REPLACE(datum,[0-9],'')>0
将是最慢的解决方案之一。