How to execute the output result for execute immediate statment - oracle

From the below query i am getting the output as below. but i am expecting the output result like the output select query to be executed again and provide the result .
Also, i want to remove the UNION ALL from last line of the output like this
select A from Table1 Union all
Select A from table2 Union All
Select A from table3 Union all
Select A from table4;
Query :
SET SERVEROUTPUT ON
Declare
v_sql varchar2(500);
v_sql2 varchar2(500);
v_prj_id varchar2(4000):='ProjectA,ProjectB,ProjectC,ProjectD';
BEGIN
Dbms_Output.Put_Line('v_prj_id='||v_prj_id);
--
FOR i IN (SELECT trim(regexp_substr(v_prj_id, '[^,]+', 1, LEVEL)) l
FROM dual
CONNECT BY LEVEL <= regexp_count(v_prj_id, ',') + 1
) LOOP
v_sql := 'select '''|| i.l ||''' AS "PRJ_ID", EVENT, email,modified_by,modified from ' || i.l ||
'.Table UNION ALL';
Dbms_Output.Put_Line (v_sql);
--
END LOOP;
EXECUTE IMMEDIATE v_sql ;
v_sql2 := RTRIM (v_sql, 'UNION ALL');
EXECUTE IMMEDIATE v_sql2 ;
Dbms_Output.Put_Line (v_sql2);
END;
/
Output :
select 'ProjectA' AS "PRJ_ID", EVENT, email,modified_by,modified from ProjectA.event UNION ALL
select 'ProjectB' AS "PRJ_ID", EVENT, email,modified_by,modified from ProjectB.event UNION ALL
select 'ProjectC' AS "PRJ_ID", EVENT, email,modified_by,modified from ProjectC.event UNION ALL
select 'ProjectD' AS "PRJ_ID", EVENT, email,modified_by,modified from ProjectD.event UNION ALL

EXECUTE IMMEDIATE will not provide you the SELECT statement results.
From Oracle Docs
If dynamic_sql_statement is a SELECT statement, and you omit both into_clause and bulk_collect_into_clause, then execute_immediate_statement never executes.
You have use SELECT INTO clause or BULK_COLLECT_INTO_CLAUSE and assign the values to some variable if you want to see the results of EXECUTE IMMEDIATE select values.
Something like below for single row
SET SERVEROUTPUT ON
DECLARE
L_RESULT VARCHAR2(20);
BEGIN
VSQL:= --YOUR LOGIC
EXECUTE IMMEDIATE VSQL INTO L_RESULT;
DBMS_OUTPUT.PUT_LINE(L_RESULT);
END;
/
For Multiple rows
DECLARE
TYPE T IS TABLE OF MYTABLE.ID%TYPE INDEX BY PLS_INTEGER;
MYROW T;
BEGIN
VSQL:= --YOUR LOGIC
EXECUTE IMMEDIATE VSQL BULK COLLECT INTO MYROW;
DBMS_OUTPUT.PUT_LINE(MYROW.XXX);
END;
/

You are doing everything right except concatenating the v_sql with original string -
SET SERVEROUTPUT ON
Declare
v_sql varchar2(500);
v_sql2 varchar2(500);
v_prj_id varchar2(4000):='ProjectA,ProjectB,ProjectC,ProjectD';
BEGIN
Dbms_Output.Put_Line('v_prj_id='||v_prj_id);
--
FOR i IN (SELECT trim(regexp_substr(v_prj_id, '[^,]+', 1, LEVEL)) l
FROM dual
CONNECT BY LEVEL <= regexp_count(v_prj_id, ',') + 1
) LOOP
v_sql := v_sql || ' select '''|| i.l ||''' AS "PRJ_ID", EVENT, email, modified_by, modified from ' || i.l ||
'.Table UNION ALL';
Dbms_Output.Put_Line (v_sql);
--
END LOOP;
EXECUTE IMMEDIATE v_sql ;
v_sql2 := RTRIM (v_sql, 'UNION ALL');
EXECUTE IMMEDIATE v_sql2 ;
Dbms_Output.Put_Line (v_sql2);
END;
/

Related

error ORA-00998: must name this expression with a column alias

I tried to create table from all_tab_columns but it throws me an error.
like error ORA-00998: must name this expression with a column alias.
i tried to figure it out but not working.
Declare
CURSOR c1 IS
SELECT COLUMN_NAME FROM (select 'standard_hash(MY_NAME) AS MY_NAME' COLUMN_NAME from DUAL
UNION
SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS WHERE TABLE_NAME='TABLE1' AND COLUMN_NAME<>'MY_NAME');
cols c1%ROWTYPE;
sqlstmt VARCHAR2(4000);
BEGIN
OPEN c1;
LOOP
FETCH c1 into cols;
EXIT WHEN c1%NOTFOUND;
sqlstmt := sqlstmt ||cols.column_name||',';
END LOOP;
CLOSE c1;
sqlstmt := 'CREATE TABLE TABLE2 AS SELECT '||substr(sqlstmt, 1, length(sqlstmt)-1)||' FROM TABLE1';
DBMS_OUTPUT.PUT_LINE(sqlstmt);
EXECUTE IMMEDIATE sqlstmt;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('error '||sqlerrm);
END;
/
You just have to give the name to the expression as follows:
sqlstmt := 'CREATE TABLE TABLE2 AS SELECT '
||substr(sqlstmt, 1, length(sqlstmt)-1)
||' as column_name FROM TABLE1'; -- column_name will bre name of the column of new table
As it will become the name of the column of newly created table.
I think this can be simplified somewhat.
You don't need to declare an explicit cursor and a record type and fetch each row into it, as this is already built into the language as the Cursor FOR loop construction:
declare
sqlStmt long := 'create table table2 as select ';
begin
for r in (
select 'standard_hash(my_name) as my_name' column_name
from dual
union
select column_name
from all_tab_columns
where table_name = 'TABLE1'
and column_name <> 'MY_NAME'
)
loop
sqlStmt := sqlStmt || r.column_name || ', ';
end loop;
sqlStmt := sqlStmt || rtrim(sqlStmt,', ') || ' from table1';
dbms_output.put_line(sqlStmt);
execute immediate sqlStmt;
end;
/
But you can do this without any loop, as the listagg function can already build a comma-separated list for you. It also makes it easier to retain the order of columns in the original table.
declare
selectList long;
sqlStmt long;
begin
select listagg(
case column_name
when 'MY_NAME' then 'standard_hash(my_name) as my_name'
else lower(column_name)
end, ', '
) within group (order by column_id) as select_list
into selectList
from user_tab_columns c
where c.table_name = 'TABLE1';
sqlStmt :=
'create table table2 pctfree 0 nologging parallel as '||chr(10)||
'select '||selectList||chr(10)||
'from table1';
dbms_output.put_line(sqlStmt||';');
execute immediate sqlstmt;
end;

ORA-00904 invalid identifier error in dynamic SQL block

I'm running the below which once executed, an error is reported telling me that EST_ONE_ROW_MB is an invalid identifier.
I've been advised I perhaps need to get the dynamic SQL part running as a stand alone query to begin with as an initial troubleshooting exercise but I'm a bit stumped in terms of how to write a sub-query here that will produce the desired output and eliminate the error.
create or replace procedure JUST_ME is
--variables
l_dblink varchar2(100) := 'DB1';
file_handle UTL_FILE.file_type;
v_ts_name varchar2(30);
v_link_name varchar2(10);
v_csv_name varchar2(100);
EST_ONE_ROW_MB varchar2(100) ;
TOTAL_ROW_COUNT NUMBER;
SPACE_REQUIRED NUMBER;
TOT_OBJECT_SIZE_MB NUMBER;
v_Mv_name varchar2(100);
v_sql1 varchar2(1500);
cur SYS_REFCURSOR;
owner varchar2(100);
table_name varchar2(100);
driver_table varchar2(100);
mandatory_join varchar2(100);
C_TOTAL_ROW_COUNT varchar2(100);
v_total_driver_only varchar2(100);
--
begin
SELECT tablename into v_csv_name
FROM BOB01.BOB_new_table_tracker
WHERE
CREATED_AT = (select MAX(CREATED_AT) from BOB01.BOB_new_table_tracker);
SELECT mv_name into v_Mv_name
FROM BOB01.BOB_new_table_tracker_mv
WHERE
CREATED_AT = (select MAX(CREATED_AT) from BOB01.BOB_new_table_tracker_mv);
select link_name into v_link_name from link_and_mail where mdate = (select max(mdate) from link_and_mail);
select distinct targetschema into v_ts_name from BOB01.MV_BOB_TABLE;
v_sql1 := 'SELECT /*+ monitor parallel (4)*/ a.owner,
a.table_name,
b.driver_table,
b.mandatory_join,
sum(c.sum_bytes) TOT_OBJECT_SIZE_MB,
(TOT_OBJECT_SIZE_MB) / (:C_TOTAL_ROW_COUNT) AS "EST_ONE_ROW_MB",
(EST_ONE_ROW_MB) * (:TOTAL_ROW_COUNT) AS "SPACE_REQUIRED"
FROM dba_tables#DB1 a, '|| v_Mv_name ||' b, MV_PRD_SEG_DATA c
WHERE a.table_name IN ( SELECT table_name
FROM MV_BOB_TABLE
WHERE driver_table IS NOT NULL
AND additional_joins IS NULL
)
AND a.owner IN ( SELECT DISTINCT productionschema FROM MV_BOB_TABLE c )
and a.table_name = b.table_name
and a.table_name = c.segment_name
group by a.owner,a.table_name,b.driver_table,b.mandatory_join
ORDER BY table_name';
file_handle := utl_file.fopen('ESTIMATES_CSV', v_csv_name||'_EST_PROC.csv', 'w', 32767);
--
UTL_FILE.PUT_LINE(file_handle, ' ');
UTL_FILE.PUT_LINE(file_handle, 'The below report shows total row counts in PROD');
UTL_FILE.PUT_LINE(file_handle, ' for unjoined tables in the BOB document:');
UTL_FILE.PUT_LINE(file_handle, ' ');
utl_file.put_line(file_handle, 'OWNER,TABLE_NAME,MANDATORY_JOIN,TOT_OBJECT_SIZE_MB,EST_ONE_ROW_MB,TOTAL_ROW_COUNT,SPACE_REQUIRED');
--main loop
open cur for v_sql1 using TOTAL_ROW_COUNT,C_TOTAL_ROW_COUNT;
loop
fetch cur into OWNER,TABLE_NAME,MANDATORY_JOIN,TOT_OBJECT_SIZE_MB,EST_ONE_ROW_MB,TOTAL_ROW_COUNT,SPACE_REQUIRED;--,EST_ONE_ROW_MB;
exit when cur%NOTFOUND;
execute immediate' select /*+parallel (4)*/ count(*) from '||owner||'.'||table_name || '#' || l_dblink into TOTAL_ROW_COUNT;
execute immediate' select /*+monitor parallel (10)*/ count(*) from ' ||owner||'.'||table_name || '#' || l_dblink||' b '||','||
driver_table || '#' || l_dblink||' a ' ||' where ' ||mandatory_join into TOTAL_ROW_COUNT;
execute immediate' select /*+monitor parallel (10)*/ count(*) from ' ||owner||'.'||table_name || '#' || l_dblink into C_TOTAL_ROW_COUNT;
utl_file.put_line(file_handle,
OWNER || ',' ||
TABLE_NAME || ',' ||
TOT_OBJECT_SIZE_MB || ',' ||
TOTAL_ROW_COUNT || ',' ||
C_TOTAL_ROW_COUNT || ',' ||
round(TOT_OBJECT_SIZE_MB / C_TOTAL_ROW_COUNT,7)|| ',' ||
round(round(TOT_OBJECT_SIZE_MB / C_TOTAL_ROW_COUNT,7) * round(TOTAL_ROW_COUNT,0),0)
);
v_total_driver_only := v_total_driver_only + round(TOT_OBJECT_SIZE_MB / C_TOTAL_ROW_COUNT,7) * round(TOTAL_ROW_COUNT,0);
end loop;
UTL_FILE.PUT_LINE(file_handle, ' ');
utl_file.put_line(file_handle,
'Total Estimated Space Required '|| round(v_total_driver_only,0) ||' MB'
);
utl_file.fclose(file_handle);
end JUST_ME;
to use EST_ONE_ROW_MB on that way is not possible because its' not defied as column.
replace it by (TOT_OBJECT_SIZE_MB) / (:C_TOTAL_ROW_COUNT)
SELECT /*+ monitor parallel (4)*/ a.owner,
a.table_name,
b.driver_table,
b.mandatory_join,
sum(c.sum_bytes) TOT_OBJECT_SIZE_MB, -- will be the same problem
(sum(c.sum_bytes)) / (:C_TOTAL_ROW_COUNT) AS "EST_ONE_ROW_MB",
((sum(c.sum_bytes)) / (:C_TOTAL_ROW_COUNT)) * (:TOTAL_ROW_COUNT) AS "SPACE_REQUIRED"
...
you can do that if you have an Inline View. e.g.
select EST_ONE_ROW_MB * (:TOTAL_ROW_COUNT) AS "SPACE_REQUIRED"
from(
select (TOT_OBJECT_SIZE_MB) / (:C_TOTAL_ROW_COUNT) AS "EST_ONE_ROW_MB"
from ....
)

Oracle PL/SQL Swapping a for loop for dynamic SQL, assistance with syntax changes

I have a for loop, here:
BEGIN
for rws in (
select /*+parallel (4)*/ a.owner,a.table_name, round(sum(b.sum_bytes),2) TOT_OBJECT_SIZE_MB, EST_ONE_ROW_MB
from dba_tables#DB1 a, MV_PRD_SEG_DATA b
where a.table_name = b.segment_name
and a.table_name in
(select table_name from MV_PDU_TABLE where driver_table is null)
and a.owner in (select distinct productionschema from MV_PDU_TABLE c)
group by a.owner,a.table_name
order by a.table_name
)
loop
Data is pulled out of the loop as follows by referencing rws. :
execute immediate' select /*+parallel (4)*/ count(*) from ' ||rws.owner||'.'||rws.table_name || '#' || dblink into TOTAL_ROW_COUNT;
I now have to change some of the hard coded table references in the select statement to variables. (I will be declaring these earlier in the code.)
As I understand it, I must now switch to dynamic SQL.
In doing so, you can see here how the hard coded tables are now referred to as variables:
BEGIN
v_sql1 := 'select /*+parallel (4)*/ a.owner,a.table_name, round(sum(b.sum_bytes),2) TOT_OBJECT_SIZE_MB, EST_ONE_ROW_MB
from dba_tables#NAB1 a, '|| v_Mv_name ||' b
where a.table_name = b.segment_name
and a.table_name in
(select table_name from '|| v_Mv_name ||' where driver_table is null)
and a.owner in (select distinct productionschema from '|| v_Mv_name ||' c)
group by a.owner,a.table_name
order by a.table_name';
The issue is... how do I now manage getting the data out of the loop? I think I would loop, just using the variable containing the SQL?:
for rws in (v_sql1)
loop
If so, what would now go here?
execute immediate' select /*+parallel (4)*/ count(*) from ' <NO_IDEA_HOW_TO_REFERENCE_THE_DATA_IN_THE_LOOP_NOW> ' into TOTAL_ROW_COUNT;
You can also use a RefCursor:
declare
cur SYS_REFCURSOR;
owner varchar2(30);
table_namevarchar2(30);
TOT_OBJECT_SIZE_MB number;
EST_ONE_ROW_MB number;
TOTAL_ROW_COUNT integer;
v_sql1 varchar2(10000);
begin
v_sql1 := 'select /*+parallel (4)*/ a.owner,a.table_name, round(sum(b.sum_bytes),2) TOT_OBJECT_SIZE_MB, EST_ONE_ROW_MB
from dba_tables#NAB1 a, '|| v_Mv_name ||' b
where a.table_name = b.segment_name
and a.table_name in
(select table_name from '|| v_Mv_name ||' where driver_table is null)
and a.owner in (select distinct productionschema from '|| v_Mv_name ||' c)
group by a.owner,a.table_name
order by a.table_name';
open cur for v_sql1;
loop
fetch cur into owner, table_name, TOT_OBJECT_SIZE_MB, EST_ONE_ROW_MB;
exit when cur%NOTFOUND;
execute immediate' select /*+parallel (4)*/ count(*) from '||table_name into TOTAL_ROW_COUNT;
end loop;
end;
Usually a BULK COLLECT provides better performance. However, as you run a dedicated query for each record I don't think you will notice any difference in the performance.
You may do a BULK COLLECT into collection of record you wish to return and then loop through the collection.
You may be able to use this example readily into your script.
DECLARE
TYPE sizerec is RECORD ( owner dba_tables.owner%type,
table_name dba_tables.table_name%type,
tot_object_size_mb number);
TYPE srectab is TABLE OF sizerec;
srec srectab;
l_tab_name varchar2(40) := 'dba_tables';
BEGIN
EXECUTE IMMEDIATE
'SELECT a.owner,a.table_name,round(SUM(b.bytes),2) tot_object_size_mb
FROM '||l_tab_name||' a
JOIN dba_segments b ON a.table_name = b.segment_name where rownum < 10
GROUP BY a.owner,a.table_name ' BULK COLLECT INTO srec;
for i in srec.first..srec.last
loop
dbms_output.put_line(srec(i).owner||','||srec(i).table_name
||','||srec(i).tot_object_size_mb);
end loop;
END;
/
Output
PL/SQL procedure successfully completed.
SYS,BOOTSTRAP$,65536
SYS,FILE$,65536
SYS,OBJERROR$,65536
SYS,UNDO$,65536
SYS,PROXY_DATA$,65536
SYS,OBJ$,10485760
SYS,PROXY_ROLE_DATA$,65536
SYS,OBJAUTH$,2097152
SYS,CON$,262144

How to insert multiple row result of dynamic sql to another Table?

I write one dynamic SQL which the result of it is a table with 2 columns and multiple rows, I want to insert it to another table with 4 columns that 2 of them will be filled by the result of dynamic SQL, I try to use collection but don't know how to insert result to another table
CREATE OR REPLACE PROCEDURE P_C_SM_Failure_error_Code_P2P AS
v_month VARCHAR2(16); -- to get Month for each table
v_day VARCHAR2(16); -- to get day for each table
v_ERRCODE t_c_rpt_resultmsg.code%TYPE;
v_ERRMSG t_c_rpt_resultmsg.MESSAGE%TYPE;
v_param VARCHAR2(16);
v_sql VARCHAR2(3000);
v_result number;
type t_c_result is record (Err_code varchar2(2000), Err_count number);
type v_t_result is table of t_c_result index by PLS_INTEGER;
v_t1_result v_t_result;
BEGIN
v_sql :='0';
v_param := 'Gateway_G';
v_result := '0';
select to_char(sysdate - 1,'MM') into v_month from dual;
select to_char(sysdate - 1,'DD') into v_day from dual;
-- Get count of P2P
v_sql := '(select count(*), error_code from (
select error_code from sm_histable'||v_month||''||v_day||'#ORASMSC01 where
orgaccount = '''||v_param||''' and destaccount = '''||v_param||''' and
sm_status <> 1 union all
select error_code from sm_histable'||v_month||''||v_day||'#ORASMSC02 where
orgaccount = '''||v_param||''' and destaccount = '''||v_param||''' and
sm_status <> 1 )
group by error_code)';
EXECUTE IMMEDIATE v_sql bulk collect into v_t1_result;
--insert into t_c_rpt_result2 values (trunc(sysdate, 'DD'), v_errcount,
v_err_code,'Failure_error_Code_P2P');
--for indx in 1 .. v_t1_result.COUNT
--loop
--dbms_output.put_line (v_t1_result (indx).Err_code);
--end loop;
You may append the constant values of date and the error message to the subquery and run a dynamic insert. It should also work if you remove the outer parentheses of your dynamic sql since constants can be included in group by. Always remember to pass values as bind variables rather than concatenating them (v_param). Also, specify the column names explicitly in an INSERT statement.
v_sql := '(select count(*) as cnt, error_code
from (
select error_code from sm_histable'||v_month||''||v_day||'#ORASMSC01
where orgaccount = :x and destaccount = :x and sm_status <> 1
union all
select error_code from sm_histable'||v_month||''||v_day||'#ORASMSC02
where orgaccount = :x and destaccount = :x and sm_status <> 1 )
group by error_code)';
EXECUTE IMMEDIATE v_sql bulk collect into v_t1_result using v_param;
EXECUTE IMMEDIATE 'insert into t_c_rpt_result2(err_dt,err_msg,errcount,error_code)
select :dt,:msg,cnt,error_code from '|| v_sql
USING trunc(sysdate, 'DD'),'Failure_error_Code_P2P',v_param;
I think you are looking at an excellent use case for FORALL. The collection you are populating needs to be done with execute immediate since you are dynamically constructing the table name. But the insert into t_c_rpt_result2 looks static to me.
BEGIN
v_sql :=
'(select count(*) as cnt, error_code
from (
select error_code from sm_histable'
|| v_month
|| ''
|| v_day
|| '#ORASMSC01
where orgaccount = :x and destaccount = :x and sm_status <> 1
union all
select error_code from sm_histable'
|| v_month
|| ''
|| v_day
|| '#ORASMSC02
where orgaccount = :x and destaccount = :x and sm_status <> 1 )
group by error_code)';
EXECUTE IMMEDIATE v_sql BULK COLLECT INTO v_t1_result USING v_param;
FORALL indx IN 1 .. v_t1_result.COUNT
INSERT INTO t_c_rpt_result2 (err_dt,
err_msg,
errcount,
ERROR_CODE)
VALUES (TRUNC (SYSDATE, 'DD'),
'Failure_error_Code_P2P',
v_t1_result (indx).cnt,
v_t1_result (indx).ERROR_CODE);
END;
Find more examples of FORALL on LiveSQL here. Of course, even if your insert was dynamic, you can use FORALL - put the execute immediate directly "inside" the FORALL statement. But I don't think that complexity is justified here.
Hope that helps!

Comma separated values to IN function in oracle

I am trying to execute below query, but not getting any result.
Could some one tell what wrong I am doing?.
DECLARE
object_types VARCHAR2(200);
v_object_types VARCHAR2(200);
l_count number;
BEGIN
object_types :='TABLE,VIEW';
select ''''||regexp_replace(object_types, '( )*(,)( )*',''',''')||''''
into v_object_types from dual;
dbms_output.put_line(to_char(v_object_types));
SELECT count(*) into l_count
FROM all_objects o where o.object_type IN ('||v_object_types||');
dbms_output.put_line(l_count);
END;
WHERE variable IN (1,2,3)
is different to what you are sending now
WHERE variable IN ('1,2,3') or
WHERE variable IN ('||v_object_types||')
You are trying to build the SQL dynamically but instead you are using a single string literal '||v_object_types||' in the IN clause.
You can do it using a collection:
Oracle Setup:
CREATE TYPE stringlist IS TABLE OF VARCHAR2(200);
/
PL/SQL:
DECLARE
object_types VARCHAR2(200) := 'TABLE,VIEW';
v_object_types stringlist;
BEGIN
SELECT TRIM( BOTH FROM REGEXP_SUBSTR( object_types, '[^,]+', 1, LEVEL ) )
BULK COLLECT INTO v_object_types
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT( object_types, '[^,]+' );
FOR i IN 1 .. v_object_types.COUNT LOOP
dbms_output.put_line( v_object_types(i) );
END LOOP;
SELECT count(*)
INTO l_count
FROM all_objects
WHERE object_type MEMBER OF v_object_types;
dbms_output.put_line(l_count);
END;
/
or using dynamic sql:
DECLARE
object_types VARCHAR2(200) := 'TABLE,VIEW';
v_sql VARCHAR2(200);
l_count INTEGER;
BEGIN
v_sql := 'SELECT count(*) FROM all_objects WHERE object_type IN ('
|| REGEXP_REPLACE( object_types, ' *(.+?) *(,|$)', '''\1''\2' )
|| ')';
EXECUTE IMMEDIATE v_sql INTO l_count;
dbms_output.put_line(l_count);
END;
/

Resources