【问题标题】:Deleting from multiple tables cleanup script SQL从多个表中删除清理脚本 SQL
【发布时间】:2018-04-30 12:29:33
【问题描述】:

答案在底部,最终发现。感谢所有的贡献。

我必须编写一个脚本,然后将其制成一个存储过程,然后每隔几个月运行一次。它需要进入一些特定的表并删除旧记录。我认为这会很简单,但我一直遇到同样的问题。

如果我尝试运行我得到的代码和无效标识符错误,这似乎是日期字段的问题,其中 oracle 默认使用几个月的字母,我尝试了各种日期格式,但我似乎没有上班。

我声明要删除的日期,然后将一条执行立即语句串在一起,该语句将循环遍历包含表名的 tabletoclean 表,以及我将对其进行清理的表的日期字段名称。

错误代码是 ORA-00904:“APR”无效指示符 我猜是因为它尝试使用 APR - APRIL 而不是 04。但我不知道。据我所知,没有一个 dtl_fields 使用月份名称日期格式。

Declare
dtldate date := to_date(add_months( to_date(sysdate), -24 ), 'dd-mm-yy');

Begin
  for tbl IN (Select * from tbltoclean)
loop 

 execute immediate 'Delete from '||tbl.tbl_name || ' where ' || tbl.dtl_field ||' < ' || dtldate;

 DBMS_OUTPUT.PUT_LINE ('Deleted from '|| to_char(tbl.tbl_name));
 end loop;
 end;

如果我在 dbms.output 中运行执行立即字符串,我会返回类似的字符串 Select * from mytable where datefield

确认问题出在日期格式上。

编辑/回答 问题出在 dtldate 变量上。它将日期发布到立即执行,如下所示。

Select * from mytable where datefield

这没用,但是

Select * from mytable where datefield

会工作,所以我编辑了以下代码的字符串。

Declare
dtldate date := add_months( to_date(sysdate), -24 );

Begin
  for tbl IN (Select * from tbltoclean)
loop 

 execute immediate 'Select null from '||tbl.tbl_name || ' where ' || tbl.dtl_field ||' < ' || 'to_date('''||dtldate||''')'; --dtldate have escaped ''

 DBMS_OUTPUT.PUT_LINE ('Deleted from '|| to_char(tbl.tbl_name));
 end loop;
 end;

【问题讨论】:

  • 我认为您必须将 dtldate 标识为变量。
  • 问题是 oracle 没有将 dtldate 识别为日期。我需要在 dtldate 周围加上 ''。以下语句有效 :) 立即执行 'Select null from '||tbl.tbl_name || '在哪里' || tbl.dtl_field ||'
  • 很抱歉让你失望了,@EclecticFish,但你犯了一个又一个错误。 '30-APR-16' 是一个字符串,并且您正在将 DATE 数据类型列(至少,我希望 - 为了您自己的利益 - 它是 DATE)与该字符串进行比较。幸运的是,Oracle 根据您当前的 NLS 设置将字符串隐式转换为日期。一旦它发生变化,您将再次遇到问题。

标签: sql oracle plsql maintainability rowdeleting


【解决方案1】:

SYSDATE是一个返回DATE数据类型的函数;再次将其转换为日期(使用TO_DATE)是没有用的。

所以,这可能会做你想做的事:

declare
  dtldate date := add_months(trunc(sysdate), -24);
begin
  for tbl in (select * from tbltoclean)
  loop 
    execute immediate 'Delete from '||tbl.tbl_name || 
                      ' where ' || tbl.dtl_field ||' < DATE ''' || to_char(dtldate, 'YYYY-MM-DD') || '''';

    dbms_output.put_line ('Deleted from '|| to_char(tbl.tbl_name));
  end loop;
end;

【讨论】:

  • 如果我错了,请纠正我,但不会以这种方式使用dtldate 将其隐式转换为字符串?我想使用' &lt; DATE''' || TO_CHAR(dtldate, 'YYYY-MM-DD') || '''' 可能更安全
  • 啊哈;使用 DATE 文字。我会说你是对的,@David,非常感谢你。 (顺便说一句,对我来说太棒了 - 宣扬一件事,做相反的事情......)
【解决方案2】:

这是处理 DATES 的正确方法:

DECLARE
    --
    DTLDATE DATE;
    --
BEGIN
    --
    DTLDATE := TRUNC(SYSDATE) -- 30/04/2018 14:36 -> 30/04/2018
    --
    DTLDATE := ADD_MONTHS(DTLDATE, -24) -- 30/04/2018 -> 30/04/2016
    --
    FOR TBL IN (SELECT * FROM TBLTOCLEAN) LOOP 
        --
        EXECUTE IMMEDIATE 'DELETE FROM '||TBL.TBL_NAME || 
                          ' WHERE ' || TBL.DTL_FIELD ||' < :DTLDATE' 
          USING DTLDATE;
        DBMS_OUTPUT.PUT_LINE ('DELETED FROM '|| TBL.TBL_NAME);
        --
    END LOOP;
    --
 END;

【讨论】:

  • 嗯,不——你犯了一个错误。这是无效的:DTLDATE := ADD_MONTHS(DTLDATE),ADD_MONTHS 需要另一个参数。 (另外,你忘了用分号结束命令)。
猜你喜欢
  • 2012-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
  • 2018-04-02
相关资源
最近更新 更多