function that put XML output back to table - sql

Use Oracle database and PL/SQL. I created procedure that generete XML output from table in my base. But, also, need reverse procedure that can put XML output back to table. Finding function to generate XML from table was easy (dbms_xmlgen.getXML). But I cannot find reverse function. Please, write here if you know reverse function.
To XML:
create or replace
PROCEDURE xml_apt
AS
doc clob;
BEGIN
doc := dbms_xmlgen.getXML('select * from аpt');
dbms_output.put_line(doc);
END xml_apt;

You could use DBMS_XMLSave
see: ORACLE Documentation
Probably something like this to update a row....(untested)
PROCEDURE yourTableHere_UPDATE (xmlDoc in clob, ret OUT number)
IS
updCtx DBMS_XMLSave.ctxType;
BEGIN
updCtx := DBMS_XMLSave.newContext('yourTableHere');
DBMS_XMLSave.setignorecase(updCtx,1);
DBMS_XMLSave.setrowtag(updCtx,'yourrowtag');
DBMS_XMLSave.clearUpdateColumnList(updCtx);
DBMS_XMLSave.setKeyColumn(updCtx,'ID');
ret := DBMS_XMLSave.updateXML(updCtx,xmlDoc);
DBMS_XMLSave.closeContext(updCtx);
commit;
END;

Related

How to make a function that takes code like "SELECT * FROM SOME_TABLE" as an input and returns a table as an output?

I want to create a function that takes some code as an input (e.g. Select * FROM SOME_TABLE) and returns the result of a query as an output.
I want to use it in procedures in order to return tables as a result.
It should look like this:
BEGIN
--some procedure code
CREATE TABLE SOME_TABLE as Select * FROM ...;
Select * FROM table(my_function('Select * FROM SOME_TABLE'));
END;
Important tips:
The resulting table can have multiple columns, from 1 to +inft
The resulting table can have multiple rows, from 1 to +inft
So the size of a table can be both very small or very large.
The input query can have several where, having, partition, and other Oracle constructions.
I want to have a table as an output, not DBMS_OUTPUT.
I can't install any modules/applications, or use other languages hints. However, I can manually create types, functions, procedures.
I tried to search in the net but could not find a solution that meets all my expectations. The best link I've found was this:
https://sqljana.wordpress.com/2017/01/22/oracle-return-select-statement-results-like-sql-server-sps-using-pipelined-functions/
DBMS_SQL.RETURN_RESULT works if your "code" is a select query
DECLARE
l_cur SYS_REFCURSOR;
l_query VARCHAR2(4000) := 'select * from SOME_TABLE';
BEGIN
OPEN l_cur for l_query;
DBMS_SQL.RETURN_RESULT(l_cur);
END;
/
you can create a function that has a string as parameter and return a cursor.
select statement you should pass as a string. in a function you can open a Cursor.
declare
v_sql varchar2(100) := 'select 1,2,3,4,5 from dual';
cur_ref SYS_REFCURSOR;
function get_data(in_sql in varchar2) return SYS_REFCURSOR
as
cur_ret SYS_REFCURSOR;
begin
OPEN cur_ret FOR in_sql;
return cur_ret;
end;
begin
:cur_ref := get_data(v_sql);
end ;
if your select statement is longer than 32K than you maybe should use a clob instead of varchar2 for your Parameter type. But you have to try that

PL/SQL equivalent of SELECT statement

