尝试DML时如何显示列名和列注释

问题描述 投票:0回答:1

我在插入或更新时尝试在表上使用DML操作。我需要在操作失败时显示列名和列注释。例如代码:

CREATE TABLE test_test(col1 VARCHAR2(10), col2 VARCHAR2(100) not null);
DECLARE
  ex_insert_null EXCEPTION;
  PRAGMA EXCEPTION_INIT(ex_insert_null, -1400);
  ex_value_too_large EXCEPTION;
  PRAGMA EXCEPTION_INIT(ex_value_too_large, -12899);
BEGIN
  INSERT INTO test_test
    (col1
    ,col2)
    SELECT CASE
             WHEN LEVEL = 8 THEN
              (LEVEL + 1) || 'qqqqqqqqqqqq'
             ELSE
              (LEVEL + 2) || 'qqq'
           END AS col1
          ,CASE
             WHEN LEVEL = 7 THEN
              NULL
             ELSE
              (LEVEL + 3) || 'wwwwwww'
           END AS col2
      FROM dual
    CONNECT BY LEVEL <= 10;
    COMMIT;
EXCEPTION
  WHEN ex_insert_null THEN
    ROLLBACK;
    dbms_output.put_line('ex_insert_null at ' || ' ' /* || column_name || ' ' || column_comment */);
  WHEN ex_value_too_large THEN
    ROLLBACK;
    dbms_output.put_line('ex_value_too_large at ' || ' ' /* || column_name || ' ' || column_comment */);
END;
/
sql oracle plsql
1个回答
1
投票

正如APC指出的那样,你可以使用“现有的Oracle异常”,例如,如果你有类似......

  procedure insert_( col1 varchar2, col2 varchar2  )
  is
    v_errorcode varchar2(64) ;
    v_errormsg  varchar2(128) ;
  begin
    insert into t ( c1, c2 ) values ( col1, col2 ) ; 
  exception
    when others then
      if sqlcode = -1400 or sqlcode = -12899 then
        v_errorcode := sqlcode;
        v_errormsg  := substr( sqlerrm, 1, 128 );
        dbms_output.put_line( v_errorcode || ' ' || v_errormsg  ) ;
      raise;
     end if;
  end insert_ ;

...你可能会得到如下错误消息:

-1400      ORA-01400: cannot insert NULL into ("MYSCHEMA"."T"."C2") 
-12899     ORA-12899: value too large for column "MYSCHEMA"."T"."C1" (actual: 13, maximum: 10)

如果这对你来说足够了,那很好。但是,您还希望查看列的COMMENTS。虽然我们可以从SQLERRM字符串中获取列名,但使用用户定义的异常可能更可靠(正如您所暗示的那样)。

作为起点,以下DDL和PACKAGE代码可能对您有用。 (另见:dbfiddle here

表:

drop table t cascade constraints ;
drop table errorlog cascade constraints ;

create table t (
  c1 varchar2(10)
, c2 varchar2(64) not null
) ;
comment on column t.c1 is 'this is the column comment for c1';
comment on column t.c2 is 'this is the column comment for c2';

create table errorlog ( 
  when_ timestamp
, msg varchar2(4000) 
) ;

包装规格

create or replace package P is
-- insert into T, throwing exceptions
  procedure insert_( col1 varchar2, col2 varchar2  );
-- use your example SELECT, call the insert_ procedure
  procedure insert_test ;
-- retrieve the column comments from user_col_comments
  function fetch_comment( table_ varchar2, col_ varchar2 ) return varchar2 ;
end P ;
/

包体

create or replace package body P is

  procedure insert_( col1 varchar2, col2 varchar2  )
  is
    ex_value_too_large exception ;  -- T.c1: varchar2(10)
    ex_insert_null exception ;      -- T.c2: cannot be null
    v_errorcol varchar2(32) := '' ;
    v_comment  varchar2(128) := '' ;
    v_tablename constant varchar2(32) := upper('T') ;
  begin
    if length( col1 ) > 10 then
      v_errorcol := upper('C1') ;
      raise ex_value_too_large ;
    end if;
    if col2 is null then
      v_errorcol := upper('C2') ;
      raise ex_insert_null ;
    end if ;
    insert into t ( c1, c2 ) values ( col1, col2 ) ; 
  exception
    when ex_value_too_large then
      dbms_output.put_line( ' ex_value_too_large @ ' 
        || v_errorcol || ' (' || fetch_comment( v_tablename, v_errorcol ) || ')' );
    when ex_insert_null then
      dbms_output.put_line( ' ex_insert_null @ ' 
        || v_errorcol || ' (' || fetch_comment( v_tablename, v_errorcol ) || ')' );
    when others then
      raise ;

  end insert_ ;

  procedure insert_test
  is
  begin
    for rec_ in (
      select
        case 
          when level = 8 then ( level + 1 ) || 'qqqqqqqqqqqq' 
          else ( level + 2 ) || 'qqq'
        end as col1 
      , case
          when level = 7 then null
          else ( level + 3 ) || 'wwwwwww'
        end as col2
      from dual
      connect by level <= 10
    ) loop
      insert_( rec_.col1, rec_.col2 ) ;
    end loop;
    commit;
   end insert_test;

   function fetch_comment( table_ varchar2, col_ varchar2 ) return varchar2
   is
     v_comment varchar2(4000) ; -- same datatype as in user_tab_comments
   begin
      select comments into v_comment 
      from user_col_comments
      where table_name = table_
        and column_name = col_ ;   
      return v_comment ;
   end fetch_comment ;

end P ;
/

要测试包代码,请执行以下匿名块:

begin
 P.insert_test ;
end;
/
-- output
ex_insert_null @ C2 (this is the column comment for c2)
ex_value_too_large @ C1 (this is the column comment for c1)

-- Table T contains:
SQL> select * from T;
C1     C2         
3qqq   4wwwwwww   
4qqq   5wwwwwww   
5qqq   6wwwwwww   
6qqq   7wwwwwww   
7qqq   8wwwwwww   
8qqq   9wwwwwww   
11qqq  12wwwwwww  
12qqq  13wwwwwww

在dbfiddle中,所有输出将分别写入T和ERRORLOG。如果需要,您还可以使用dbms_output.put_line(在dbfiddle中注释掉)。请注意,insert_test过程中的循环游标效率低(我们可以使用BULK操作)。此外,您需要确定处理异常的位置和方式。如上所述,这个例子只是一个起点 - 可能需要进行大量改进。

© www.soinside.com 2019 - 2024. All rights reserved.