In this case how the parameters pass - oracle

I have a procedure in oracle
CREATE OR REPLACE
PROCEDURE ReportCalculate
(
param_acTypeId in NUMBER
)
AS
sqlstr VARCHAR2(500);
result NUMBER;
BEGIN
sqlstr:='select count(1) from table1 where 1=1 and AC_TYPE_LEVEL1_ID=:acTypeId';
execute immediate sqlstr into result using param_acTypeId;
DBMS_OUTPUT.PUT_LINE(result);
END;
But sometimes I would like to query all the data, sql looks like this
select count (1) from table1 where 1 = 1 and AC_TYPE_LEVEL1_ID = AC_TYPE_LEVEL1_ID,
then how should the parameters pass, or param_acTypeId should have any default value? Is it only in the stitching sql when to judge it?

A typical method would be to accept NULL as meaning "all":
sqlstr := 'select count(1) from table1 where AC_TYPE_LEVEL1_ID = :acTypeId or :acTypeId is null';
I should note that this version precludes the use of indexes. If performance is an issue, then use two queries:
if param_acTypeId is null then
sqlstr := 'select count(1) from table1';
execute immediate sqlstr into result;
else
sqlstr := 'select count(1) from table1 where AC_TYPE_LEVEL1_ID = :acTypeId';
execute immediate sqlstr into result using param_acTypeId;
end if;
DBMS_OUTPUT.PUT_LINE(result);

You do not need dynamic SQL. If you pass in NULL then it will count all rows:
CREATE OR REPLACE PROCEDURE ReportCalculate (
param_acTypeId in NUMBER
)
AS
result NUMBER;
BEGIN
select count(1)
into result
from table1
where ( param_acTypeId IS NULL OR AC_TYPE_LEVEL1_ID = param_acTypeId );
DBMS_OUTPUT.PUT_LINE(result);
END;

Related

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!

PLSQL convert single row in one string

