SQL Oracle, returning a table from a Function - sql

I was trying create a function (maybe procedure will be better?) which return a table. Presently I have this:
CREATE OR REPLACE TYPE rowx AS OBJECT
(
nam1 VARCHAR2 (100),
nam2 VARCHAR2 (100)
);
/
CREATE OR REPLACE TYPE tablex
IS TABLE OF rowx;
/
CREATE OR REPLACE FUNCTION example(FS varchar2)
RETURN tablex
IS
tab tablex;
BEGIN
select y.ident as PARENT, x.ident as CHILD into tab
from relation2 rt
inner join plate x on rt.child = x.id
inner join plate y on rt.parent =y.id
where x.ident like 'string1' or y.ident like 'string2';
RETURN tab;
END;
After compilation above function I recive ORA-00947. Any tips?

Your query is selecting two scalar values, and trying to put them into a table of an object type. That type has two fields, but there is no automatic comversion. So you need to build the object explicitly, which you can do as part of the query.
You should also use a bulk query to populate your collection:
select rowx(y.ident, x.ident)
bulk collect into tab
from relation2 rt
...

Have a look at this example; does it help?
My TEST table represents your tables. This function returns a collection, which is then used in SELECT statement along with the TABLE operator.
SQL> create table test (nam1 varchar2(10), nam2 varchar2(10));
Table created.
SQL> insert into test values ('Little', 'Foot');
1 row created.
SQL> insert into test values ('Stack', 'Overflow');
1 row created.
SQL> create or replace type t_tf_row as object (nam1 varchar2(10), nam2 varchar2(10));
2 /
Type created.
SQL> create or replace type t_tf_tab is table of t_tf_row;
2 /
Type created.
SQL>
SQL> create or replace function get_tab_tf return t_tf_tab as
2 l_tab t_tf_tab := t_tf_tab();
3 begin
4 for cur_r in (select nam1, nam2 from test) loop
5 l_tab.extend;
6 l_tab(l_tab.last) := t_tf_row(cur_r.nam1, cur_r.nam2);
7 end loop;
8 return l_tab;
9 end;
10 /
Function created.
SQL>
SQL> select * From table(get_Tab_tf);
NAM1 NAM2
--------------------
Little Foot
Stack Overflow
SQL>

Related

Select a column from table return by function in Oracle

I have a function that returns a table of custom objects. I wish to select a certain column by name from the returned result.
create or replace type sd_Serial_Number as object (
serial_number VARCHAR2(32)
);
The table of objects
create or replace type sd_Serial_Number_Table as table of sd_Serial_Number;
The function
create function get_result
return sd_Serial_Number_Table as
v_ret sd_Serial_Number_Table;
begin
select sd_Serial_Number(selected.SERIAL_NUMBER)
bulk collect into v_ret
from (
selection here
) selected;
return v_ret;
end get_result;
When I call the function this way, I get a result with a single column called SERIAL_NUMBER
select * from table(get_result());
However, I can't do something like this
select SERIAL_NUMBER from table(get_result());
Is there a way to select the column SERIAL_NUMBER ?
"I can't" is difficult to debug. I'll show you that I can (on the same database version you use).
SQL> SELECT * FROM v$version WHERE rownum = 1;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
SQL> CREATE OR REPLACE TYPE sd_serial_number AS OBJECT
2 (
3 serial_number VARCHAR2 (32)
4 );
5 /
Type created.
SQL> CREATE OR REPLACE TYPE sd_serial_number_table AS TABLE OF sd_serial_number;
2 /
Type created.
SQL> CREATE OR REPLACE FUNCTION get_result
2 RETURN sd_serial_number_table
3 AS
4 v_ret sd_serial_number_table;
5 BEGIN
6 SELECT sd_serial_number (deptno)
7 BULK COLLECT INTO v_ret
8 FROM dept;
9
10 RETURN v_ret;
11 END get_result;
12 /
Function created.
Testing:
SQL> SELECT * FROM TABLE (get_result ());
SERIAL_NUMBER
--------------------------------
10
20
30
40
SQL> SELECT serial_number FROM TABLE (get_result ());
SERIAL_NUMBER
--------------------------------
10
20
30
40
SQL>

Select records from table where table name come from another table

