We know that it is best when a single SQL statement can be written for solving a problem. However, your situation requires a SQL statement that would be very unwieldy and difficult to debug and test. One of your comments* contains the following facts:
User can enter anything between 0 to 1000 characters (Data is read
from the excel, and end user do not want any restriction on the
excel). But on our application, we have to show the errors of the
excel.
(* see: https://stackoverflow.com/questions/48839473/oracle-plsql-validate-a-row-and-insert-each-cell-value-of-row-as-a-new-row-with )
My suggestions are: {1} Create a table ("checks") that contains all necessary conditions (checks) including error messages, comments etc. {2} Using PL/SQL and BULK COLLECT to read all rows from this table, and subsequently generate dynamic SQL statements that perform batches of tests (checks) and write their results to a log table (your "table B").
{1}
create table checks (
condition varchar2(256)
, colname varchar2(256)
, errmessage varchar2(256) default 'no error'
);
begin
insert into checks ( condition, colname ) values ( 'LENGTH( column_1 ) <= 7', 'column_1') ;
insert into checks ( condition, colname ) values ( 'LENGTH( column_2 ) <= 75', 'column_2') ;
insert into checks ( condition, colname ) values ( 'LENGTH( column_3 ) <= 17', 'column_3') ;
insert into checks ( condition, colname ) values ( 'LENGTH( column_4 ) <= 17', 'column_4') ;
-- etc
-- etc
-- etc
insert into checks ( condition, colname, errmessage )
values ( 'LENGTH( column_38 ) > 44', 'column_38', 'invalid length' ) ;
insert into checks ( condition, colname, errmessage )
values ( 'LENGTH( column_39 ) > 44', 'column_39', 'invalid length' ) ;
insert into checks ( condition, colname, errmessage )
values ( 'LENGTH( column_40 ) > 44', 'column_40', 'invalid length' ) ;
end;
/
{2}
declare
type checks_t is table of checks%rowtype ;
tchecks checks_t ;
sqlstring varchar2(1000) := '' ;
begin
select condition, colname, errmessage
bulk collect into tchecks
from checks ;
for i in tchecks.first .. tchecks.last
loop
sqlstring := 'insert into b ( column_name, column_value, column_errorKey ) '
|| 'select '
|| ' ( select ''' || tchecks( i ).colname || ''' from dual ), '
|| 'substr( '
|| tchecks( i ).colname || ', 1, 256 ) ,'
|| ' case '
|| ' when ' || tchecks( i ).condition
|| ' then ''' || tchecks( i ).errmessage
|| ''' else ''condition evaluates to FALSE'' end '
|| ' from A' ;
execute immediate sqlstring ;
sqlstring := '' ;
end loop;
end;
/
There is quite a lot of example code in the dbfiddle. However, the first 5 sections are just about test data for "table A", which is supposed to resemble data stored in the spreadsheet (40 columns x 16 rows). With this setup, table B will end up having 1280 rows after the PL/SQL anonymous block has been executed (80 checks are run on each row of table A).
Being a bit wary about the performance of the script, I've done some testing on a smallish VM (Oracle 12c).
Results as follows:
-- table A with 50 rows -> 4000 generated INSERTs into B (80 checks per row)
-- PL/SQL procedure successfully completed.
Elapsed: 00:00:00.050
-- table A with 234256 rows -> 18740480 generated INSERTs into B
-- PL/SQL procedure successfully completed.
Elapsed: 00:02:18.305
SQL> select count(*) from B;
COUNT(*)
18740480
Elapsed: 00:00:25.945
Due to limitations of Oracle 11g (no identity columns) and dbfiddle (could not create a sequence), there are no ID columns or PK constraints anywhere in this example. Also, the error messages (in the checks table) can be a bit misleading, but all that can be "easily" adjusted .