Oracle Where with variable - oracle

I have problem with my plsql code. It's just part of my whole job.
declare
id number(2):=1; (here is function which returns any value)
check VARCHAR2(100);
begin
select COUNT(*) into check from T_SDSN_LOG Where ANY_ID=id AND CHECK LIKE
'NAME';
dbms_output.put_line(check);
end;
In this case, my select returns 0 althought it should be 2.
If I change the part
Where ANY_ID=id to
Where ANY_ID=2 it works perfectly. Any advices? I need id to be variable as a return value from function.

This uses a locally defined function so it isn't available in the SQL but can be referenced in the PL/SQL.
DECLARE
lnum_id NUMBER := return_id;
lnum_check VARCHAR2(100);
FUNCTION return_id
RETURN NUMBER
IS
BEGIN
RETURN 123456;
END;
BEGIN
lnum_id := return_id;
SELECT COUNT(*)
INTO lnum_check
FROM my_table
WHERE table_id = lnum_id;
DBMS_OUTPUT.put_line(lnum_check);
END;
You will presumably want this functionality in a package in which case you can declare the function in the package header, write the code for the function in the body and then reference it in the SQL itself. So if I declare a function (FNC_RETURN_ID) in a package called PKG_DATA_CHECKS that returns a NUMBER I can do the following;
DECLARE
lnum_id NUMBER;
lnum_check VARCHAR2(100);
BEGIN
SELECT COUNT(*)
INTO lnum_check
FROM my_table
WHERE table_id = (SELECT pkg_data_checks.fnc_return_id FROM dual);
DBMS_OUTPUT.put_line(lnum_check);
END;

Related

How to run Oracle function which returns more than one value

My test function is this
CREATE OR REPLACE FUNCTION MULTI_VAL
(MYNAME OUT EMP2017.ENAME%TYPE)
RETURN NUMBER AS
MYSAL EMP2017.SAL%TYPE;
BEGIN
SELECT SAL, ENAME INTO MYSAL, MYNAME FROM EMP2017 ;
RETURN MYSAL;
END;
/
When I run it like
variable mynm varchar2(20)
SELECT MULTI_VAL(:mynm) FROM dual;
it gives this error
ERROR at line 1:
ORA-06553: PLS-561: character set mismatch on value for parameter 'MYNAME'
The error you get now indicates a datatype mismatch.
However there is a fundamental problem with your code. We cannot use functions which have OUT parameters in SQL. So once you have fixed the datatype issue you will get this error: ORA-06572: Function MULTI_VAL has out arguments.
You can run it like this:
declare
n varchar2(20);
x number;
begin
x := multi_val(n);
end;
/
Generally, functions with OUT parameters are considered bad practice. The syntax allows them, but the usage is hard to understand. It's better to use a procedure with two OUT parameters (because we can only call the program in PL/SQL anyway) or else have the function return a user-defined type.
CREATE TABLE EMP2017(ENAME VARCHAR2(10),SAL NUMBER);
INSERT INTO EMP2017 VALUES ('SMITH',5000);
INSERT INTO EMP2017 VALUES ('JOHNS',1000);
COMMIT;
CREATE TYPE RET_MULT AS OBJECT
(ENAME VARCHAR2(10),SAL NUMBER);
CREATE TYPE T_RET_MULT AS TABLE OF RET_MULT;
CREATE OR REPLACE FUNCTION MULTI_VAL RETURN T_RET_MULT PIPELINED IS
MYSAL RET_MULT;
BEGIN
FOR I IN(SELECT SAL, ENAME FROM EMP2017) LOOP
MYSAL := RET_MULT(I.ENAME,I.SAL);
PIPE ROW(MYSAL);
END LOOP ;
RETURN ;
END;
SELECT * FROM TABLE(MULTI_VAL());
I think this question can be solved without using pipeline functions. Just like this. All pre required data as described #Sedat.Turan except function. Sorry for copy/past.
CREATE TABLE EMP2017(ENAME VARCHAR2(10),SAL NUMBER);
INSERT INTO EMP2017 VALUES ('SMITH',5000);
INSERT INTO EMP2017 VALUES ('JOHNS',1000);
COMMIT;
CREATE TYPE RET_MULT AS OBJECT
(ENAME VARCHAR2(10),SAL NUMBER);
CREATE TYPE T_RET_MULT AS TABLE OF RET_MULT;
create or replace function MULTI_VAL return T_RET_MULT is
RET_SET T_RET_MULT;
begin
select RET_MULT(ENAME, SAL) bulk collect into RET_SET from EMP2017;
return RET_SET;
end;

dymanic count query bind variable does not exist

i want to execute dynamic count for view employeesview
so i applied the current function
CREATE OR REPLACE FUNCTION get_num_of_employees
RETURN NUMBER
IS
v_query_str VARCHAR2(1000);
v_num_of_employees NUMBER;
BEGIN
v_query_str := 'select count(*) into :countresult from employeesview';
EXECUTE IMMEDIATE v_query_str
USING out v_num_of_employees;
RETURN v_num_of_employees;
END;
but when i execute this function
select get_num_of_employees from dual
iam getting the error
01006. 00000 - "bind variable does not exist"
is my function right or is there any other way to execute dynamic count
This is a way to run a dynamic SELECT query and save the result into a variable:
CREATE OR REPLACE FUNCTION get_num_of_employees
RETURN NUMBER
IS
v_query_str VARCHAR2(1000);
v_num_of_employees NUMBER;
BEGIN
v_query_str := 'select count(*) from employeesview';
EXECUTE IMMEDIATE v_query_str
into v_num_of_employees;
RETURN v_num_of_employees;
END;
In this situation you don't need dynamic SQL, so I assume you need it in your real code for some reason.
If you don't have a good reason to use dynamic SQL, your function can be simplified:
CREATE OR REPLACE FUNCTION get_num_of_employees
RETURN NUMBER
IS
v_num_of_employees NUMBER;
BEGIN
select count(*) into v_num_of_employees from employeesview;
RETURN v_num_of_employees;
END;
thanks very much but i have solved it simply as following
CREATE OR REPLACE FUNCTION get_num_of_employees
RETURN NUMBER
IS
v_query_str VARCHAR2(1000);
v_num_of_employees NUMBER;
BEGIN
v_query_str := 'select count(*) from employeesview';
EXECUTE IMMEDIATE v_query_str
into v_num_of_employees ;
RETURN v_num_of_employees;
END;
and you can append any filter in the v_query_str or pass view name as parameter later to achieve real dynamic execution

