Oracle reading JSON data using json_query - json

While working on oracle json datatype and trying to extract data from it, not able to extract name & value elements from this. tried using all known notations but getting null.
select json_query(po_document, '$.actions.parameters[0]') from j_purchaseorder where ID='2';

You can use the JSON_VALUE function as follows:
SQL> select JSON_VALUE('{"_class":"123", "name":"tejash","value":"so"}', '$.name') as name,
2 JSON_VALUE('{"_class":"123", "name":"tejash","value":"so"}', '$.value') as value
3 from dual;
NAME VALUE
---------- ----------
tejash so
SQL>

Thanks for your help. got required output using below
select json_value(json_query(po_document, '$.actions.parameters[0]'),'$.value') from j_purchaseorder where ID='2' and
json_value(json_query(po_document, '$.actions.parameters[0]'),'$.name') = 'SERVERUSER';

As explained, for example, in the Oracle documentation, multiple calls to JSON_VALUE() on the same JSON document may result in very poor performance. When we need to extract multiple values from a single document, it is often best (for performance) to make a single call to JSON_TABLE().
Here is how that would work on the provided document. First I create and populate the table, then I show the query and the output. Note the handling of column (attribute) "_class", both in the JSON document and in the SQL SELECT statement. In both cases the name must be enclosed in double-quotes, because it begins with an underscore.
create table j_purchaseorder (
id number primary key,
po_document clob check (po_document is json)
);
insert into j_purchaseorder (id, po_document) values (
2, '{"_class":"hudson.model.StringParameterValue","name":"SERVERUSER","value":"avlipwcnp04"}'
);
commit;
select "_CLASS", name, value
from j_purchaseorder
cross apply
json_table(po_document, '$'
columns (
"_CLASS" varchar2(40) path '$."_class"',
name varchar2(20) path '$.name',
value varchar2(20) path '$.value'
)
)
where id = 2
;
_CLASS NAME VALUE
---------------------------------------- ------------------ ------------------
hudson.model.StringParameterValue SERVERUSER avlipwcnp04

Related

oracle CLOB modify to obtain columns for json_table()

Since oracle does not support dynamic conversion of JSON column keys as relational column and JSON column value as relational column value, I had thought to generate my dynamic list of columns as CLOB column
col_a,col_b,col_c,col_d
and then convert it into below form
col_a NUMBER(22,3) PATH '$.col_a',col_b NUMBER(22,3) PATH '$.col_b',col_c NUMBER(22,3) PATH '$.col_c',col_d NUMBER(22,3) PATH '$.col_d'
Basically each of my column "col_a" is converted to "col_a NUMBER(22,3) PATH '$.col_a'"
so that I can directly place this clob value in my plsql block and fetch like below
select t.*,jt.*
from
table_1 t,
json_table(t.json_doc,'$' columns (col_a NUMBER(22,3) PATH '$.col_a',col_b NUMBER(22,3) PATH '$.col_b',col_c NUMBER(22,3) PATH '$.col_c',col_d NUMBER(22,3) PATH '$.col_d'))jt
but I'm not sure if i can do it using REPLACE or any other function.
I'm able to achieve it by concatenating while generating the original list of dynamic columns, but that additional burden I want to avoid.
NOTE: All columns are NUMBER(22,3) datatypes so not a burden on that side.
If your CLOB is valid JSON, you may be able to retrieve the keys for your CLOB using the function json_dataguide. Below is an example
My Table
create table json_doc (
data clob check (data is json)
);
insert into json_doc(data) values ('{"col1": "A"}');
insert into json_doc(data) values ('{"col2": "B"}');
Checking the table
select doc.data from json_doc doc;
-- DATA
-- 1 {"col1": "A"}
-- 2 {"col2": "B"}
Then using json_dataguide
select json_dataguide(doc.data) columns from json_doc doc;
-- COLUMNS
-- 1 [{"o:path":"$","type":"object","o:length":16},{"o:path":"$.col1","type":"string","o:length":1},{"o:path":"$.col2","type":"string","o:length":1}]
Finally, using json_table
select jt.* from
(select json_dataguide(doc.data) columns from json_doc doc) d,
json_table(d.columns, '$[*]' COLUMNS (
path varchar2(22) path '$."o:path"'
)) jt
-- PATH
-- 1 $
-- 2 $.col1
-- 3 $.col2
You can then get the JSON keys including the root (which you can easily remove as well as the $. in the beginning, perhaps using LTRIM).
If this solves your problem, remember to mark it as the answer ;)

JSON_VALUE for Nameless JSON payload

