Example for SQL_TO_JSON - pljson

How to use the function JSON_UTIL_PKG.SQL_TO_JSON? Please give an example.
I tried this:
select JSON_UTIL_PKG.SQL_TO_JSON('select column from table where rownum = 1',100) from dual;
but the result is not ok

The declaration of that function is:
function sql_to_json (p_sql in varchar2,
p_max_rows in number := null,
p_skip_rows in number := null) return json_list
Thus, the result should be a pljson.json_list object. Since the only information you have given is "the result is not okay" I can only assume you are expecting the result to be a JSON string. If that is the case, and your result is stored in a variable named foo, then you can use foo.to_char to generate the string. Or foo.to_clob to return the JSON string as a CLOB.

I tried to execute as:
declare jlist json_list;
Begin
jlist := json_utl_pkg.sql_to_json('select col1, col2 from mytable', 10, 0);
end;
This shows an error like "jlist invalid left assignement"...
Then I tried this one, and it worked:
declare jobj json;
begin
jobj := json_dyn.executeObject('select * from myTable');
jobj.print;
end;
It worked correctly!
Based on:https://github.com/oberstet/pljson/blob/master/examples/ex16.sql
Best regards

Related

Is there a way to INSERT Null value as a parameter using FireDAC?

I want to leave some fields empty (i.e. Null) when I insert values into table. I don't see why would I want to have a DB full of empty strings in fields.
I use Delphi 10, FireDAC and local SQLite DB.
Edit: Provided code is just an example. In my application values are provided by user input and functions, any many of them are optional. If value is empty, I would like to keep it at Null or default value. Creating multiple variants of ExecSQL and nesting If statements isn't an option too - there are too many optional fields (18, to be exact).
Test table:
CREATE TABLE "Clients" (
"Name" TEXT,
"Notes" TEXT
);
This is how I tried it:
var someName,someNote: string;
begin
{...}
someName:='Vasya';
someNote:='';
FDConnection1.ExecSQL('INSERT OR REPLACE INTO Clients(Name,Notes) VALUES (:nameval,:notesval)',
[someName, IfThen(someNote.isEmpty, Null, somenote)]);
This raises an exception:
could not convert variant of type (Null) into type (OleStr)
I've tried to overload it and specify [ftString,ftString] and it didn't help.
Currently I have to do it like this and I hate this messy code:
FDConnection1.ExecSQL('INSERT OR REPLACE INTO Clients(Name,Notes) VALUES ('+
IfThen(someName.isEmpty,'NULL','"'+Sanitize(someName)+'"')+','+
IfThen(someNote.isEmpty,'NULL','"'+Sanitize(someNote)+'"')+');');
Any recommendations?
Edit2: Currently I see an option of creating new row with "INSERT OR REPLACE" and then use multiple UPDATEs in a row for each non-empty value. But this looks direly ineffective. Like this:
FDConnection1.ExecSQL('INSERT OR REPLACE INTO Clients(Name) VALUES (:nameval)',[SomeName]);
id := FDConnection1.ExecSQLScalar('SELECT FROM Clients VALUES id WHERE Name=:nameval',[SomeName]);
if not SomeString.isEmpty then
FDConnection1.ExecSQL('UPDATE Clients SET Notes=:noteval WHERE id=:idval)',[SomeNote,id]);
According to Embarcadero documentation ( here ):
To set the parameter value to Null, specify the parameter data type,
then call the Clear method:
with FDQuery1.ParamByName('name') do begin
DataType := ftString;
Clear;
end;
FDQuery1.ExecSQL;
So, you have to use FDQuery to insert Null values, I suppose. Something like this:
//Assign FDConnection1 to FDQuery1's Connection property
FDQuery1.SQL.Text := 'INSERT OR REPLACE INTO Clients(Name,Notes) VALUES (:nameval,:notesval)';
with FDQuery1.ParamByName('nameval') do
begin
DataType := ftString;
Value := someName;
end;
with FDQuery1.ParamByName('notesval') do
begin
DataType := ftString;
if someNote.IsEmpty then
Clear;
else
Value := someNote;
end;
if not FDConnection1.Connected then
FDConnection.Open;
FDQuery1.ExecSql;
It's not very good idea to execute query as String without parameters because this code is vulnerable to SQL injections.
Some sources tells that it's not enough and you should do something like this:
with FDQuery1.ParamByName('name') do begin
DataType := ftString;
AsString := '';
Clear;
end;
FDQuery1.ExecSQL;
but I can't confirm it. You can try it if main example won't work.

how to get file size or object size in oracle