Oracle Variable as select

I have to call oracle SQL statement inside my project.
All connection related stuff is done, but my tool does not capture the output parameter executed by oracle.
Hence I need alter this query to return p_num value in a select statement.
i.e. the table which has 1 column ('p_num') with column name called 'Result' and which has only one row which is p_num value.
Following is the sql statement which currently gives output value with help of dbms_output.put_line
DECLARE
p_num varchar2(4000);
message varchar2(4000) ;
BEGIN
p_num := MyFunction();
dbms_output.put_line('Message : ' || p_num) ;
END;
What I want is p_num value in a SELECT statement so that I can capture specific column inside my bpm tool.
You can directly call the function in the SELECT statement.
1) First way is to do it VIA plain SQL
SELECT MyFunction FROM DUAL;
2) Second way is PLSQL but i will not recommend it unless its unavoidable
set serveroutput on;
declare
lv_var VARCHAR2(100);
lv_out_param VARCHAR2(100);
BEGIN
lv_var:=MyFunction(lv_out_param);
dbms_output.put_line(lv_var||' '||lv_out_param);
END;
/

Oracle PL/SQL array input into parameter of pipelined function

I am new to PL/SQL. I have created a pipelined function inside a package which takes as its parameter input an array of numbers (nested table).
But I am having trouble trying to run it via an sql query. Please see below
my input array
CREATE OR REPLACE TYPE num_array is TABLE of number;
my function declaration
CREATE OR REPLACE PACKAGE "my_pack" as
TYPE myRecord is RECORD(column_a NUMBER);
TYPE myTable IS TABLE of myRecord;
FUNCTION My_Function(inp_param num_array) return myTable PIPELINED;
end my_pack;
my function definition
CREATE OR REPLACE PACKAGE BODY "my_pack" as
FUNCTION My_Function(inp_param num_array) return myTable PIPELINED as
rec myRecord;
BEGIN
FOR i in 1..inp_param.count LOOP
FOR e IN
(
SELECT column_a FROM table_a where id=inp_param(i)
)
LOOP
rec.column_a := e.column_a;
PIPE ROW (rec);
END LOOP;
END LOOP;
RETURN;
END;
end my_pack;
Here is the latest code I've tried running from toad. But it doesn't work
declare
myarray num_array;
qrySQL varchar2(4000);
begin
myarray := num_array(6341,6468);
qrySQL := 'select * from TABLE(my_pack.My_Function(:myarray))';
execute immediate qrySQL;
end;
So my question is how can I feed an array into this pipelined function from either TOAD or SQL Developer. An example would be really handy.
Thanks
The error is fairly clear, you have a bind variable that you haven't assigned anything to. You need to pass your actual array with:
qrySQL := 'select * from TABLE(my_pack.My_Function(:myarray))';
execute immediate qrySQL using myarray;
It's maybe more useful, if you want to call it from PL/SQL, to use static SQL as a cursor:
set serveroutput on
declare
myarray num_array;
begin
myarray := num_array(6341,6468);
for r in (select * from TABLE(my_pack.My_Function(myarray))) loop
dbms_output.put_line(r.column_a);
end loop;
end;
/
Or just query it statically as a test, for fixed values:
select * from TABLE(my_pack.My_Function(num_array(6341,6468)));
SQL Fiddle with some minor tweaks to the function to remove errors I think came from editing to post.

Whats the correct syntax to increment a sequence?

I have a function that looks like this.
Function GetNewBatch ( CourseName Varchar2 ) Return RefCursor
As
Results RefCursor;
CourseId Number;
Begin
CourseId := Courselist.GetId( CourseName );
Open Results For
Select q.user_abn UserAbn,
q.completed_t DateCompleted,
CourseName,
q.batch_n BatchId
From GAK.GAKHR02_ACK q
Where q.crse_i = CourseId
And q.batch_n is null
And rownum < 1000;
GAK.SEQ1_GAKHR03.NextVal;
Return Results;
End;
I want to increment the sequence after the select, but SQL Developer is giving me the error:
"Error(194,5): PLS-00313: 'NEXTVAL' not declared in this scope."
How can I do this?
It's because you're not assigning the nextval to a variable. Assume that .nextval is a function of some description. It's not, Oracle actually describe it as a psuedocolumn; something used in the same context as a column but not written to the disk.
How you increment a sequence depends on the version of Oracle you're using. Prior to 11G you could do the following in a PL/SQL block:
declare
i number;
begin
select my_sequence.nextval
into i
from dual;
insert into my_table(id)
values(my_sequence.nextval);
update my_table
set id = my_sequence.nextval;
end;
In 11G this changed slightly so you could also assign the "return" value from .nextval to a variable:
declare
l_next_val number;
begin
l_next_val := my_sequence.nextval;
end;
The reason for PLS-00313 is that Oracle is assuming that SEQ1_GAKHR03 is a package or some other object and .nextval is a sub-type of this object.
It's very unusual to increment a sequence without actually using the value. Is this intended behaviour?

Resources