What would be the PL/SQL equivalent of this SQL query:
SELECT * FROM table(OWNER.PACKAGE.get_exam('123456789'));
This is the Function that I am trying to call:
FUNCTION get_exam(id IN VARCHAR2)
RETURN ab_assign_v1
IS
CURSOR c_exams(cid VARCHAR2) IS
SELECT t_api_exam_v1(
sei.person_id, --unique id
l.description --loc description
)
FROM my_view sei
JOIN loc l
ON sei.loc_code = l.loc_code
v_collection ab_assign_v1;
BEGIN
OPEN c_exams(id);
FETCH c_exams BULK COLLECT INTO v_collection;
CLOSE c_exams;
RETURN v_collection;
EXCEPTION
WHEN OTHERS THEN
error_a1.raise_error(SQLCODE, SQLERRM);
END get_exam;
Hope this helps.
DECLARE
lv <COLLECTION_NAME>;
BEGIN
lv:= OWNER.PACKAGE.get_exam('123456789');
dbms_output.put_line(lv.COUNT);
END;
/
Assuming that you want to return the result of a function :
select owner.package.get_exam('123456789') from table
Your function returns a nested table type. You simply need to declare a variable of that type, and assign to it as you would if it were a scalar:
declare
l_coll your_collection_type;
begin
l_coll := OWNER.PACKAGE.get_exam('123456789');
end;
/
In this example your_collection_type is a placeholder for whatever object your function actually returns.
" I am getting this error: PLS-00201: identifier 'ab_assign_v1' must be declared "
ab_assign_v1 is the type used by your function. From the code posted in your revised question it seems that type is in the same schema which owns the package with the function. However your original pseudo-code prefixes the call with the schema name. So, putting two and two together, you need to revise the variable declaration to include the schema too. (You may need to grant EXECUTE on it too, if you haven't done this already).
declare
l_coll OWNER.ab_assign_v1;
begin
l_coll := OWNER.PACKAGE.get_exam('123456789');
end;
/

How to output multiple rows from an existing table in a stored procedure using oracle sql developer?

I have an existing Customers table and want to output each row from this table using a stored procedure. There is no input criteria, just need to output all of the records.
The stored procedure should basically be equivalent to:
"SELECT C_ID, LAST, FIRST, DOB, DPHONE, EMAIL FROM customers;"
This seems simple but I can't figure it out. All my searches haven't worked out for this case.
How would one accomplish this?
EDIT: Answered my question below. Very simple.
In Oracle your options are:
1. Use a function and return a REF CURSOR
2. Use a procedure and use a REF CURSOR as an OUT parameter
3. Use a PIPELINED function
4. Use a function and return a collection.
read this documentation
Overview of Table Functions
see similar question here Return collection from packaged function for use in select
simple sample of such function
CREATE FUNCTION StockPivot(p refcur_pkg.refcur_t) RETURN TickerTypeSet
PIPELINED IS
out_rec TickerType := TickerType(NULL,NULL,NULL);
in_rec p%ROWTYPE;
BEGIN
LOOP
FETCH p INTO in_rec;
EXIT WHEN p%NOTFOUND;
-- first row
out_rec.ticker := in_rec.Ticker;
out_rec.PriceType := 'O';
out_rec.price := in_rec.OpenPrice;
PIPE ROW(out_rec);
-- second row
out_rec.PriceType := 'C';
out_rec.Price := in_rec.ClosePrice;
PIPE ROW(out_rec);
END LOOP;
CLOSE p;
RETURN;
END;
/
Nevermind! Just got it. It is pretty simple. I just did this:
CREATE OR REPLACE PROCEDURE CustomerReport AS
BEGIN
FOR cus IN (SELECT C_ID, LAST, FIRST, DOB, DPHONE, EMAIL FROM customers)
LOOP
dbms_output.put_line(cus.C_ID||' '||cus.FIRST||' '||cus.LAST||' '||cus.DOB||' '||cus.DPHONE||' '||cus.EMAIL);
END LOOP;
END;

Stored search procedure in oracle 12c

I have a table in an Oracle 12c databse called testimonial that has content as a column. I have created a stored search procedure to find testimonials whose content matches an input string that is defined as:
CREATE OR REPLACE PROCEDURE Search_Testimonials
(keyword IN VARCHAR2,
output OUT SYS_REFCURSOR)
AS
BEGIN OPEN output
FOR SELECT *
FROM Testimonial T
WHERE T.content LIKE keyword;
END;
/
VAR output REFCURSOR;
DECLARE
keyword VARCHAR2(15) := '%like%';
BEGIN
Search_Testimonials(keyword, :output);
END;
/
I am trying to run a test on this procedure using the input 'like'. From what I have found on this site and other sites I should run the following:
var output refcursor;
exec Search_Testimonials('like', output);
print output;
However my output is just:
OUTPUT
------
When it should display all the records in testimonial table as they all contain the word 'like.'
Am I messing up something in the procedure? I've looked around and this seems to be how to do it as far as I can figure. Thanks!

Oracle SQL Developer, using dynamic SQL in function

I have the following script which contains a function named 'myFunction'. (declaration of types named rowValueTmp and rowValueTable are also attached for your information) Basically, I need to use a table name as an input parameter for myFunction. I found that I need to use dynamic SQL in order to use the table name as a parameter (Please correct me if there are alternative ways to do this). So the following code is what I have tried so far.
create or replace type rowValueTmp as object (
month number,
year number
);
/
create or replace type rowValueTable as table of rowValueTmp;
/
create or replace FUNCTION myFunction (TABLENAME in VARCHAR2)
return rowValueTable as
v_ret rowValueTable;
begin
execute immediate '
select rowValueTmp(month, year)
bulk collect into v_ret
from '||TABLENAME;
return v_ret;
end myFunction;
/
select * from table(myFunction('SCHEMA.TEST'));
But, this code gives me an error, and I assumed that this error is occurred because of using 'bulk collect' in execute immediate block.
ORA-03001: unimplemented feature
If I replace the content of execute immediate as the following, the above script is working..
select rowValueTmp(month, year)
bulk collect into v_ret
from SCHEMA.TEST;
Question
1] Is there any way(rather than Dynamic SQL) that I can use a table name as an input parameter for myFunction?
2] If I am not allowed to use bulk collect in execute immediate block, what do you suggest?
You can return values from execute immediately into a bulk collect:
CREATE OR REPLACE FUNCTION myfunction (tablename IN VARCHAR2)
RETURN rowvaluetable AS
v_ret rowvaluetable;
v_table VARCHAR2 (61) := DBMS_ASSERT.sql_object_name (tablename);
BEGIN
EXECUTE IMMEDIATE '
select rowValueTmp(month, year)
from ' || v_table
BULK COLLECT INTO v_ret;
RETURN v_ret;
END myfunction;
/
In the interest of an abundance of caution, I'd recommend using DBMS_ASSERT to validate the table parameter as well (as shown).