I have an table contain three columns ID,Obj_name,Object in a table. Object refers to metadata/File which is located in folder. How can write a script to check what is the file size of each object.
Output like
ID,Obj_name,Object,File_size.
let me know if there is any idea.
Try this :
DECLARE
v_fexists BOOLEAN;
v_file_length NUMBER;
v_block_size BINARY_INTEGER;
BEGIN
UTL_FILE.FGETATTR
('NFS_DIR', 'west.txt', v_fexists, v_file_length,
v_block_size);
DBMS_OUTPUT.PUT_LINE (v_file_length);
END;
Since object is a bfile, you can do something like
CREATE OR REPLACE FUNCTION( p_id IN INTEGER )
RETURN INTEGER
IS
l_bfile bfile;
l_length integer;
BEGIN
SELECT object
INTO l_bfile
FROM your_table
WHERE id = p_id;
DBMS_LOB.OPEN(l_bfile, DBMS_LOB.LOB_READONLY);
/* Get the length of the LOB: */
l_length := DBMS_LOB.GETLENGTH(l_bfile);
DBMS_LOB.CLOSE(l_bfile);
RETURN l_length;
END;
and then call that function from your query passing in the id. Note that this example is taken directly from the documentation on LOBs

Return ref_cursor from for loop of cursor object

I am trying to get a ref_cursor to be assigned to a variable inside a for loop then returned at the end of a function. The loop in going through a local cursor if it gets more than 1 result.
I have noted where the error occurs in the code. I am not sure how to create a loop where i can get a ref_cursor for the current point in the loop, assign it to a variable and then return it to the function. Could someone someone help me figure out how to do that? Below is my i-th attempt at logic based of reading around the google searches.
The error is "PLS-00382: expression is of wrong type" and i know that i obviously am not assigning the correct variably type based on this error but the code below with the error is an illustration of what I want to do and what I need help accomplishing.
FUNCTION GET_PARCEL(p_lat in number, p_long in number) return sys_refcursor
IS
v_distance number(10) := 100000000;
v_shortest_dist number(10) := v_distance;
v_centroid SDO_GEOMETRY;
v_rc_ref_cursor sys_refcursor;
v_ref_geom SDO_GEOMETRY := mdsys.SDO_GEOMETRY(2001, 8311, NULL, SDO_ELEM_INFO_ARRAY(1, 1, 1), SDO_ORDINATE_ARRAY(120.3214, -10.7088));
cursor query_cursor is select * from PARCEL_TABLE where code = 20134;
BEGIN
for query_row in query_cursor loop
v_centroid := SDO_GEOM.SDO_CENTROID(query_row.geometry, 0.05);
IF (v_centroid is not null) then
v_distance := SDO_GEOM.SDO_DISTANCE(v_centroid, v_ref_geom, 0.05);
IF v_distance < v_shortest_dist THEN
v_shortest_dist := v_distance;
v_rc_ref_cursor := query_row; -- Error on this line
END IF;
ELSE
DBMS_OUTPUT.PUT_LINE('Centroid is not initialised for some reason.');
END IF;
end loop;
return v_rc_ref_cursor;
END;
As far as I know, you cannot build up a cursor. Cursors are created and maintained by the database with connections to their source data, transaction and session context, and the like.
I would suggest you declare a type, instantiate it, build up the values in the type.
When you are done, create a cursor by selecting * from table (cast (variable as your_type)).
Munge the cursor into a ref_cursor and return that.
Pro tip is to remember you have data in your table and you can use it for logic. Turns out if I use the IDENTIFIER or ROWID of the row/s which i want then i can do a where clause into a ref cursor that looks up by IDENTIFIER or ROWID.
eg.
open v_rc_ref_cursor for select * from PARCEL_TABLE n where n.identifier = query_row.identifier;
super simple stuff :)

oracle pl sql function having errors

I want to create a function that returns the number of rows in a table called Rating with a where clause.Where am i going wrong before the declare statement and the end statement?
create or replace
FUNCTION get_movies(user IN NUMBER) RETURN NUMBER
IS
DECLARE cnt NUMBER;
BEGIN
SELECT count(*)
INTO cnt
FROM rating
where userid= user;
RETURN cnt;
END;
I will appreciate help.Thanks.
You should not have the DECLARE keyword. You only need that for an anonymous block (or a sub-block).
create or replace
FUNCTION get_movies(p_userid IN NUMBER) RETURN NUMBER
IS
cnt NUMBER;
BEGIN
...
user is a reserved word so I'd suggest not using that as your parameter name. In the where clause I'm not sure if it will use your parameter value, or the name of the user executing the function; which would error as that string value couldn't be implicitly converted to a number.

