Sysdate 作为 char 而不是 date

Posted

技术标签:

【中文标题】Sysdate 作为 char 而不是 date【英文标题】:Sysdate as char instead of date 【发布时间】:2017-02-19 20:25:07 【问题描述】:

我有一个问题。

我有一个配置表 AB,其中一行标记为“sysdate-360”

col1 ||col2
AB   || sysdate-360
BC   || sysdate -2

当我编写一个程序从我使用的配置表 AB 中获取日期值时。

    v_date varchar(20);
    cursor c1 as
    select col2 from AB;
    then 

    for ab_date in c1
    loop
    select ab_date.col2 into v_date from dual;
v_sql := 'delete from any_table where load_date <='||v_date;
execute immediate v_sql ;
commit;
    end loop;

程序已编译,但当我执行时出现以下错误

ORA-01722: 无效号码 ORA-06512: 在“程序”第 46 行 ORA-06512: 在第 1 行 01722. 00000 - “无效号码” *原因: *行动:

sysdate -360 被视为 char 但不是日期,因为 SYSDATE 本身就是一个日期,对吧?

请帮忙。

【问题讨论】:

大概load_date是一个日期类型。由于您的光标查询看起来不正确,您的混淆有点令人困惑 - 真的是from config_table where col1 = AB吗?并且您没有指出哪一行对应于错误中的第 46 行。 col1 是什么数据类型,因为你让它看起来像一个 varchar?如果它是一个字符串,AB 是一个数字,并且您没有将它括在引号中,并且 col1 的值不是 数字吗?我认为错误来自游标查询,与日期无关...... 我认为您应该对传递给execute immediatev_sql 中的值进行调试。这可能会揭示您的问题,例如 v_sql 中缺少空格。 【参考方案1】:

如果你只处理表达式SYSDATE +/- N 我建议修改配置表如下

ID SYSDATE_OFFSET
-- --------------
AB           -360 
BC             -2 

所以你有一个 sysdate 的数字偏移量,可以这样查询:

select sysdate + (select SYSDATE_OFFSET from config where id = 'AB') s_360
from dual;

S_360           
-----------------
25.02.16 21:46:50 

所以你可以用上面的查询打开一个游标。

如果您无法更改表格 - 定义一个删除字符串 sysdate 并转换为数字的视图!

【讨论】:

让我检查一下,我可以更改配置表。 我现在有另一个问题。我的 v_sql 现在正在给出正确的查询,但是当我在立即执行中运行它时,它给了我以下错误。 00911. 00000 - “无效字符” *原因:标识符不能以字母和数字以外的任何 ASCII 字符开头。在第一个字符之后也允许使用 $#_。用双引号括起来的标识符可以包含除双引号之外的任何字符。替代引号 (q'#...#') 不能使用空格、制表符或回车作为分隔符。 @AmjathAK 使用新配置,您根本不需要立即执行。将 DELTE 中的偏移量作为绑定变量传递。 我必须找到我的表的分区名称,所以所有内容都写在 v_sql 中,包括日期。所以我对 v_sql 的删除查询是从 my_table 分区 (partitionname) 中删除,其中 load_date 要遵循@MarmiteBomber 的建议,您可以在光标上添加一列sysdate - ab.sysdate_offset as maxdate,然后您的删除语句将类似于delete sometable t where t.load_date &lt; ab_date.maxdate。无需动态 SQL。但是,分区的要求是什么?【参考方案2】:

这对我来说看起来很不错。但是为什么选择v_date呢?你从光标中得到一个字符串,你可以直接连接:

for ab_date in c1 loop
  v_sql := 'delete from any_table where load_date <=' || ab_date.col2;
  execute immediate v_sql ;
  commit;
end loop;

最后,这只是两个字符串 'delete from any_table where load_date &lt;=''sysdate-360' 的串联,这使得 'delete from any_table where load_date &lt;= sysdate-360' - 正是您想要的 SQL 字符串。

(如果使用正确的列名,例如 date_expression 而不是 col2,这看起来会更好。)

更详细的解释:光标为您获取字符串“sysdate-360”。查询select ab_date.col2 into v_date from dual; 就是v_date := ab_date.col2;。但是v_date 是字符串吗?如果不是,你会得到一个转换错误,因为 'sysdate-360' 只是一个字符串,仅此而已。如果您希望 DBMS 看到字符串包含“sysdate”,它也恰好是当前时间的系统变量的名称,然后神奇地转换它,那么您期望很高。

【讨论】:

是的,我的 'sysdate-360" 被视为字符串,v_date 是定义的日期。如何使 dbms 将 ssydate 视为系统定义的而不是字符串。 当您使用它来构建 SQL 字符串 时,您无需执行任何操作。我的脚本不适合你吗?【参考方案3】:

试试 to_date 函数

TO_DATE(v_date)

【讨论】:

希望你能好好阅读我的问题。我有一个读取数据的游标,包含“sysdate-360”的列被读取为字符而不是日期 col2 有什么类型?我没有先看到你的程序。你会把它格式化成代码吗?

以上是关于Sysdate 作为 char 而不是 date的主要内容,如果未能解决你的问题,请参考以下文章

sysdate 的 to_date 函数问题

使用 java 而不是 sql 获取当前数据库 sysdate

oracle数据库的sysdate类型怎么转换为字符串

oracle学习

oracle 时间

oracle 怎样把systimestamp 转换成date? 如:2012-11-11 17:20:39