Hi I'm looking for a Oracle function for convert all record of one row in a single string
TABLE_A
|a|b|c|1|
|d|e|f|2|
|g|h|i|3|
select * from TABLE_A where COL4='1';
must return
"abc"
select * from TABLE_A where COL4='2';
"def"
I can't use CONCAT
SELECT COL1||COL2||COL3 from TABLE_A
Becouse I don't know the number and the name of the columns in the table.
Is it possible?
Please, try this, working for record with ID=1, you can change that, or add a loop if needed:
DECLARE
CURSOR CUR IS
SELECT COLUMN_NAME
FROM ALL_TAB_COLS
WHERE TABLE_NAME='TABLE_A';
STMT VARCHAR(1000);
RESULT VARCHAR(1000);
BEGIN
STMT := 'SELECT ';
FOR COL in CUR
LOOP
STMT := STMT || COL.COLUMN_NAME || '||';
END LOOP;
STMT := STMT || ''''' FROM TABLE_A WHERE ID=1';
DBMS_OUTPUT.PUT_LINE( STMT );
EXECUTE IMMEDIATE
STMT
INTO RESULT;
DBMS_OUTPUT.PUT_LINE( 'RESULT: ' || RESULT );
END;

How to return a collection from dynamic SQL having RETURNING clause

I have a PL/SQL block like this:
CREATE OR REPLACE TYPE NUMBER_TABLE_TYPE AS TABLE OF NUMBER;
DECLARE
updatedEmp NUMBER_TABLE_TYPE;
sqlstr VARCHAR2(1000);
tableName VARCHAR2(30) := 'EMPLOYEE';
deptId NUMBER := 12;
BEGIN
sqlstr := 'UPDATE '||tableName||' SET SALARY = SALARY * 2 WHERE DEPT_ID = :deptId '||
'RETURNING EMP_ID BULK COLLECT INTO :res';
EXECUTE IMMEDIATE sqlstr BULK COLLECT INTO updatedEmp USING deptId;
END;
RETURNING BULK COLLECT INTO clause would be simple for static DML, however in my application it is a dynamic one. I tried several ways but non of them worked out. Any idea how to achieve this?
CREATE OR REPLACE TYPE NUMBER_TABLE_TYPE AS TABLE OF NUMBER;
DECLARE
updatedEmp NUMBER_TABLE_TYPE;
sqlstr VARCHAR2(1000);
tableName VARCHAR2(30) := 'EMPLOYEE';
deptId NUMBER := 12;
BEGIN
sqlstr := 'UPDATE '||tableName||' SET SALARY = SALARY * 2 WHERE DEPT_ID = :deptId '||
'RETURNING EMP_ID INTO :res';
EXECUTE IMMEDIATE sqlstr
USING deptId RETURNING BULK COLLECT INTO updatedEmp ;
END;

PLSQL dynamic query

I have a table A which has column A which holds table names as values.
All these tables have a common column C. I need maximum value of this column for each table.
I tried this using dynamic SQL but I'm getting errors. Please suggest.
DECLARE
query1 VARCHAR2(100);
c_table VARCHAR2(40);
c_obj VARCHAR2(20);
Cursor cursor_a IS
SELECT a FROM A;
BEGIN
Open cursor_a;
LOOP
Fetch cursor_a INTO c_table2;
EXIT WHEN cursor_a%notfound;
query1 := 'SELECT max(object_ref) AS "c_obj" FROM c_table' ;
EXECUTE IMMEDIATE query1;
dbms_output.put_line('Maximum value: '|| c_table || c_obj);
END LOOP;
Close cursor_a;
END;
Dynamic SQL can't see your PL/SQL variable: you need to pass it a string which can be executed in the scope of the SQL engine. So you need to concatenate the table name with the statement's boilerplate text:
query1 := 'SELECT max(c) FROM ' || variable_name;
You also need to return the result of the query into a variable.
Here is how it works (I've stripped out some of the unnecessary code from your example):
DECLARE
c_table VARCHAR2(40);
c_obj VARCHAR2(20);
BEGIN
for lrec in ( select a as tab_name from A )
LOOP
EXECUTE IMMEDIATE 'SELECT max(object_ref) FROM ' || lrec.tab_name
into c_obj ;
dbms_output.put_line('Maximum value: '|| lrec.tab_name
|| '='|| c_obj);
END LOOP;
END;
There is some miss match in veriables that you had used i.e.
declared as "c_table" but accessing as "c_table2"
Each table common column name is "C" but accessing as "object_ref"
In dynamic query use INTO keyword to store the value to your varibale
Suggestions
Use concat() function to prepare the query dynamically i.e. something like:
SET #SQL := CONCAT('SELECT max(c) INTO ', c_obj, ' FROM ',c_table);
Steps of implementing dynamic query is:
SET #SQL = <your dynamic query>
PREPARE stmt FROM #SQL;
EXECUTE stmt;
Sample code:
DECLARE
query1 VARCHAR2(100);
c_table VARCHAR2(40);
c_obj VARCHAR2(20);
CURSOR cursor_a IS
SELECT a FROM A;
BEGIN
OPEN cursor_a;
LOOP
FETCH cursor_a INTO c_table;
EXIT WHEN cursor_a%notfound;
SET #SQL := CONCAT('SELECT max(object_ref) AS c_obj INTO ', c_obj, ' FROM ',c_table);
PREPARE stmt FROM #SQL;
EXECUTE stmt;
dbms_output.put_line('Maximum value: '|| c_table || c_obj);
END LOOP;
CLOSE cursor_a;
END;

How to insert data from one table to other table by other mapping table through procedure

There are two tables
Table1(Column11, Column12, Column13)
Table2(Column21, Column22)
And the following Mapping Table:
Table3(Sourcetable,Source column ,Destination table ,Destination column)
How to insert data from Table1 as source table and destination table as Table2 , Through Procedures?
I am using oracle 11g; please help to achieve this!
Thanks & Regards,
Hitman
Try this one:
DECLARE
sqlstr varchar2(1000);
SourceCol varchar2(1000);
DestCol varchar2(1000);
BEGIN
FOR aTab IN (SELECT DISTINCT Source_table, Destination_table FROM Table3) LOOP
FOR aCol IN (SELECT Source_column, Destination_column
FROM Table3
WHERE Source_table = aTab.Source_table
AND Destination_table = aTab.Destination_table)
LOOP
SourceCol := SourceCol || aCol.Source_column ||',';
DestCol := DestCol || aCol.Destination_column ||',';
END LOOP;
SourceCol := REGEXP_REPLACE(SourceCol, ',$');
DestCol := REGEXP_REPLACE(DestCol, ',$');
sqlstr := 'insert into '||aTab.Destination_table||' ('||DestCol
||') SELECT '||SourceCol||' FROM '||aTab.Source_table;
EXECUTE IMMEDIATE sqlstr;
END LOOP;
END;
/
You find Example Schema here SQL Fiddle

Resources