dymanic count query bind variable does not exist - oracle

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

Related

PL/SQL Function - Bulk Collect into and Pipe Row

I am new to PL/SQL have issue with output value of a function.
I want to execute a SQL statement in a function and return the results. The function will be executed with following command: select * from table(mypkg.execute_query('1'));
I was using following article as refence "Bulk Collect Into" and "Execute Immediate" in Oracle, but without success.
It seems that I am using wrong data type. System returns issue on following line: PIPE Row(results)
create or replace package mypkg
as
type node is table of edges%ROWTYPE;
function execute_query (startNode in varchar2) RETURN node PIPELINED;
end;
create or replace package body mypkg
as
function execute_query(startNode in varchar2) RETURN node PIPELINED
AS
results node;
my_query VARCHAR2(100);
output VARCHAR2(1000);
c sys_refcursor;
BEGIN
my_query := 'SELECT DISTINCT * FROM EDGES WHERE src='|| startNode;
open c for my_query;
loop
fetch c bulk collect into results limit 100;
exit when c%notfound;
PIPE Row(results);
end loop;
close c;
END;
end;
I tried several options with cursor but wasn't able to return the value. If you have idea how to return the data by using something else than PIPELINED, please let me know.
Thanks for your support!
Fixed body:
create or replace package body mypkg
as
function execute_query(startNode in varchar2) RETURN node PIPELINED
AS
results node;
my_query VARCHAR2(100);
output VARCHAR2(1000);
c sys_refcursor;
BEGIN -- don't use concatenation, it leads to sql injections:
my_query := 'SELECT DISTINCT * FROM EDGES WHERE src=:startNode';
-- use bind variables and bind them using cluase "using":
open c for my_query using startNode;
loop
fetch c bulk collect into results limit 100;
-- "results" is a collection, so you need to iterate it to pipe rows:
for i in 1..results.count loop
PIPE Row(results(i));
end loop;
exit when c%notfound;
end loop;
close c;
END;
end;
/

Oracle Where with variable

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;

How to pass array as input parameter in Oracle Function

I have a function to BULK insert data using FORALL.
create or replace type l_array_tab as table of number;
create or replace FUNCTION fn_insert_using_array(
L_TAB VARCHAR2,
L_COL_NAME VARCHAR2,
L_ARRAY L_ARRAY_TAB)
RETURN NUMBER
AS
SQL_STMT VARCHAR2(32767);
sql_count NUMBER;
BEGIN
FORALL i IN L_ARRAY.first .. L_ARRAY.LAST
EXECUTE immediate 'INSERT INTO my_table
Select * from '||L_TAB
||' where '||L_COL_NAME||' := :1' using L_ARRAY(i);
sql_count:= SQL%ROWCOUNT;
RETURN SQL_COUNT;
end;
I need to call this function from another stored procedure or plsql block in this example. While calling this function, I am getting error as wrong number or type of inputs.
This is how I am calling the function:
create or replace type l_array_orig_tab as table of number;
Declare
l_array_orig l_array_orig_tab :=l_array_orig_tab();
l_tab varchar2(30): ='my_tab_orig';
l_col_name varchar2(30) :='insert_id';
V_COUNT NUMBER;
cursor c1 is select * from my_tab_orig;
begin
open c1;
LOOP
FETCH c1 BULK COLLECT INTO l_array_orig limit 1000;
EXIT WHEN L_ARRAY_orig.COUNT =0;
V_COUNT:= fn_insert_using_array(L_TAB, L_COL_NAME,l_array_orig);
END LOOP;
END ;
Please suggest how to call the function.
I am getting error as wrong number or type of inputs
You are getting the error because l_array_orig_tab is a different type from l_array_tab. It doesn't matter that they have the same structure, as far as Oracle knows they are different types. Oracle is a database engine and it strongly enforces type safety. There is no duck typing here.
So the simplest solution is to use the correct type when calling the function:
Declare
l_array_orig l_array_tab :=l_array_tab(); -- change this declaration
l_tab varchar2(30): ='my_tab_orig';
l_col_name varchar2(30) :='insert_id';
V_COUNT NUMBER;
cursor c1 is select * from my_tab_orig;
begin
open c1;
LOOP
FETCH c1 BULK COLLECT INTO l_array_orig limit 1000;
EXIT WHEN L_ARRAY_orig.COUNT =0;
V_COUNT:= fn_insert_using_array(L_TAB, L_COL_NAME,l_array_orig);
END LOOP;
END ;
"The function fn_insert_using_array is in a different schema and also the Type."
So the schema which owns the function has granted you EXECUTE privilege on the function. But they also need to grant you EXECUTE on the type. This is their responsibility: they defined the function with a UDT in its signature so they have to give you all the privileges necessary to call it.
I don't don't whether this is a toy example just for posting on SO, but if it isn't there is no need to create a type like this. Instead use the documented Oracle built-in table of numbers, sys.odcinumberlist.
Is l_array_orig_tab != l_array_tab
you have to use the same type or do the cast between type.
Declare
l_array_orig l_array_orig_tab;
new_array l_array_tab;
l_tab varchar2(30): ='my_tab_orig';
l_col_name varchar2(30) :='insert_id';
V_COUNT NUMBER;
cursor c1 is select * from my_tab_orig;
begin
open c1;
LOOP
FETCH c1 BULK COLLECT INTO l_array_orig limit 1000;
select cast( l_array_orig as l_array_tab) into new_array from dual;
EXIT WHEN L_ARRAY_orig.COUNT =0;
V_COUNT:= fn_insert_using_array(L_TAB, L_COL_NAME,new_array);
END LOOP;
END ;
How cast works.
select cast( variable as destination_type) into var_destination_type from dual

