Get Tables Name Through Plsql Query - sql

I need a procedure that input user_name and password then get to me the exist tables in that schema with the create script for each table?
This is what I tried, but is wrong:
CREATE OR REPLACE procedure TABLE_INFO(P_USER_NAME IN VARCHAR2,P_PASSWORD IN VARCHAR,P_TABLE_NAME OUT VARCHAR2,P_SCRIPT OUT VARCHAR2)
IS
chk_username all_users.username%type;
CURSOR C IS SELECT table_name FROM USER_TABLES;
t_tablename user_tables.table_name%type;
BEGIN
SELECT username into chk_username from all_users
where chk_username=p_user_name;
open c;
loop
fetch c into t_tablename;
exit when c% notfound;
end loop;
exception when no_data_found then
dbms_output.put_line('Wrong Username Or Password');
close c;
end;
/

Try this code. Let me know if this helps.
CREATE OR REPLACE PROCEDURE TABLE_INFO(
P_USER_NAME IN VARCHAR2,
-- P_PASSWORD IN VARCHAR, --Not required
P_TABLE_NAME OUT sys_refcursor)
-- P_SCRIPT OUT VARCHAR2) --Not required
AS
BEGIN
-----------------------For DDL script use dbms_metadata.get_ddl-------------------------
OPEN P_TABLE_NAME FOR
SELECT OWNER,TABLE_NAME,dbms_metadata.get_ddl('TABLE',TABLE_NAME) "table DDL"
FROM all_tables WHERE upper(OWNER) = upper(P_USER_NAME);
END;
--------------------To EXECUTE this proc---------------------------------
var usr VARCHAR2(100);
VAR p_lst refcursor;
exec TABLE_INFO(<username>,:p_lst);
------------------------------------------------------------------------

Check this out. This is a function returning all the values as per requirement.
-- Obj Creation
CREATE OR REPLACE TYPE my_obj
IS
OBJECT
(
TAB_NAME VARCHAR2(100),
DDL_S VARCHAR2(32676) );
-- Table type Creation
CREATE OR REPLACE TYPE my_tab
IS
TABLE OF my_obj;
--Function Creation---
CREATE OR REPLACE FUNCTION TABLE_INFO_FUN(
P_USER_NAME IN VARCHAR2 )
RETURN my_tab
AS
my_otpt my_tab;
BEGIN
-----------------------For DDL script use dbms_metadata.get_ddl-------------------------
SELECT CAST( multiset
(SELECT my_obj(TABLE_NAME,dbms_metadata.get_ddl('TABLE',TABLE_NAME))
FROM all_tables
WHERE upper(OWNER) = upper(P_USER_NAME)
) AS my_tab )
INTO my_otpt
FROM DUAL;
RETURN my_otpt;
END;
-- Using Function to Select Data -------------
SELECT * FROM TABLE(TABLE_INFO_FUN(<USERNAME>));

Related

Passing Multiple Values To PL/SQL Input