Just started playing with JSON_VALUE in SQL Server. I am able to pull values from name/value pairs of JSON but I happen to have an object that looks like this:
["first.last#domain.com"]
When I attempt what works for name/value pairs:
SELECT TOP 1
jsonemail,
JSON_VALUE(jsonemail, '$') as pleaseWorky
FROM MyTable
I get back the full input, not first.last#domain.com. Am I out of luck? I don't control the upstream source of the data. I think its a sting collection being converted into a json payload. If it was name: first.last#domain.com I would be able to get it with $.name.
Thanks in advance.
It is a JSON array. So you just need to specify its index, i.e 0.
Please try the following solution.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, jsonemail NVARCHAR(MAX));
INSERT INTO #tbl (jsonemail) VALUES
('["first.last#domain.com"]');
-- DDL and sample data population, end
SELECT ID
, jsonemail AS [Before]
, JSON_VALUE(jsonemail, '$[0]') as [After]
FROM #tbl;
Output
+----+---------------------------+-----------------------+
| ID | Before | After |
+----+---------------------------+-----------------------+
| 1 | ["first.last#domain.com"] | first.last#domain.com |
+----+---------------------------+-----------------------+
From the docs:
Array elements. For example, $.product[3]. Arrays are zero-based.
So you need JSON_VALUE(..., '$[0]') when the root is an array and you want the first value.
To break it out into rows, you would need OPENJSON:
SELECT TOP 1
jsonemail
,j.[value] as pleaseWorky
FROM MyTable
CROSS APPLY OPENJSON(jsonemail) j

How do I return a JSON updated document in Oracle?

From the docs I see an example:
SELECT json_mergepatch(po_document, '{"Special Instructions":null}'
RETURNING CLOB PRETTY)
FROM j_purchaseorder;
But When I try this code in SQL Developer I get a squiggly line under CLOB and an error when I run the query?
It works in Oracle 18c:
SELECT json_mergepatch(
po_document,
'{"Special Instructions":null}'
RETURNING CLOB PRETTY
) AS updated_po_document
FROM j_purchaseorder;
Which for the test data:
CREATE TABLE j_purchaseorder( po_document CLOB CHECK ( po_document IS JSON ) );
INSERT INTO j_purchaseorder ( po_document )
VALUES ( '{"existing":"value", "Special Instructions": 42}' );
Outputs:
| UPDATED_PO_DOCUMENT |
| :------------------------------- |
| {<br> "existing" : "value"<br>} |
Removing the Special Instructions attribute as per the documentation you linked to:
When merging object members that have the same field:
If the patch field value is null then the field is dropped from the source — it is not included in the result.
Otherwise, the field is kept in the result, but its value is the result of merging the source field value with the patch field value. That is, the merging operation in this case is recursive — it dives down into fields whose values are themselves objects.
db<>fiddle here

postgres force json datatype

When working with JSON datatype, is there a way to ensure the input JSON must have elements. I don't mean primary, I want the JSON that gets inserted to at least have the id and name element, it can have more but at the minimum the id and name must be there.
thanks
The function checks what you want:
create or replace function json_has_id_and_name(val json)
returns boolean language sql as $$
select coalesce(
(
select array['id', 'name'] <# array_agg(key)
from json_object_keys(val) key
),
false)
$$;
select json_has_id_and_name('{"id":1, "name":"abc"}'), json_has_id_and_name('{"id":1}');
json_has_id_and_name | json_has_id_and_name
----------------------+----------------------
t | f
(1 row)
You can use it in a check constraint, e.g.:
create table my_table (
id int primary key,
jdata json check (json_has_id_and_name(jdata))
);
insert into my_table values (1, '{"id":1}');
ERROR: new row for relation "my_table" violates check constraint "my_table_jdata_check"
DETAIL: Failing row contains (1, {"id":1}).

how to parse json using json_populate_recordset in postgres

I have a json stored as text in one of my database row. the json data is as following
[{"id":67272,"name":"EE_Quick_Changes_J_UTP.xlsx"},{"id":67273,"name":"16167.txt"},{"id":67274,"name":"EE_12_09_2013_Bcum_Searchall.png"}]
to parse this i want to use postgresql method
json_populate_recordset()
when I post a command like
select json_populate_recordset(null::json,'[{"id":67272,"name":"EE_Quick_Changes_J_UTP.xlsx"},{"id":67273,"name":"16167.txt"},{"id":67274,"name":"EE_12_09_2013_Bcum_Searchall.png"}]') from anoop;
it gives me following error
first argument of json_populate_recordset must be a row type
note : in the from clause "anoop" is the table name.
can anyone suggest me how to use the json_populate_recordset method to extract data from this json string.
I got method's reference from
http://www.postgresql.org/docs/9.3/static/functions-json.html
The first argument passed to pgsql function json_populate_recordsetshould be a row type. If you want to use the json array to populate the existing table anoop you can simply pass the table anoop as the row type like this:
insert into anoop
select * from json_populate_recordset(null::anoop,
'[{"id":67272,"name":"EE_Quick_Changes_J_UTP.xlsx"},
{"id":67273,"name":"16167.txt"},
{"id":67274,"name":"EE_12_09_2013_Bcum_Searchall.png"}]');
Here the null is the default value to insert into table columns not set in the json passed.
If you don't have an existing table, you need to create a row type to hold your json data (ie. column
names and their types) and pass it as the first parameter, like this anoop_type:
create TYPE anoop_type AS (id int, name varchar(100));
select * from json_populate_recordset(null :: anoop_type,
'[...]') --same as above
no need to create a new type for that.
select * from json_populate_recordset(null::record,'[{"id_item":1,"id_menu":"34"},{"id_item":2,"id_menu":"35"}]')
AS
(
id_item int
, id_menu int
)