We generate tables dynamically Eg. Table T_1, T_2, T_3, etc & we can get that table names from another table by following query.
SELECT CONCAT('T_', T_ID) AS T_NAME FROM T_NAMES WHERE T_KEY = 'ABC';
Now I want to get records from this retrieved table name. What can I do ?
I'm doing like following but that's not working :
SELECT * FROM (SELECT CONCAT('T_', T_ID) AS T_NAME FROM T_NAMES WHERE T_KEY = 'ABC')
FYI : I'm hitting two individual queries as of now though I want to eliminate one and I can not follow cursor/procedure approach due to some limitations.
A procedure which utilizes refcursor seems to be the most appropriate to me. Here's an example:
SQL> -- creating test case (your T_NAMES table and T_1 which looks like Scott's DEPT)
SQL> create table t_names (t_id number, t_key varchar2(3));
Table created.
SQL> insert into t_names values (1, 'ABC');
1 row created.
SQL> create table t_1 as select * from dept;
Table created.
SQL> -- a procedure; accepts KEY and returns refcursor
SQL> create or replace procedure p_test
2 (par_key in varchar2, par_out out sys_refcursor)
3 as
4 l_t_name varchar2(30);
5 begin
6 select 'T_' || t_id
7 into l_t_name
8 from t_names
9 where t_key = par_key;
10
11 open par_out for 'select * from ' || l_t_name;
12 end;
13 /
Procedure created.
OK, let's test it:
SQL> var l_out refcursor
SQL> exec p_test('ABC', :l_out)
PL/SQL procedure successfully completed.
SQL> print l_out
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL>
I could propose to you Dynamic SQL.
First of all, you need to create a cursor. The cursor will iterate by the dynamic tables. Then you could use dynamic SQL to create a query and then execute it.
So example:
https://livesql.oracle.com/apex/livesql/file/content_C81136WLRFYZF8ION6Q57GWE1.html - detailed cursor example.
https://docs.oracle.com/cd/B28359_01/appdev.111/b28370/dynamic.htm#i13057 - dynamic SQL in Oracle

Array Input for Stored Procedure

I am a newbie to Oracle and this is my first post for Oracle queries.
Below is the existing query which inserts 1 row for each SP call.
I want to make change in the SP which would accept input as array where SAP system would would send the Array to Stored Procedure.
As you observe in SP, the value of ID is incremented each time with the each update. The SP will take this input of Phone and Text and insert the value of ID in sequence wise.The ID is not passed in the input.
CREATE OR REPLACE PROCEDURE DetailsTable
(
Phoneno IN NUMBER,
Text IN VARCHAR2
)
aS
BEGIN
INSERT INTO PERSON.DETAILS(
ID,
PHONENO,
TEXT,
COUNTRY,
LANG,
--PRIORITY,
SENDER)
VALUES (
DETAILS_seq.nextval ,
p_phoneno,
p_text ,
'RSA',
'EN',
'Nest-Payroll');
commit;
END DetailsTable;
Please guide.
SQL> CREATE OR REPLACE TYPE arraytype AS VARRAY(1000) OF VARCHAR2(100);
2 /
Type created
SQL> CREATE OR REPLACE PROCEDURE test_array (in_array arraytype) IS
2 BEGIN
3 FOR i IN 1..in_array.count LOOP
4 DBMS_OUTPUT.PUT_LINE(in_array(i));
5 END LOOP;
6 END;
7 /
Procedure created
SQL> DECLARE
2 var_array arraytype;
3 BEGIN
4 var_array := arraytype();
5 var_array.EXTEND(10);
6 var_array(1) := '1st sentence in the array';
7 var_array(2) := '2nd sentence in the array';
8 test_array(var_array);
9 END;
10 /
1st sentence in the array
2nd sentence in the array
We can use a Type in SQL but it needs to be declared as a SQL Type:
create or replace type person_t as object
(phoneno number
, text varchar2(100)
);
/
create or replace type person_nt as table of person_t
/
Use it like this:
CREATE OR REPLACE PROCEDURE DetailsTable
(
p_array in person_nt
)
aS
BEGIN
INSERT INTO PERSON.DETAILS(
ID,
PHONENO,
TEXT,
COUNTRY,
LANG,
--PRIORITY,
SENDER)
select DETAILS_seq.nextval ,
t.phoneno,
t.text ,
'RSA',
'EN',
'Nest-Payroll'
from table (p_array)t;
commit;
END DetailsTable;
/

Using Table type in IN-clause in PLSQL procedure

I have a procedure which takes table type input parameter. Now I have to use this parameter in IN-clause of SELECT query.
CREATE TYPE ids IS TABLE OF NUMBER;
CREATE PROCEDURE (emp_ids IN ids) IS
CURSOR IS (SELECT * FROM EMPLOYEES WHERE EMP_ID IN (SELECT * FROM TABLE(emp_ids)); .....
But I found that this code is not going to work because local collection types cannot be used in an SQL statement.
Is there any alternate way to achieve using table type parameter in a SELECT statement?
According to what you have posted, you are declaring collection as schema object, not the local type. This means that you shouldn't have any problems of using it. Here is an example:
-- collection type as schema object
SQL> create or replace type ids is table of number;
2 /
Type created
SQL> create or replace procedure proc1 (emp_ids IN ids)
2 IS
3 cursor c is (
4 select first_name
5 from employees
6 where employee_id in (select column_value
7 from table(emp_ids)
8 )
9 );
10 begin
11 for i in c
12 loop
13 dbms_output.put_line(i.first_name);
14 end loop;
15 end;
16 /
Procedure created
SQL> exec proc1(ids(101, 103, 200));
Neena
Alexander
Jennifer
PL/SQL procedure successfully completed

Cursor on record table type in Oracle

I am having a declaration as shown below
type respond_field
IS
record
(
provider_id VARCHAR2(100),
provider_name VARCHAR2(100));
type respond_field_group
IS
TABLE OF respond_field INDEX BY BINARY_INTEGER;
I have created an variable for respond_field_group and i have populated values for this virtual table.
My prblem is how to i can convert/transfer this virtual table to a cursor.
What i have tried is show below respond_values is variable of respond_field_group
OPEN v_result_cursor for SELECT provider_id FROM TABLE (Cast(respond_values AS respond_field));
But i am getting invalid datatype
Please help me out to find a solution for this problem
You cannot use pl/sql types like this, only sql types (i.e. types defined at schema level not at package or procedure level). Record and associative array (index by table) are pl/sql types. Instead you have to create appropriate object types and use them in your code, for example:
SQL> create type respond_field as object
2 (
3 provider_id varchar2(100),
4 provider_name varchar2(100)
5 )
6 /
Type created.
SQL> create type respond_field_group as table of respond_field
2 /
Type created.
SQL> create or replace function test_fun return respond_field_group as
2 l_rfgroup respond_field_group := respond_field_group();
3 begin
4 l_rfgroup.extend(2);
5 l_rfgroup(1) := respond_field('abc', '123');
6 l_rfgroup(2) := respond_field('def', '456');
7 return l_rfgroup;
8 end;
9 /
Function created.
SQL> select * from table(test_fun);
PROVIDER_ID PROVIDER_NAME
--------------- ---------------
abc 123
def 456