PL/SQL - 使用异常插入数据

PL/SQL - Inserting data using Exception

我有以下未正确执行的代码。我将数据存储在 date_tmp (varchar) 中,其中包括日期和非日期。我想将该列中的日期移至 date_run(日期),非日期的数据将移至注释 (varchar) 列。当我 运行 下面的代码时,整个数据集都被移到了注释中。 运行 当我编辑掉插入语句并且只是 运行 dbms_outputline 行时它很好。我可能做错了什么?

DECLARE

  CURSOR getrow IS
  SELECT a.id, a.date_tmp
  FROM mycolumn a 
  WHERE a.id < 1300;

  v_date date;  

BEGIN
  FOR i in getrow LOOP
    BEGIN
      v_date := to_date(i.date_tmp, 'mm/dd/yy');  
      INSERT INTO mycolumn a(a.date_run)
      VALUES(i.date_tmp);

    EXCEPTION
      WHEN OTHERS THEN       
        --dbms_output.put_line(i.date_tmp);
        update mycolumn a
        SET a.comments = i.date_tmp
        where a.id = i.id;
    END;
  END LOOP; 
END;

您尝试将 varchar i.date_tmp 插入日期字段。而是插入 v_date.

...
INSERT INTO mycolumn a (a.date_run)
VALUES(v_date);
...

但其实你的要求是出招。这实际上需要更新。所以我认为你真正想做的是:

...
update mycolumn a
SET a.date_run = v_date
where a.id = i.id    
...

实际上你可以有一个函数来检查你是否有一个有效的日期,然后你可以使用一个简单的更新语句来处理整个任务。

create or replace function is_a_date(i_date varchar2, i_pattern varchar2) 
return date 
is
begin
  return to_date(i_date, i_pattern);
exception
  when others return null;
end is_a_date;

使用该函数,您可以编写两个更新语句

update mycolumn 
   set date_run = to_date(date_tmp,'dd/mm/yy')
 where is_a_date(date_tmp, 'dd/mm/yy') is not null;

update mycolumn 
   set comment = date_tmp
 where is_a_date(date_tmp, 'dd/mm/yy') is null;

我设计函数的方式可以让您以多种方式使用它,因为它 returns 您是一个日期或 null 但如果 varchar 不符合日期模式也不例外。

您有一个 insert,看起来您需要一个 update,就像在异常处理程序中一样。所以只需将其更改为:

  v_date := to_date(i.date_tmp, 'mm/dd/yy');  
  update  mycolumn
      set date_run = v_date
  where   id = i.id;

或者您可以将其缩短为:

  update  mycolumn
      set date_run = to_date(i.date_tmp, 'mm/dd/yy')
  where   id = i.id;

@hol 解决方案对我来说是最好的方法。 如果您可以使用简单的 SQL 语句来完成,请避免始终可以循环和过程,您的代码会更快。 另外,如果你总是有一个数据固定格式,你可以使用 PL/SQL 函数 is_a_date 函数并用 SQL 做所有事情......但是代码变得有点丑陋像这样:

update mycolumn 
   set date_run = to_date(date_tmp,'dd/mm/yy')
     where substr(date_tmp,1,2) between '1' and '31'
      and substr(date_tmp,4,2) between '1' and '12'
      and substr(date_tmp,7,2) between '00' and '99';

如果您需要更快的查询速度或者您在 date_tmp 中有大量数据,因为函数 is_a_date 是确定性的(总是 returns 给定相同的值X,Y,的值),你可以为它创建一个索引:

create index mycol_idx on mycolumn(is_a_date(date_tmp));

并且当您使用该函数时,Oracle 将使用您的索引,就像在那些选择中一样:

SELECT a.id, a.date_tmp
  FROM mycolumn a 
  WHERE a.id < 1300
and is_a_date(a.date_tmp) is not null;

SELECT a.id, a.date_tmp
  FROM mycolumn a 
  WHERE a.id < 1300
  and (is_a_date(a.date_tmp) is not null and is_a_date(a.date_tmp)>sysdate-5);