【问题标题】:Oracle SQL: ORA-01858 error on date fieldsOracle SQL:日期字段出现 ORA-01858 错误
【发布时间】:2021-09-17 00:13:13
【问题描述】:

我有许多名称中带有日期的表。例如MY_TABLE_2021_06_01, MY_TABLE_2021_06_02, etc。我正在尝试从表名中提取日期,并查看是否有任何表超过一年。这是我的代码:

select * from (
  select
      table_name,
to_date(substr(table_name,-2,2)||'/'||substr(table_name,-5,2)||'/'||substr(table_name,-10,4),'DD/MM/YYYY') TABLE_DATE
  from
      all_tables
  where
      owner = 'my_schema'
      and table_name like '%_20%'
)
where
    TABLE_DATE < trunc(sysdate)-365;

如果我不包含 where 子句 where table_date &lt; trunc(sysdate)-365,上面的代码可以正常工作。如果我使用 where 子句运行代码,那么我会得到

ORA-01858:在需要数字的地方发现了一个非数字字符 01858. 00000 - “在需要数字的地方发现了一个非数字字符” *原因:要使用日期格式模型转换的输入数据是 不正确。输入数据不包含数字 格式模型所要求的。 *行动:修复输入数据或日期格式模型,以确保 元素在数量和类型上匹配。然后重试操作。

我尝试了另一种冗长的方法来查看是否可以让我的代码正常工作,但它仍然会引发相同的错误。我的新代码:

select * from (    
  select table_name, case when table_date < old_date then 1 else 0 end as OLD_TABLE from (
    select
        table_name,
    to_date(substr(table_name,-2,2)||'/'||substr(table_name,-5,2)||'/'||substr(table_name,-10,4),'DD/MM/YYYY') TABLE_DATE,
        trunc(sysdate)-365 OLD_DATE
    from
        all_tables
    where
        owner = 'my_schema'
        and table_name like '%_20%'
    )
 )
where 
    old_table = 1
order by
    old_table desc;

如果我不包含where old_table = 1 子句,上面的代码同样可以正常工作,但在包含 where 子句时会给出相同的 ORA-01858 错误。我不明白这一点,因为字段 OLD_TABLE 不是日期字段,但仍然出现日期格式错误。

【问题讨论】:

  • "I have many tables with a date in their name" - 为什么?这听起来是个坏主意。数据(包括日期)属于表的数据集,而不是其名称。如果这是关于快速访问和删除完整天数,您可以考虑分区表,但不要按日期创建表。
  • @ThorstenKettner,不幸的是不在我手中。这就是源系统生成这些表的方式,我只需要照原样摄取它们。

标签: sql oracle oracle-sqldeveloper


【解决方案1】:

并非所有表都满足这些条件:

      owner = 'my_schema'
  and table_name like '%_20%'

具有“有效”的日期格式,或者它与您使用的格式掩码不匹配。

注意:如果表名是MY_TABLE_2021_06_01,为什么要TO_DATE(..., 'DD/MM/YYYY')

2021_06_01 肯定不是DD/MM/YYYY 格式,而是YYYY_MM_DDYYYY_DD_MM(不知道,06 可以是月或日;01 也是如此)。 也许一旦你修复了这个问题,你的代码就会开始工作。

如果不是,则列出所有名称为 %_20% 的表,并查看其中哪些违反了您设置的规则。


对我有用的示例:首先是示例表:

SQL> CREATE TABLE my_table_2021_06_01
  2  (
  3     id   NUMBER
  4  );

Table created.

SQL> CREATE TABLE some_other_table_2020_02_17
  2  (
  3     id   NUMBER
  4  );

Table created.

查询以提取“名称”超过 1 年的表:

SQL> WITH
  2     tables
  3     AS
  4        (SELECT table_name,
  5                TO_DATE (REGEXP_SUBSTR (table_name, '\d+_\d+_\d+'),
  6                         'yyyy_mm_dd') datum
  7           FROM all_tables
  8          WHERE     owner = 'SCOTT'
  9                AND table_name LIKE '%20%')
 10  SELECT table_name
 11    FROM tables
 12   WHERE datum <= ADD_MONTHS (TRUNC (SYSDATE), -12);

TABLE_NAME
------------------------------
SOME_OTHER_TABLE_2020_02_17

SQL>

【讨论】:

  • 这是我首先检查的,但所有表都满足这些条件。幸运的是,我的表格列表很小,所以我确实手动浏览了每个字段,发现它们都很好。作为健全性检查,我创建了一个名为 TABLE_DATE + 1 的列,并将所有日期增加了一天。如果您查看我的 substr 连接,我会先提取 DD,然后再提取 MM 和 YYYY,这就是为什么我的 TO_DATE 位于 DD/MM/YYYY 中的原因。我一开始确实尝试过 YYYY-MM-DD 并得到了同样的错误。
  • 我添加了一个例子来展示你如何做到这一点;适合我。
  • 我用你的 to_date() 替换了我的 to_date() 并且一切正常:)
  • 太好了,如果有帮助我很高兴。
【解决方案2】:

我会使用这个逻辑来提取日期:

select to_date(substr(table_name, -10) default null on conversion error, 'YYYY_MM_DD')

这应该适用于与sysdate 的比较。

这既能处理与格式不匹配的表名,又能简化日期运算。

【讨论】:

  • 收到ORA-00907: missing right parenthesis 错误
  • @Anish:我想您使用的旧版 Oracle 还不支持 DEFAULT ... ON CONVERSION ERROR 子句
猜你喜欢
  • 1970-01-01
  • 2020-09-17
  • 2017-09-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-06
  • 2015-05-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多