Can't use PLSQL ConvertToBlob inside a loop

I have a problem when trying to convert CLOB from a table to BLOB into another table.
Basically I'm looping inside a PLSQL array, the first call to DBMS_LOB.convertToBlob always works well, but the next iterations either create an empty blob or give me an error ORA-22275: invalid LOB locator specified, depending on whether I initialize my blob inside or outside the loop.
So, if I do :
BEGIN
FOR i IN 1 .. rs.COUNT
LOOP
DBMS_LOB.createTemporary (v_blob, TRUE);
DBMS_LOB.convertToBlob (v_blob,
rs (i).v_clob,
DBMS_LOB.LOBMAXSIZE,
v_in,
v_out,
DBMS_LOB.DEFAULT_CSID,
v_lang,
v_warning);
[...]
DBMS_LOB.freeTemporary(v_blob);
It converts the first blob well but only returns empty blobs for the other ones.
If I do:
BEGIN
DBMS_LOB.CREATETEMPORARY (v_blob, TRUE);
FOR i IN 1 .. rs.COUNT
LOOP
DBMS_LOB.convertToBlob(...);
It also converts the first blob well but I get the ORA-22275: invalid LOB locator specified error after the first iteration.
How could I avoid this? I can't seem to find good explanation for this. Thanks for your help!
Must be a NULL value problem. The CLOB must not be NULL. The following code gives me the error on the third round.
set serveroutput on
declare
TYPE rs_rec_type IS RECORD (
v_clob clob
);
TYPE rs_rec_table_type IS TABLE OF rs_rec_type INDEX BY pls_integer;
rs rs_rec_table_type;
v_blob blob;
v_in integer := 1;
v_out integer := 1;
v_lang integer := 0;
v_warning integer := 0;
BEGIN
rs(1).v_clob := 'foo';
rs(2).v_clob := 'bar';
rs(3).v_clob := null;
FOR i IN 1 .. rs.COUNT
LOOP
DBMS_LOB.createTemporary (v_blob, TRUE);
dbms_output.put_line('i='||i);
DBMS_LOB.convertToBlob (v_blob,
rs (i).v_clob,
DBMS_LOB.LOBMAXSIZE,
v_in,
v_out,
DBMS_LOB.DEFAULT_CSID,
v_lang,
v_warning);
dbms_output.put_line('done i='||i);
DBMS_LOB.freeTemporary(v_blob);
end loop;
end;
Output
Error report:
ORA-06502: PL/SQL: numeric or value error: invalid LOB locator specified: ORA-22275
ORA-06512: at "SYS.DBMS_LOB", line 991
ORA-06512: at line 20
06502. 00000 - "PL/SQL: numeric or value error%s"
*Cause:
*Action:
i=1
done i=1
i=2
done i=2
i=3
I experienced a similar problem when using temporary blobs within a loop.
I resolved it by initialising the in, out, lang and warning parameters each time.
James.
This worked for me:
declare
cursor note is
select id, rtf_clob
from rtf_data
where rtf_clob is not null
for update of rtf_blob;
l_blob blob;
l_amt integer := dbms_lob.lobmaxsize;
l_dest_offset integer := 1;
l_src_offset integer := 1;
l_csid integer := dbms_lob.default_csid;
l_ctx integer := dbms_lob.default_lang_ctx;
l_warn integer;
begin
for note_rec in note loop
l_blob := null;
l_amt := dbms_lob.lobmaxsize;
l_dest_offset := 1;
l_src_offset := 1;
l_csid := dbms_lob.default_csid;
l_ctx := dbms_lob.default_lang_ctx;
l_warn := null;
dbms_lob.createTemporary(l_blob, true);
dbms_lob.convertToBlob(l_blob,
note_rec.rtf_clob,
l_amt,
l_dest_offset,
l_src_offset,
l_csid,
l_ctx,
l_warn );
update rtf_data
set rtf_blob = l_blob
where note_rec.id = id;
dbms_lob.freeTemporary(l_blob);
end loop;
end;
/
Without reinitializing the variables inside the loop, only the first record created a blob.
This error might occur when the CLOB contains NULL.
This means the CLOB variable is passed NULL to the DBMS_LOB.convertToBlob
I had a similar problem to this and I figured something about DBMS_LOB.convertToBlob. The variables that you enter as dest_offset and src_offset change after the go through the procedure in question so you have to reset them after every iteration, in the case that you want to create multiple files.
I don't know if that helps directly with this problem in particular, but keep it in mind, for future reference, in case one uses DBMS_LOB.convertToBlob inside a loop.

Resources