PLSQL record or collection into json object - oracle

I need to convert a Pl/SQl record or collection into json object using json_object(*) function.Is it possible or is there any other way?

As long as they are database types (not solely PLSQL types) you could do it with a table function, eg
SQL> create or replace
2 type the_row as object (
3 x int,
4 y int );
5 /
Type created.
SQL>
SQL> create or replace
2 type the_row_list as table
3 of the_row
4 /
Type created.
SQL>
SQL> -- interestingly, direct SELECT fails
SQL>
SQL> select json_object(*)
2 from table(the_row_list(the_row(1,1),the_row(2,2)));
select json_object(*)
*
ERROR at line 1:
ORA-40579: star expansion is not allowed
SQL> -- but a WITH is ok
SQL> with t as
2 (
3 select *
4 from table(the_row_list(the_row(1,1),the_row(2,2)))
5 )
6 select json_object(*)
7 from t;
JSON_OBJECT(*)
-------------------------------------------------------------------
{"X":1,"Y":1}
{"X":2,"Y":2}

Related

SQL statement ignored and missing opening parenthesis

I get these errors during a creation of a trigger but I don't understand why
create or replace NONEDITIONABLE TRIGGER magazzino_bef_ins
BEFORE INSERT ON MAGAZZINO
FOR EACH ROW
DECLARE
tempcodice varchar2(8);
cacc char(3);
ogg int;
CURSOR cursore_disp IS
SELECT cacciatore, oggetto
FROM TABLE EDDY.disponibilita
WHERE ID_DISPONIBILITA = :NEW.disponibilità;
BEGIN
CURSOR cursore_disp IS
SELECT cacciatore, oggetto
FROM TABLE DISPONIBILITA
WHERE ID_DISPONIBILITA = :NEW.disponibilità;
open cursore_disp;
fetch cursore_disp into cacc,ogg;
temp:= pk_gestione_magazzino.genera_catalogo(cacc,ogg);
:new.codcatalogo:=temp;
END;
The errors are:
Error(5,9): PL/SQL: SQL Statement ignored
Errore(6,20): PL/SQL: ORA-00906: missing opening parenthesis
Errore(9,8): PLS-00103: encountered symbol "CURSORE_DISP" instead of one of the following: := . ( # % ;
I can't understand these errors, I'm just trying to take the values from a table in where the id inserted is equal in the other table.
Here's how. I created test environment which is kind of stupid, but it makes the following code work.
SQL> create table magazzino (disponibilita number, codcatalogo varchar2(8));
Table created.
SQL> create table disponibilita (cacciatore char(3), oggetto number, id_disponibilita number);
Table created.
SQL> create or replace package pk_gestione_magazzino as
2 function genera_catalogo (cacc number, ogg number) return varchar2;
3 end;
4 /
Package created.
SQL> create or replace package body pk_Gestione_magazzino as
2 function genera_catalogo (cacc number, ogg number) return varchar2 is
3 begin
4 return 'Little';
5 end;
6 end;
7 /
Package body created.
Trigger which causes you trouble: no need for a cursor; moreover, you have two of them (was it just a typo)? It looks as if you used it to avoid no data found error. If so, don't do it - it just makes confusion. Handle exceptions properly. By the way, you "forgot" to close the cursor.
SQL> create or replace trigger magazzino_bef_ins
2 before insert on magazzino
3 for each row
4 declare
5 cacc char(3);
6 ogg int;
7 begin
8 select cacciatore, oggetto
9 into cacc, ogg
10 from disponibilita
11 where id_disponibilita = :new.disponibilita;
12
13 :new.codcatalogo := pk_gestione_magazzino.genera_catalogo (cacc, ogg);
14 end;
15 /
Trigger created.
Testing:
SQL> insert into disponibilita values (1, 1, 1);
1 row created.
SQL> insert into magazzino (disponibilita) values (1);
1 row created.
SQL> select * From magazzino;
DISPONIBILITA CODCATAL
------------- --------
1 Little
SQL>
Works, kind of.

Convert T-SQL INNER JOIN on a Function to PL-SQL

I have a T-SQL view that does this:
LEFT JOIN fnc_AssetAttributeByType(3) tmp
ON
A.AssetID = tmp.AssetID;
Is there a straight forward way I can translate this (I'm writing a tool to do it programmatically) without creating a package or modifying the header of the function that would void other calls to it in other DML statements?
Main questions:
1. Can I even write a PL function that returns a table?
2. If not, what should I do?
You can create a function that returns a table type, and work on it in SQL by using it inside a table() clause. The user running the SQL needs execute privilege on the function.
SQL> create or replace type tp_asset as object (assetId number, asset_name varchar2(100), asset_val number)
2 /
Type created
SQL> create or replace type tp_tab_asset is table of tp_asset;
2 /
Type created
SQL> create or replace function fnc_AssetAttributeByType(p_num in number) return tp_tab_asset pipelined as
2 v_tp_asset tp_asset;
3 begin
4 for i in 1 .. 3
5 loop
6 v_tp_asset := tp_asset(i, 'ABC', i * 3);
7 pipe row (v_tp_asset);
8 end loop;
9 return;
10 end;
11 /
Function created
SQL> select *
2 from table(fnc_AssetAttributeByType(3)) a
3 left join table(fnc_AssetAttributeByType(3)) b on b.assetid = a.assetid;
ASSETID ASSET_NAME ASSET_VAL ASSETID ASSET_NAME ASSET_VAL
---------- --------------- ---------- ---------- --------------- ----------
1 ABC 3 1 ABC 3
2 ABC 6 2 ABC 6
3 ABC 9 3 ABC 9

Join nested table and normal table to fetch the result

I am having a normal table temp and a nested table temp_nt
Temp
-------------
ID Status
-------------
1 open
2 close
3 open
4 open
5 close
---------------
Suppose my nested table is having list of ID, X
Lets say the data in nested table is like
temp_nt(1).ID=1 temp_nt(1).X='ANC'
temp_nt(2).ID=2 temp_nt(2).X='pqr'
temp_nt(3).ID=3 temp_nt(3).X='ANCF'
temp_nt(4).ID=4 temp_nt(4).X='ANCF'
Can it be possible to join both to get the data like below,
Status COUNT
-----------------------
open 3
close 1
-----------------------
Since ID=5 is not present in the nested table, therefore it is excluded from the count
It would help to define exactly what objects you're working with...
You have a table with 5 rows of data
SQL> create table foo(
2 id number,
3 status varchar2(10)
4 );
Table created.
SQL> insert into foo values( 1, 'open' );
1 row created.
SQL> insert into foo values( 2, 'close' );
1 row created.
SQL> insert into foo values( 3, 'open' );
1 row created.
SQL> insert into foo values( 4, 'open' );
1 row created.
SQL> insert into foo values( 5, 'close' );
1 row created.
But then how is your nested table defined? Is it defined in SQL or PL/SQL? Are you using the object from SQL or PL/SQL?
If you have defined the nested table in SQL
SQL> create type foo_obj is object (
2 id number,
3 status varchar2(10)
4 );
5 /
Type created.
SQL> create type foo_nt
2 as table of foo_obj;
3 /
Type created.
And you are using the nested table in PL/sQL, you can use the TABLE operator
SQL> ed
Wrote file afiedt.buf
1 declare
2 l_foos foo_nt := new foo_nt();
3 begin
4 l_foos.extend(4);
5 l_foos(1) := new foo_obj( 1, 'ANC' );
6 l_foos(2) := new foo_obj( 2, 'pqr' );
7 l_foos(3) := new foo_obj( 3, 'ANCF' );
8 l_foos(4) := new foo_obj( 4, 'ANCF' );
9 for x in (select t.status, count(*) cnt
10 from foo t,
11 table( l_foos ) l
12 where t.id = l.id
13 group by t.status)
14 loop
15 dbms_output.put_line( x.status || ' ' || x.cnt );
16 end loop;
17* end;
SQL> /
close 1
open 3
PL/SQL procedure successfully completed.
Is that what you're looking for? Or do you have a different setup?
If you are defining a local collection in PL/SQL, you won't be able to use that collection in a SQL statement since the SQL engine isn't able to access any information about the collection type. If you want to use the collection in SQL, it would make much more sense to define the collection in SQL.

How can I do forward declarations in Oracle?

Here is my situation: type A wants to have a method that returns a type that is a table of type A entries. Can I do this?
Here is a pair of SQL Type declarations:
SQL> create or replace type a as object
2 ( attr1 number
3 , attr2 date )
4 /
Type created.
SQL> create or replace type a_nt as table of a
2 /
Type created.
SQL>
Now what we want is a method which returns A_NT(). Hmm, let's see:
SQL> alter type a
2 add member function getme (p1 number) return a_nt
3 /
alter type a
*
ERROR at line 1:
ORA-04055: Aborted: "A" formed a non-REF mutually-dependent cycle with "A_NT".
SQL>
Uh-oh. We need another approach. This is the sort of occasion when we should be using inheritance.
SQL> create or replace type abstract_a as object
2 ( attr1 number
3 , attr2 date )
4 not final not instantiable
5 /
Type created.
SQL> create or replace type a_nt as table of abstract_a
2 /
Type created.
SQL> create or replace type a under abstract_a
2 ( member function getme (p1 number) return a_nt )
3 instantiable
4 /
Type created.
SQL>
Looks good. So, we'll add an implementation and then try it out:
SQL> create or replace type body a as
2 member function getme (p1 number) return a_nt
3 is
4 l_nt a_nt;
5 begin
6 select a(empno, hiredate)
7 bulk collect into l_nt
8 from emp
9 where deptno = p1;
10 return l_nt;
11 end;
12 end;
13 /
Type body created.
SQL>
Let's roll!
SQL> set serveroutput on
SQL> declare
2 v a := a(null, null);
3 n a_nt;
4 begin
5 n := v.getme(50);
6
7 for i in n.first()..n.last() loop
8 dbms_output.put_line(n(i).attr1 ||'::'||to_char(n(i).attr2, 'DD-MON-YYYY'));
9 end loop;
10 end;
11 /
8085::08-APR-2010
8060::08-APR-2008
8061::27-FEB-2010
8100::
PL/SQL procedure successfully completed.
SQL>
The bootstrapping is cumbersome but it works. This may be yet another area where Oracle's OOP implementation is incomplete. But perhaps it's just a reflection of the fact that is not a good idea. It took me a while to figure it out, because the underlying model doesn't really make sense. Although maybe with Real World names it would have become obvious :)

Create Oracle procedure error - declare custom type

I'm attempting to create a procedure in Oracle Express Server (Application Express 2.1.0.00.39) using the web interface.
This is the SQL I'm running via the SQL Commands option in the web interface
CREATE OR REPLACE PROCEDURE my_procedure (listOfNumbers num_list,
v_value varchar2)
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
UPDATE my_table
SET my_column = v_value
WHERE my_row_id IN (SELECT column_value
FROM TABLE(listOfNumbers));
COMMIT;
END;
UPDATE:
Changed SELECT column_value FROM TABLE to SELECT column_value FROM TABLE(listOfNumbers) but now I get the following error:
PLS-00201: identifier 'num_list' must
be declared
UPDATE 2:
Here is how I created my type:
CREATE OR REPLACE TYPE "num_list" as table of NUMBER(38,1)
/
Seems the error is being caused on the parameter declaration line:
(listOfNumbers num_list, v_value varchar2)
Below is the object details as displayed by the Oracle Database Express Edition web interface.
Try ...TABLE(CAST(listOfNumbers AS num_list)).
The SQL parser simply sees a bind placeholder in place of listOfNumbers, and since it's a custom type you need to tell it what type it is.
This will only work if num_list has been defined as a type in the schema, not just declared as a type in a PL/SQL block.
Your code works - providing the array type has been declared correctly (see below). As you are still having a problem I suspect that is where you are going wrong. But you need to post the code you are using to create the NUM_LIST type in order for us to correct it.
My test data:
SQL> select * from my_table
2 /
MY_COLUMN MY_ROW_ID
-------------------- ----------
APC 1
XYZ 2
JFK 3
SQL>
In order to use a type in a SQL statement we must create it as a SQL object:
SQL> create type num_list as table of number;
2 /
Type created.
SQL>
SQL>
SQL> create or replace procedure my_procedure
2 (listofnumbers num_list,
3 v_value varchar2)
4 is
5 begin
6
7 update my_table
8 set my_column = v_value
9 where my_row_id in (select column_value
10 from table(listofnumbers));
11
12 end;
13 /
Procedure created.
SQL>
Executing the procedure:
SQL> declare
2 n num_list := num_list(1,3);
3 begin
4 my_procedure (n , 'FOX IN SOCKS');
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
And lo!
SQL> select * from my_table
2 /
MY_COLUMN MY_ROW_ID
-------------------- ----------
FOX IN SOCKS 1
XYZ 2
FOX IN SOCKS 3
SQL>
Apparently I was creating the type with quotes around the name:
The following didn't work:
CREATE OR REPLACE TYPE "NUMBER_T" as table of NUMBER(38,1)
When I did it without the quotes and then created the procedure, it was able to recognize it.
The following did work:
CREATE OR REPLACE TYPE NUMBER_T as table of NUMBER(38,1)
I'm not sure why, but it worked.

Resources