I have a simple select query that needs to be put into a stored procedure.
The query takes in 3 parameters and displays 2 columns as result, one of them being an aggregate.
CREATE OR REPLACE PROCEDURE "B_SP_GET_TOTAL_CLOCKED_IN_TIME"
(
cv_1 IN OUT TYPES.cursorType,
p_PARENT_CLIENT_ID IN NUMBER DEFAULT 10000,
p_START_TIME IN NVARCHAR2,
p_END_TIME IN NVARCHAR2
)
AS
v_sql VARCHAR2(4000);
BEGIN
v_sql := 'SELECT b.CLIENT_NAME, ROUND(SUM((a.ENDTIME-a.STARTTIME)*24*60),2) TOTAL_CLOCKIN_TIME
FROM TIMESHEET a
INNER JOIN CLIENTS b ON a.CLIENT_ID = b.CLIENT_ID
INNER JOIN CLOCKACTIONS c ON c.ID = a.CLOCKACTIONID
WHERE a.STARTTIME > p_START_TIME AND a.ENDTIME < p_END_TIME AND b.PARENT_CLIENT_ID = p_PARENT_CLIENT_ID
GROUP BY b.CLIENT_NAME';
OPEN cv_1 FOR v_sql;
END;
I executed the stored procedure and it got compiled, with no issues.
How do i check if its working properly? As in how do I test it now?
The statement I used to test the above procedure can be found below:
execute B_SP_GET_TOTAL_CLOCKED_IN_TIME(10000,'04-01-2015 00:00:00','05-01-2015 00:00:00');
This was the error I got:
Error starting at line : 1 in command - execute B_SP_GET_TOTAL_CLOCKED_IN_TIME(10000,'04-01-2015 00:00:00','05-01-2015 00:00:00')
Error report - ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'B_SP_GET_TOTAL_CLOCKED_IN_TIME'
ORA-06550: line 1, column 7: PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
There is not need of (ab)using dynamic SQL. You could simple use OPEN FOR SELECT and use a SYS_REFCURSOR.
For example,
SQL> CREATE OR REPLACE
2 PROCEDURE p_get_emp(
3 p_deptno IN emp.deptno%TYPE,
4 p_ref OUT SYS_REFCURSOR)
5 AS
6 BEGIN
7 OPEN p_ref FOR
8 SELECT ename,
9 empno,
10 deptno
11 FROM emp
12 WHERE deptno = p_deptno
13 ORDER BY empno;
14 END p_get_emp;
15 /
Procedure created.
SQL>
SQL> sho err
No errors.
SQL>
Procedure created without any errors. Let's test it:
SQL> var p_ref refcursor
SQL>
SQL> EXEC p_get_emp (30, :p_ref);
PL/SQL procedure successfully completed.
SQL>
SQL> print p_ref
ENAME EMPNO DEPTNO
---------- ---------- ----------
ALLEN 7499 30
WARD 7521 30
MARTIN 7654 30
BLAKE 7698 30
TURNER 7844 30
JAMES 7900 30
6 rows selected.
SQL>
Related
Am porting a Postgres PLPGSQL function to an Oracle stored procedure, but it has a TEXT[] array as a parameter, then uses this parameter in an ANY operation - specifically:
create or replace function func_name
(
...
in_array_param text[],
...
)
as $$
declare
begin
...
select column_1,
column_2
from table_x
where (column_a = value)
and (column_b = any(in_array_param));
...
end;
I don't recall Oracle historically having an equivalent to this (using a PL/SQL array in SQL), but with the evolution of PL/SQL, am wondering if there are now options to do this? Am using Oracle 19c, but can move to 21c if there is a newer construct that would help.
I have tried using a VARRAY, and using the IN operator:
type my_array_type is varray(10) of varchar2(255);
var_array my_array_type := my_array_type('1', '2', '3');
procedure my_test(param_a varchar2, param_b my_array_type) is
var_col test_tab.col2%type;
begin
select col2 into var_col
from test_tab
where col1 in param_b;
end my_test;
my_test('2', var_array);
This results in a PLS-00642 error:
ORA-06550: line 11, column 21:
PLS-00642: local collection types not allowed in SQL statements
Have a look at the following example.
It uses built-in datatype (use it; why creating your own, if you don't have to?). Procedure searches through employees and finds the last (alphabetically) employee name in list of jobs passed as a collection.
I'd say that it is line #10 you're looking for.
SQL> create or replace procedure p_test
2 (param_a in number, param_b in sys.odcivarchar2list)
3 is
4 l_ename emp.ename%type;
5 begin
6 select max(e.ename)
7 into l_ename
8 from emp e
9 where e.deptno = param_a
10 and e.job in (select * from table(param_b));
11 dbms_output.put_line('Result: ' || l_ename);
12 end;
13 /
Procedure created.
Sample data:
SQL> select ename, job from emp where deptno = 20 order by job, ename;
ENAME JOB
---------- ---------
FORD ANALYST --> this
SCOTT ANALYST --> this
ADAMS CLERK
SMITH CLERK
JONES MANAGER --> this
Who's the last among analysts and managers? These are Ford, Jones and Scott so - Scott it is:
SQL> set serveroutput on
SQL> exec p_test(param_a => 20, param_b => sys.odcivarchar2list('ANALYST', 'MANAGER'));
Result: SCOTT
PL/SQL procedure successfully completed.
SQL>
I have created procedure for simple select statement output.
CREATE OR REPLACE PROCEDURE marcydashboard (p_recordset IN OUT SYS_REFCURSOR)
IS
BEGIN
OPEN p_recordset FOR select employee_id,first_name,last_name from employees;
END;
VARIABLE CURSOR_OUTPUT REFCURSOR;
EXECUTE marcydashboard(:CURSOR_OUTPUT);
I need result same like select statement result but am getting error like:
ERROR at line 6: PLS-00103: Encountered the symbol "VARIABLE"
4. END;
5. VARIABLE CURSOR_OUTPUT REFCURSOR;
6. EXECUTE marcydashboard(:CURSOR_OUTPUT );
please help me to fix the error
Well, it works in SQL*Plus:
SQL> CREATE OR REPLACE PROCEDURE marcydashboard (p_recordset OUT SYS_REFCURSOR)
2 IS
3 BEGIN
4 OPEN p_recordset FOR
5 SELECT employee_id, first_name, last_name FROM employees;
6 END;
7 /
Procedure created.
SQL>
SQL> VARIABLE cursor_output REFCURSOR;
SQL> EXECUTE marcydashboard(:cursor_output);
PL/SQL procedure successfully completed.
SQL> PRINT :cursor_output
EMPLOYEE_ID FIRST_NAME LAST_NAME
----------- ---------- ---------
7369 SMITH CLERK
7499 ALLEN SALESMAN
7521 WARD SALESMAN
7566 JONES MANAGER
SQL>
Looks like you aren't using that tool but some other. In that case, it won't work and you'll have to do it differently, e.g.
SQL> SET SERVEROUTPUT ON
SQL>
SQL> DECLARE
2 l_rc SYS_REFCURSOR;
3 --
4 l_employee_id employees.employee_id%TYPE;
5 l_first_name employees.first_name%TYPE;
6 l_last_name employees.last_name%TYPE;
7 BEGIN
8 marcydashboard (l_rc);
9
10 LOOP
11 FETCH l_rc INTO l_employee_id, l_first_name, l_last_name;
12
13 EXIT WHEN l_rc%NOTFOUND;
14
15 DBMS_OUTPUT.put_line (
16 l_employee_id || ' - ' || l_first_name || ' - ' || l_last_name);
17 END LOOP;
18
19 CLOSE l_rc;
20 END;
21 /
7369 - SMITH - CLERK
7499 - ALLEN - SALESMAN
7521 - WARD - SALESMAN
7566 - JONES - MANAGER
PL/SQL procedure successfully completed.
SQL>
You need a / on a new line after END;
END;
/
VARIABLE CURSOR_OUTPUT REFCURSOR;
create procedure employee_get
(
c_Emp out SYS_REFCURSOR
)
is
begin
open c_Emp for
select a.last_name, b.department_id, b.department_name from employee a inner join department b on a.department_id = b.department_id
order by a.last_name asc ;
end employee_get;
-- run
var c_out refcursor;
exec employee_get(:c_out);
print :c_out;
Everything was fine until I made the Run command. I'm new member, please help me. Thanks and respect!
You need following code to execute the procedure:
create procedure employee_get
(
c_Emp out SYS_REFCURSOR
)
is
begin
open c_Emp for
select a.last_name, b.department_id, b.department_name from employee a inner join department b on a.department_id = b.department_id
order by a.last_name asc ;
end employee_get;
/
-- EXECUTE THE PROCEDURE
DECLARE
C_OUT SYS_REFCURSOR;
BEGIN
-- run
employee_get(C_OUT);
dbms_sql.return_result(C_OUT); --UPDATED
END;
/
Cheers!!
The procedure which returns refcursor:
SQL> create or replace procedure employee_get (c_emp out sys_refcursor) is
2 begin
3 open c_emp for select empno, ename from emp;
4 end;
5 /
Procedure created.
Execution:
SQL> declare
2 c_out sys_refcursor;
3 begin
4 employee_get(c_out);
5 dmbs_sql.return_result(c_out);
6 end;
7 /
dmbs_sql.return_result(c_out);
*
ERROR at line 5:
ORA-06550: line 5, column 3:
PLS-00201: identifier 'DMBS_SQL.RETURN_RESULT' must be declared
ORA-06550: line 5, column 3:
PL/SQL: Statement ignored
See with your DBA whether you can get execute privileges on DBMS_SQL package.
If not:
SQL> var c_out refcursor;
SQL> exec employee_get(:c_out);
PL/SQL procedure successfully completed.
SQL> print :c_out
EMPNO ENAME
---------- ----------
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER
14 rows selected.
SQL>
I don't want to use dynamic SQL so I'm trying different ways to alter my where statement.
Inside my WHERE statement, there is a row:
AND c.nregion = pnregion
pnregion is a number of Russian region. This statement helps my cursor to work a lot faster since Oracle doesn't have to look through the full table.
Problem is that if pnregion is equal to 47 or 78 then this row should look like this
AND c.nregion in (47, 78)
How to do it? Should I use CASE somehow or is there something I could do outside my cursor?
You can use:
WHERE ( c.nregion = pnregion
OR ( pnregion IN ( 47, 78 )
AND c.nregion IN ( 47, 78 )
)
)
This is easily extensible if you want more than 2 values as the values can be added to both IN filters.
You can use decode function to add another option per codes 47/78:
AND (c.nregion = pnregion OR c.nregion = decode(pnregion, 47, 78, 78, 47))
If I understood the question, it is a varying elements in IN list that bothers you. In other words, you can't put comma-separated values into an IN list, unless you
switch to dynamic SQL (which is what you don't want)
separate those values into rows
Here's an example, based on Scott's schema; I hope you'll understand it.
This is what you currently have:
SQL> create or replace procedure p_test (pnregion in varchar2)
2 is
3 cursor c1 is select empno, ename from emp
4 where deptno in pnregion;
5 begin
6 for cr in c1 loop
7 dbms_output.put_line(cr.ename);
8 end loop;
9 end;
10 /
Procedure created.
SQL> -- This is OK
SQL> exec p_test('10');
CLARK
KING
MILLER
PL/SQL procedure successfully completed.
SQL> -- This is not OK
SQL> exec p_test('10, 20');
BEGIN p_test('10, 20'); END;
*
ERROR at line 1:
ORA-01722: invalid number
ORA-06512: at "SCOTT.P_TEST", line 6
ORA-06512: at line 1
SQL>
Now, split comma-separated values to rows and watch it work:
SQL> create or replace procedure p_test (pnregion in varchar2)
2 is
3 cursor c1 is select empno, ename from emp
4 where deptno in (select regexp_substr(pnregion, '[^,]+', 1, level)
5 from dual
6 connect by level <= regexp_count(pnregion, ',') + 1
7 );
8 begin
9 for cr in c1 loop
10 dbms_output.put_line(cr.ename);
11 end loop;
12 end;
13 /
Procedure created.
SQL> -- This is OK
SQL> exec p_test('10');
CLARK
KING
MILLER
PL/SQL procedure successfully completed.
SQL> -- This is also OK now
SQL> exec p_test('10, 20');
SMITH
JONES
CLARK
SCOTT
KING
ADAMS
FORD
MILLER
PL/SQL procedure successfully completed.
SQL> -- Or even some more values:
SQL> exec p_test('10, 20,30');
SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER
PL/SQL procedure successfully completed.
SQL>
I have a very simple test proc:
create or replace PROCEDURE TestSproc
(userName in VARCHAR2, p_Test OUT SYS_REFCURSOR)IS
BEGIN
OPEN p_Test FOR
SELECT * FROM Test_Table
WHERE name = userName ;
END TestSproc;
When I run the proc (ctrl f10) in sqldeveloper on the proc page I get the result I would expect. But when I try to call the proc with the below query I get the error:
Error starting at line : 1 in command - begin DB.TestSproc('Phil'); end;
Error report - ORA-06550: line 2, column 1:
PLS-00306: wrong number or types of arguments in call to 'TestSproc'
ORA-06550: line 2, column 1: PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
begin
DB.TestSproc('Phil');
end;
Can anyone please point me in the correct direction.
EDIT
In SQL Server I would simply do:
USE DB;
GO
EXEC dbo.TestSproc#Name= 'Phil';
Assuming you are using Oracle 12c with a 12c client:
create or replace procedure testsproc
( username in varchar2 )
as
resultset sys_refcursor;
begin
open resultset for
select * from test_table
where name = username;
dbms_sql.return_result(resultset);
end testsproc;
Then call it with
exec testsproc('Phil')
or
call testsproc('Phil');
or
begin
testsproc('Phil');
end;
depending on what you are calling it from.
Further reading
You have to put the output somewhere, so - declare an appropriate variable:
SQL> create or replace procedure p_test (par_deptno in number, p_emps out sys_refcursor) is
2 begin
3 open p_emps for
4 select deptno, empno, ename
5 from emp
6 where deptno = par_deptno;
7 end;
8 /
Procedure created.
SQL>
SQL> var l_out refcursor
SQL>
SQL> begin
2 p_test(10, :l_out);
3 end;
4 /
PL/SQL procedure successfully completed.
SQL>
SQL> print :l_out;
DEPTNO EMPNO ENAME
---------- ---------- ----------
10 7839 KING
10 7782 CLARK
10 7934 MILLER
SQL>