Reputation: 1
I am building a mini project in SQL to automate the load failures occurring due to ORA-12899 - Value too large for the column.
From an error repository table, I can get the error message like the following,
"ORA-12899:value too large for column "SCOTT"."TABLE_EMPLOYEE"."NAME" ( actual 15, maximum:10 )
I would like to use a regular expression such that I can extract the following DDL from the above error message,
ALTER TABLE TABLE_EMPLOYEE MODIFY NAME VARCHAR2(15);
Below is my current code. With this I was able to extract only the schema name i.e "SCOTT"
SELECT REGEXP_SUBSTR('ORA-12899: value too large for column "SCOTT"."TABLE_EMPLOYEE"."NAME" (actual:15 , maximum: 10)','"([^"]+)"',1,1,NULL,1) AS RESULT from DUAL;
Appreciate it if someone can help me with the right regular expression or any other ways of extracting this information
Upvotes: 0
Views: 150
Reputation: 167962
You can use the regular expression:
SELECT REGEXP_REPLACE(
error,
'^.*(".*?"\.".*?")\.(".*?")\s+\(\s+actual:\s+(\d+).*$',
'ALTER TABLE \1 MODIFY \2 VARCHAR2(\3)'
) AS query
FROM table_name
Which, for the sample data:
CREATE TABLE table_name (error) AS
SELECT 'ORA-12899:value too large for column "SCOTT"."TABLE_EMPLOYEE"."NAME" ( actual: 15, maximum: 10 )' FROM DUAL UNION ALL
-- Handle quoted identifiers with numbers
SELECT 'ORA-12899:value too large for column "test1"."actual 20"."VALUE20" ( actual: 25, maximum: 7 )' FROM DUAL;
Outputs:
QUERY |
---|
ALTER TABLE "SCOTT"."TABLE_EMPLOYEE" MODIFY "NAME" VARCHAR2(15) |
ALTER TABLE "test1"."actual 20" MODIFY "VALUE20" VARCHAR2(25) |
Upvotes: 2
Reputation: 142705
Here's one option, which uses only substr + instr
combination.
As of your sample data: that's most probably fabricated. "Real" error message looks like this:
SQL> create table table_employee (name varchar2(10));
Table created.
SQL> insert into table_employee (name) values ('Littlefoot Wiki');
insert into table_employee (name) values ('Littlefoot Wiki')
*
ERROR at line 1:
ORA-12899: value too large for column "SCOTT"."TABLE_EMPLOYEE"."NAME" (actual: 15, maximum: 10)
SQL>
When dealing with such strings, you just need to be precise, otherwise you'll get unexpected (wrong) result.
You : ORA-12899:value too large for column "SCOTT"."TABLE_EMPLOYEE"."NAME" ( actual 15, maximum:10 )
Really: ORA-12899: value too large for column "SCOTT"."TABLE_EMPLOYEE"."NAME" (actual: 15, maximum: 10)
Yet another example (for @MT0's - correct - objection to my previous code) with table and column containing digits:
SQL> create table test15 (col12umn varchar2(2));
Table created.
SQL> insert into test15 values ('abc');
insert into test15 values ('abc')
*
ERROR at line 1:
ORA-12899: value too large for column "SCOTT"."TEST15"."COL12UMN" (actual: 3, maximum: 2)
SQL>
So:
SQL> with test (col) as
2 (select 'ORA-12899: value too large for column "SCOTT"."TEST15"."COL12UMN" (actual: 3, maximum: 2)' from dual union all
3 select 'ORA-12899: value too large for column "SCOTT"."TABLE_EMPLOYEE"."NAME" (actual: 15, maximum: 10)' from dual
4 )
5 select
6 'alter table ' ||
7 substr(col, instr(col, '"', 1, 1),
8 instr(col, '"', 1, 4) - instr(col, '"', 1, 1) + 1
9 ) ||
10 ' modify ' ||
11 substr(col, instr(col, '"', 1, 5),
12 instr(col, '"', 1, 6) - instr(col, '"', 1, 5) + 1
13 ) ||
14 ' varchar2(' ||
15 substr(col, instr(col, ': ', -1, 2) + 2,
16 instr(col, ',', -1, 1) - instr(col, ': ', -1, 2) - 2
17 ) || ')' as result
18 from test;
RESULT
----------------------------------------------------------------------------------------------------
alter table "SCOTT"."TEST15" modify "COL12UMN" varchar2(3)
alter table "SCOTT"."TABLE_EMPLOYEE" modify "NAME" varchar2(15)
SQL>
Upvotes: 0
Reputation: 155
You need to write a PL/SQL block like this:
cl scr
set SERVEROUTPUT ON
declare
err varchar2(3000);
cmnd varchar2(3000);
scma varchar2(100);
tbl varchar2(500);
clm varchar2(200);
N varchar2(100);
begin
err:='ORA-12899:value too large for column "SCOTT"."TABLE_EMPLOYEE"."NAME" ( actual 15, maximum:10 )';
select regexp_substr(err, '\w+', 1, 8) into scma from dual; -- Extract 8th word
select regexp_substr(err, '\w+', 1, 9) into tbl from dual; -- Extract 9th word
select regexp_substr(err, '\w+', 1, 10) into clm from dual; -- Extract 10th word
select regexp_substr(err, '\w+', 1, 12) into N from dual; -- Extract 12th word
cmnd:='ALTER TABLE "'||scma||'"."'||tbl||'" modify "'||clm||'" varchar2('||N||');';
dbms_output.put_line(cmnd);
end;
the result:
ALTER TABLE "SCOTT"."TABLE_EMPLOYEE" modify "NAME" varchar2(15);
Indeed you should generate a dynamic sql as you saw. by this, you can generate any command from information you extract from errors.
Upvotes: 0