I have an Oracle package which contains a function. This function has 3 inputs. I need to pass multiple values to each input. I could automate a process which runs it multiple times with each combination of variables but I would like to only make one call to the database.
Simplified Code
declare
ln_ret number;
begin
ln_ret := dbo.pkg_rpa.mis_run_script (
'%2020%',
'111','222','333','444',
'1234','2345','6192','1204'
);
dbms_output.put_line('ln_ret=' || t.t (ln_ret));
end;
CREATE OR REPLACE
package dbo.pkg_rpa IS
function mis_run_script (
p_input_dt in varchar2,
p_hospital_id in varchar2,
p_procedure_code in varchar2) RETURN number;
end PKG_RPA;
/
CREATE OR REPLACE
PACKAGE BODY dbo.pkg_rpa IS
function mis_run_claim_assessment_script (
p_input_dt in varchar2,
p_hospital_id in varchar2,
p_procedure_code in varchar2
)
Begin
for i in (select table_name from user_tables where lower(table_name) = 'temp_rpa') loop
execute immediate 'drop table temp_rpa';
end loop;
execute immediate ' create table temp_rpa as select distinct ci.claim_id, count(ci.receipt_id) as count_receipts,
sum(ci.billed_amount) as total_billed_amount, count(*) as claim_items
from claim_item ci left join claim_header ch on ch.claim_id = ci.claim_id
left join cd_hos ho on ho.hospital_id = ci.hospital_id
left join claim_type_header cl on cl.claim_id = ci.claim_id
where cl.claim_status is null and ch.deleted_flag is null
and ch.input_dt like p_input_dt
and ci.hospital_id in (p_hospital_id)
and (ci.claim_id, NVL(ci.claim_item_id,0)) in (select claim_id, NVL(claim_item_id,0) from cd_roc_claim_item
where procedure_code in (p_procedure_code))
and (ci.claim_id, NVL(ci.claim_item_id,0)) not in (select claim_id, NVL(claim_item_id,0) from cd_roc_claim_item
where procedure_code not in (p_procedure_code))
group by ci.claim_id
having sum(case when ci.service_type_id is null then 1 end) = 1)';
End;
end mis_run_script;
end PKG_RPA;
/
Pass it with quoted string (Q'<delimeter><your_actual_string><delimeter>') as follows:
begin
ln_ret := dbo.pkg_rpa.mis_run_script (
'%2020%',
Q'#'111','222','333','444'#',
Q'#'1234','2345','6192','1204'#'
);
dbms_output.put_line('ln_ret=' || t.t (ln_ret));
end;
What you could do is using an associative array as input type. Instead of varchar2, use dbms_sql.varchar2a as date type for the 2nd and 3rd arguments.
But if the arguments are related to each other, let's say
p_hospital_id '111' belongs to procedure code '1234'
p_hospital_id '222' belongs to procedure code '2345'
etc.
I think you would want to create a custom record type, create a table type of the record type and use that as an parameter.
Your arguments become p_hospital_ids in dbms_sql.varchar2a in both the package specification and the package body.
In you code, you would have to loop over it and instead of dropping the table and recreate it each time, you drop it once at the start and add data within the loop;
truncate table; --alternative drop and create
for i in 1 .. p_hospital_ids.count loop
insert into temp_rpa
select <columns>
from claim_item ci
......
and ci.hospital_id = p_hospital_ids[i]
end loop
You may want to refer to the below example which is taken from Oracle Website. Hope it helps.
CREATE OR REPLACE TYPE nt_type IS TABLE OF NUMBER;
/
CREATE OR REPLACE PROCEDURE print_nt (nt nt_type) AUTHID DEFINER IS
i NUMBER;
BEGIN
i := nt.FIRST;
IF i IS NULL THEN
DBMS_OUTPUT.PUT_LINE('nt is empty');
ELSE
WHILE i IS NOT NULL LOOP
DBMS_OUTPUT.PUT('nt.(' || i || ') = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(nt(i)), 'NULL'));
i := nt.NEXT(i);
END LOOP;
END IF;
DBMS_OUTPUT.PUT_LINE('---');
END print_nt;
/
DECLARE
nt nt_type := nt_type(); -- nested table variable initialized to empty
BEGIN
print_nt(nt);
nt := nt_type(90, 9, 29, 58);
print_nt(nt);
END;
/
You don't need dynamic SQL at all.
CREATE OR REPLACE TYPE NUMBER_TABLE_TYPE AS TABLE OF NUMBER;
CREATE OR REPLACE TYPE VARCHAR_TABLE_TYPE AS TABLE OF VARCHAR2(1000);
function mis_run_claim_assessment_script (
p_input_dt in varchar2,
p_hospital_id in NUMBER_TABLE_TYPE, -- why on earth do you put numbers as strings?
p_procedure_code in VARCHAR_TABLE_TYPE
) RETURN ??? AS
INSERT INTO temp_rpa (...)
SELECT ...
FROM ...
WHERE ch.input_dt like p_input_dt
AND ci.hospital_id MEMBER OF p_hospital_id
AND procedure_code MEMBER OF p_procedure_code ;
RETURN ???
END;
ln_ret := mis_run_claim_assessment_script(
'%2020%',
NUMBER_TABLE_TYPE(111, 222, 333, 444),
VARCHAR_TABLE_TYPE('not','clear','in','your','question')
);

How to select all rows from the oracle PL/SQL collection into SYS_REFCURSOR

Note: I have seen many solution and all says I can not use SQL with a PL/SQL type. I must have to use CREATE or REPLACE, but my restriction is I can not use system object for this task.
What I have tried the below example returns only last row.
create or replace PROCEDURE SP_TEST (TEST_cursor OUT SYS_REFCURSOR)IS
TYPE TEMP_RECORD IS RECORD(
entries NUMBER,
name VARCHAR2(50),
update VARCHAR2(200)
);
TYPE TEMP_TABLE IS TABLE OF TEMP_RECORD INDEX BY PLS_INTEGER;
VAR_TEMP TEMP_TABLE;
IDX PLS_INTEGER := 0;
BEGIN
VAR_TEMP(IDX).cur_entries := 1;
VAR_TEMP(IDX).cur_entries := 2;
OPEN TEST_cursor FOR
SELECT VAR_TEMP(idx).cur_entries from dual;
END SP_TEST;
Another way tried.
OPEN TEST_cursor FOR
SELECT * FROM TABLE(VAR_TEMP)
--- It gives compilation error ora-
Given that you can't create an object in the database, the only solution I can think of is to use dynamic SQL:
CREATE TYPE temp_record AS OBJECT
(
entries NUMBER,
entry_name VARCHAR2 (50),
update_value VARCHAR2 (200)
);
CREATE TYPE temp_table IS TABLE OF temp_record;
CREATE OR REPLACE PROCEDURE sp_test (test_cursor OUT SYS_REFCURSOR) IS
var_temp temp_table := temp_table ();
strSql VARCHAR2(32767);
BEGIN
-- Populate the temp table, or pass it in from elsewhere
var_temp.EXTEND();
var_temp (var_temp.LAST).entries := 1;
var_temp (var_temp.LAST).entry_name := 'test';
FOR i IN 1..var_temp.COUNT LOOP
strSql := strSql ||
CASE
WHEN LENGTH(strSql) > 0 THEN ' UNION ALL '
ELSE NULL
END ||
'SELECT ' || var_temp.ENTRIES || ' ENTRIES,' ||
'''' || var_temp.ENTRY_NAME || ''' ENTRY_NAME FROM DUAL';
END LOOP;
OPEN test_cursor FOR strSql;
END sp_test;
Now, I may have messed up the string concatenation logic there a bit, but the objective is to end up with an SQL string which looks something like
SELECT 1 ENTRIES,'test' ENTRY_NAME FROM DUAL
UNION ALL
SELECT 2 ENTRIES,'test 2' ENTRY_NAME FROM DUAL
UNION ALL
SELECT 3 ENTRIES,'test_3' ENTRY_NAME FROM DUAL
but, of course, without the nice white space and etc.
The 32K limit on dynamic SQL may bite you eventually, but if push comes to shove you can the DBMS_SQL package to handle arbitrarily large SQL text, although that presents its own challenges.
Best of luck.
In order to reference types in SQL (as opposed to PL/SQL), they must be created as objects in the database. This is effectively a scope issue: when you run SQL you are shifting to a different context. Any structures that you have created locally are not available there.
CREATE TYPE temp_record AS OBJECT
(
entries NUMBER,
entry_name VARCHAR2 (50),
update_value VARCHAR2 (200)
);
CREATE TYPE temp_table IS TABLE OF temp_record;
CREATE OR REPLACE PROCEDURE sp_test (test_cursor OUT SYS_REFCURSOR) IS
var_temp temp_table := temp_table ();
BEGIN
var_temp.EXTEND ();
var_temp (var_temp.LAST).entries := 1;
var_temp (var_temp.LAST).entry_name := 'test';
OPEN test_cursor FOR SELECT * FROM TABLE (var_temp);
END sp_test;

Invalid Data Type error while casting PL/SQL Array to Table

I have a PL/SQL stored proc which needs to return a RefCursor type object as output parameter.
PROCEDURE usp_appnt_stts_driver_wraper2
( in_req_src_system_id IN NUMBER,
in_req_user_info IN VARCHAR2,
out_response_rec1 OUT SYS_REFCURSOR)
At the end of the SP, I am able to return Hard Coded values to my front end by using a Select Statement.
OPEN out_response_rec1 FOR
SELECT 'data1', 'data2', 'data3', 'data 4' FROM DUAL;
This works fine. But I need to send the data which I am getting from an Array.
The Array is populated like this,
FOR g_index IN g_slsnetoutbndarr.FIRST..g_slsnetoutbndarr.LAST
LOOP
out_response_rec.EXTEND;
IF g_SlsnetOutbndArr(g_index).Rectypdesc IS NOT NULL THEN
out_response_rec(g_index).Rectypdesc := g_SlsnetOutbndArr(g_index).Rectypdesc ;
out_response_rec(g_index).Recdetltcode := g_SlsnetOutbndArr(g_index).Recdetltcode;
out_response_rec(g_index).RecDetlDesc := g_SlsnetOutbndArr(g_index).RecDetlDesc ;
END IF;
END LOOP;
So at the end of this code, the Array Object out_response_rec has all the values I need.
But How do I transfer these values in the RefCursor output parameter?
Update 1
I have tried to create a new data type in the Package specification.
TYPE SlsnetOutbndRec IS RECORD(
Rectypdesc VARCHAR2(30),
Recdetltcode NUMBER,
RecDetlDesc VARCHAR2(130));
TYPE SlsnetOutbndTabArr IS TABLE OF SlsnetOutbndRec;
Finally I have tried to Cast the Array to table in my SP as
OPEN out_response_rec_result FOR
SELECT * FROM TABLE (Cast(out_response_rec AS SlsnetOutbndTabArr));
But this is throwing an Invalid Data Type error. The SP does not recognize the new data types I created.
So at the end of this code, the Array Object out_response_rec has all
the values I need.
But How do I transfer these values in the RefCursor output parameter?
As I could understand, you wanted to use a SYS_REFCUSOR to get the output of a Query plus the values that are in collection which is being populated by another Procedure. I have come up with a solution for your requirement see below inline explaination:
--Create a Object in Place of Record since we cannot use a PLSQL scope compnenet in SQL scope in Oracle 11g and below
CREATE OR REPLACE TYPE SlsnetOutbndRec IS OBJECT
(
Rectypdesc VARCHAR2 (30),
Recdetltcode NUMBER,
RecDetlDesc VARCHAR2 (130)
);
--Create a table type of the Object
CREATE OR REPLACE TYPE SlsnetOutbndTabArr IS TABLE OF SlsnetOutbndRec;
/
--Procedure
CREATE OR REPLACE PROCEDURE combined_rslt (var OUT SYS_REFCURSOR)
AS
v_var SlsnetOutbndTabArr := SlsnetOutbndTabArr ();
l_var SlsnetOutbndTabArr := SlsnetOutbndTabArr ();
BEGIN
--Populating the collection
v_var.EXTEND;
v_var (1) := SlsnetOutbndRec ('ABC', 1, 'A');
OPEN VAR FOR
SELECT 'CDE', 2, 'B' FROM DUAL
UNION ALL -- Combining the result of collection with the result of query
SELECT *
FROM TABLE (v_var) t;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (SQLERRM);
END;
Execution :
DECLARE
x SYS_REFCURSOR;
a VARCHAR2 (30);
b NUMBER;
c VARCHAR2 (130);
BEGIN
combined_rslt (var => x);
LOOP
FETCH x INTO a, b, c;
EXIT WHEN x%NOTFOUND;
DBMS_OUTPUT.put_line (a || ' ' || b || ' ' || c);
END LOOP;
END;
Results:
SQL> /
CDE 2 B
ABC 1 A
PL/SQL procedure successfully completed.
You need to create the types in the SQL scope (not the PL/SQL scope) if you want to use them in SQL statements (in versions prior to Oracle 12):
CREATE TYPE SlsnetOutbndRec IS OBJECT(
Rectypdesc VARCHAR2(30),
Recdetltcode NUMBER,
RecDetlDesc VARCHAR2(130)
)
/
CREATE TYPE SlsnetOutbndTabArr IS TABLE OF SlsnetOutbndRec
/
Then you can use it in your procedure (assuming your 3rd party data type is a collection or a VARRAY):
PROCEDURE usp_appnt_stts_driver_wraper2(
in_req_src_system_id IN NUMBER,
in_req_user_info IN VARCHAR2,
out_response_rec_result OUT SYS_REFCURSOR
)
IS
out_response_rec SlsnetOutbndTabArr := SlsnetOutbndTabArr();
g_slsnetoutbndarr ThirdPartyDataType := Get_From_3rd_party_Package();
BEGIN
FOR i IN 1 .. g_slsnetoutbndarr.COUNT LOOP
IF g_SlsnetOutbndArr(i).Rectypdesc IS NOT NULL THEN
out_response_rec.EXTEND;
out_response_rec := SlsnetOutbndRec(
g_SlsnetOutbndArr(i).Rectypdesc,
g_SlsnetOutbndArr(i).Recdetltcode,
g_SlsnetOutbndArr(i).RecDetlDesc
);
END IF;
END LOOP;
OPEN out_response_rec_result FOR
SELECT *
FROM TABLE( out_response_rec );
END;
If the 3rd party data type is an associative array then:
...
IS
out_response_rec SlsnetOutbndTabArr := SlsnetOutbndTabArr();
g_slsnetoutbndarr ThirdPartyDataType := Get_From_3rd_party_Package();
i ThirdPartyIndexType := g_slsnetoutbndarr.FIRST;
BEGIN
WHILE i IS NOT NULL LOOP
IF g_SlsnetOutbndArr(i).Rectypdesc IS NOT NULL THEN
out_response_rec.EXTEND;
out_response_rec := SlsnetOutbndRec(
g_SlsnetOutbndArr(i).Rectypdesc,
g_SlsnetOutbndArr(i).Recdetltcode,
g_SlsnetOutbndArr(i).RecDetlDesc
);
END IF;
i := g_slsnetoutbndarr.NEXT(i);
END LOOP;
...

How to store result of a function which will return sysrefcursor?

Scenario: there is an procedure inside which we have a cursor.
I need to call a function which will take an input from that cursor value and will return SYS_REFCURSOR.
I need to store that result of function in a different variable/cursor & need to return this value from procedure as out parameter.
I am using Oracle 11g.
How can I proceed?
PFB My Approach:
create or replace procedure prc_test
(p_dept_id in number,
c_detail out sysrefcursor)--need to add extra out parameter
as
var1 varchar2(200) :=null;
begin
open c_detail for
select -1 from dual;
if p_dept_id is not null then
open c_detail for
select emp_no from emp
where dept_id=p_dept_id;
--i need to retrn value of 'get_emp_dtls' function as out parameter.
end if;
end procedure;
/
Function to be called
CREATE OR REPLACE FUNCTION get_emp_dtls
(p_emp_no IN EMP.EMP_NO%TYPE)
RETURN SYS_REFCURSOR
AS
o_cursor SYS_REFCURSOR;
BEGIN
OPEN o_cursor FOR
SELECT
ENAME,
JOB
FROM emp
WHERE EMP_NO = p_emp_no;
RETURN o_cursor;
-- exception part
END;
/
Here is your function that takes a varchar2 variable and returns A refcursor( weakly typed).
CREATE OR replace FUNCTION fn_return_cur(v IN VARCHAR2)
RETURN SYS_REFCURSOR
IS
c1 SYS_REFCURSOR;
BEGIN
OPEN c1 FOR
SELECT 'ABC'
FROM dual
WHERE 'col1' = v;
RETURN c1;
END;
/
Here is the procedure that has a cursor value passed as argument to function and the returned cursor passed as OUT argument.
CREATE OR replace PROCEDURE Pr_pass_out_cur(v_2 OUT SYS_REFCURSOR)
IS
func_arg VARCHAR2(3);
other_arg VARCHAR2(3);
CURSOR c_2 IS
SELECT 'ABC' col1,
'DEF' col2
FROM dual;
BEGIN
LOOP
FETCH c_2 INTO func_arg, other_arg;
EXIT WHEN c_2%NOTFOUND;
v_2 := Fn_return_cur(func_arg);
END LOOP;
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
/
Let me know your feedback.

How to create a new OBJECT TYPE in Oracle PL/SQL if it doesn't already exist

I need to declare a new OBJECT TYPE in PL/SQL to hold rows in a join query that only selects a few columns. I can create the TYPE just fine, but it becomes part of the schema.
Something like:
IF (SELECT COUNT(*) FROM user_objects WHERE LOWER(object_name) = 'my_custom_type') = 0 THEN
CREATE TYPE my_custom_type AS OBJECT
(
...
);
/
END IF;
DECLARE
v_foo my_custom_type%TYPE;
BEGIN
-- Do stuff with v_foo...
END;
/
How can I check to see if the TYPE exists before creating it?
If you need new SQL-type. You may create it using dynamic SQL.
DECLARE
v_count NUMBER(10);
BEGIN
SELECT COUNT(*) INTO v_count
FROM user_objects
WHERE LOWER(object_name) = 'my_custom_type';
IF v_count = 0 THEN
EXECUTE IMMEDIATE 'CREATE TYPE my_custom_type AS OBJECT (
id NUMBER(10),
name VARCHAR2(100)
)';
END IF;
END;
/