Oracle display resultset of dynamic sql

i am pretty new to oracle and i am searching for two days already for a solution for my problem.
i have a view which should have a dynamic column and table name.
something like that:
DECLARE
plsql_block VARCHAR2(500);
BEGIN
plsql_block := 'SELECT CONCAT('some','column') FROM CONCAT('some','table')';
EXECUTE IMMEDIATE plsql_block
END;
This would work but how to i display the result? I already tried it with DBMS.Output and a Loop but thats not exactly what i want. i need that it is displayed as a normal result set in the GUI when i run this command. Does anyone has a hint for me how i am doing this in oracle?
I am Thankful for every answer
Thanks pat
Actually I don't understand your dynamic query. But as per my understanding this query is multirow result result set. So you need to use BULK collect and iterate throuh the output for just the purpose of display.
There are two approaches
1) Just to display the output.
SET serveroutput ON;
DECLARE
plsql_block VARCHAR2(500);
lv_col1 VARCHAR2(10):='1';
lv_col2 VARCHAR2(10):='2';
type tab_var
IS
TABLE OF VARCHAR2(10);
tab tab_var;
BEGIN
plsql_block := 'SELECT CONCAT('||lv_col1||','||lv_col2||') FROM dual';
EXECUTE immediate plsql_block bulk collect INTO tab;
FOR i IN tab.first..tab.last
LOOP
dbms_output.put_line(tab(i));
END LOOP;
END;
2) Approach will be refactor this into a function and then use it as below.
Creating a Table Type
create or replace
type string_table
IS TABLE OF VARCHAR2(100);
CREATE OR REPLACE
FUNCTION func_mu
RETURN string_table
AS
plsql_block VARCHAR2(500);
lv_col1 VARCHAR2(10):='1';
lv_col2 VARCHAR2(10):='2';
tab string_table;
BEGIN
plsql_block := 'SELECT CONCAT('||lv_col1||','||lv_col2||') FROM dual';
EXECUTE immediate plsql_block bulk collect INTO tab;
RETURN tab;
END;
SELECT * FROM TABLE(func_mu);
If you are on Oracle 12c (with the corresponding Oracle client), you can do this:
declare
l_resultset sys_refcursor;
l_sql_text varchar2(500) :=q'{select 'Hello, 12c!' as greeting from dual}';
begin
open l_resultset for l_sql_text;
dbms_sql.return_result(l_resultset);
end;
(Untested, because I'm not near a 12c command line right now.)

Inserting a RefCursor into a table

I have a simple function where I run a stored procedure that returns a RefCursor and I try to use that RefCursor to insert data to a temporary table. I get the following error when trying to do so:
SQL Error: ORA-00947: not enough values
I know for a fact that the refcursor returns exactly the same number of values as the temporary table has, correct column names, their order and their type. I ran print RefCursor and I can see all of the data. Here's the code:
var r refcursor;
EXEC SCHEMA.PACKAGE.SPROC(:r);
insert into SCHEMA.TEMP_TABLE
values
(r);
I have to add that the stored procedure has a refcursor defined as a OUT parameter so it returns a correct type. Using print r; prints the correct data.
What am I doing wrong?
EDIT:
Based on a suggestion I tried to use a fetch to a rowtype variable, but getting Invalid Number exception whenever I attempt to fetch a row:
DECLARE
cur SYS_refcursor;
rec SCHEMA.TEMP_TABLE%rowtype;
begin
SCHEMA.PACKAGE.SPROC( cur );
LOOP
FETCH cur INTO rec;
EXIT WHEN cur%NOTFOUND;
INSERT INTO SCHEMA.TEMP_TABLE
VALUES rec;
END LOOP;
EXCEPTION
WHEN INVALID_NUMBER THEN
DBMS_output.put_line(rec.move_id);
end;
I added the exception block to see which row is failing and needless to say it is the first one. The stored procedure I run returns a refcursor of a select query from multiple tables. The temporary table defined as the exact copy of the refcursor columns and their types. Not sure what could be causing the exception.
You can't insert into a table from a refcursor. You could write a procedure that fetches from the cursor and inserts into the table. If schema.package.sproc returns a ref cursor of temp_table%rowtype, you could do something like
DECLARE
cur sys_refcursor;
rec schema.temp_table%rowtype;
BEGIN
schema.package.sproc( cur );
LOOP
FETCH cur INTO rec;
EXIT WHEN cur%NOTFOUND;
INSERT INTO schema.temp_table
VALUES rec;
END LOOP;
END;
You can use LOOP + FETCH to filter the row in SYS_REFCURSOR.
Exit the LOOP using "EXIT WHEN ref_%notfound;"
Example: Have 2 functions.
FUNCTION get_data
RETURN SYS_REFCURSOR
is
s varchar2(2000);
ref_ SYS_REFCURSOR;
begin
s := 'select username, password, email from user_info where id < 100';
OPEN ref_ FOR s;
return ref_;
end;
FUNCTION load_data_in_table
RETURN varchar2
is
s varchar2(2000);
puser_name varchar2(2000);
ppassword varchar2(2000);
pemail varchar2(2000);
ref_ SYS_REFCURSOR;
begin
ref_ := get_data();
LOOP
--process_record_statements;
FETCH ref_ into puser_name, ppassword, pemail;
s := 'INSERT INTO TEST_USER_EXP VALUES(:user_name, :password, :email)';
EXECUTE IMMEDIATE s USING puser_name, ppassword, pemail;
EXIT WHEN ref_%notfound;
END LOOP;
commit;
return 'OK';
end;

Resources