PL/SQL APEX_JSON how to parse to CLOB variable - plsql

I'm trying to parse a json object like this one:
{
"sites": [
{
"code": "code",
"siteName": "site name",
"country": "country",
"arrayToClob": [
{
"field1": "field 1",
"field2": "field 2"
}
]
}
]
}
and I want to store the value of "arrayToClob" element into a Clob column of my DB and for that I'm trying to get the value of that element as a whole. This is what I tried:
APEX_JSON.parse(MY_JSON);
l_count := APEX_JSON.get_count('sites');
FOR i IN 1 .. l_count LOOP
l_code := APEX_JSON.get_varchar2('sites[%d].code', i);
l_siteName := APEX_JSON.get_varchar2('sites[%d].siteName', i);
l_country := APEX_JSON.get_varchar2('sites[%d].country', i);
l_value := APEX_JSON.get_array('sites[%d].arrayToClob', i);
END LOOP;
where l_value is type json_array_t... but of course is not working. I've tried also with varchar2 type and I've check other options here https://docs.oracle.com/cd/E59726_01/doc.50/e39149/apex_json.htm#AEAPI29655
I don't know how to approach it, I don't know if it's even possible what I want... any tips will be welcome.
Thanks in advance

You mean that the value for "field1" is a CLOB value in your actual data ? If that is not the case and it is just a varchar it's possible to use JSON_TABLE to get what you want in a plain SQL statement. Note that APEX_JSON isn't very performant.
with json_tab AS
(
SELECT
'{
"sites": [
{
"code": "code",
"siteName": "site name",
"country": "country",
"arrayToClob": [
{
"field1": "field 1",
"field2": "field 2"
}
]
}
]
}' as data FROM DUAL
)
SELECT jt.code, jt.field1, jt.field2
FROM json_tab t,
JSON_TABLE(
data,
'$.sites[*]'
columns (
code VARCHAR2(100) PATH '$.code',
NESTED PATH '$.arrayToClob[*]'
columns (
field1 VARCHAR2(32000) PATH '$.field1',
field2 VARCHAR2(32000) PATH '$.field2'
)
)
) jt;
JSON_TABLE does not support CLOB datatype as column - so if it really is a CLOB it won't work.

Related

Oracle Apex 22.21 - REST data source - nested JSON array - sync two tables by trigger - PLSQL error question

This question is a follow up to another SO question.
I've actually recreated the tables from the previous question. The updated JSON response can be found at the bottom of this question.
ORDERS_LOCAL table
ORDERS_LOCAL table data. ORDER_ITEMS column is the JSON array that I need to extract into ORDER_ITEMS_LOCAL table.
ORDER_ITEMS_LOCAL table. LINE_ID column should be created automatically. ORDER_ID column is a foreign key to ORDERS_LOCAL table. PRODUCT_ID column is a foreign key to PRODUCTS table. LINE_NUMBER is just the order line number (line 1 = product 1, price, qty | line 2 = product 2, price, qty etc..) I believe it's called a sequence type?
PRODUCTS table
PRODUCTS table data
Per Carsten's answer, I've created a new trigger for the ORDERS table from the Object Browser.
I've then entered Carsten's PLSQL code from the previous question. He did mention that it was pseudo-code. So I tried to update it..
create or replace trigger "TR_MAINTAIN_LINES"
AFTER
insert or update or delete on "ORDERS_LOCAL"
for each row
begin
if inserting then
insert into ORDER_ITEMS_LOCAL ( line_id, order_id, line_number, product_id, quantity, price)
( select :new.id,
seq_lines.nextval,
j.line_number,
j.product_id,
j.quantity,
j.price
from json_table(
:new.order_items,
'$[*]' columns (
line_number for ordinality,
product_id number path '$.product_id',
quantity number path '$.quantity',
price number path '$.price' ) ) );
elsif deleting then
delete ORDER_ITEMS_LOCAL
where order_id = :old.id;
elsif updating then
delete ORDER_ITEMS_LOCAL
where order_id = :old.id;
--
-- handle the update case here.
-- I would simply delete and re-insert LINES rows.
end if;
end;
I am receiving the following errors
Compilation failed, line 4 (08:38:57) The line numbers associated with compilation errors are relative to the first BEGIN statement. This only affects the compilation of database triggers.
PLS-00049: bad bind variable 'NEW.ID'Compilation failed, line 19 (08:38:57) The line numbers associated with compilation errors are relative to the first BEGIN statement. This only affects the compilation of database triggers.
PLS-00049: bad bind variable 'OLD.ID'Compilation failed, line 22 (08:38:57) The line numbers associated with compilation errors are relative to the first BEGIN statement. This only affects the compilation of database triggers.
PLS-00049: bad bind variable 'OLD.ID'
I believe this is due to missing columns in the trigger code but I'm not sure.
I am new to PLSQL and parsing the JSON is kind of confusing.. especially below. Please see my comments.
if inserting then
insert into ORDER_ITEMS_LOCAL ( line_id, order_id, line_number, product_id, quantity, price)
( select :new.id, -- is this new id for `line_id`
order_id -- how to insert order_id foreign key
seq_lines.nextval, -- not sure what this is for?
j.line_number, -- I changed 'lines' to 'order_items' so should this be seq_order_items.nextval, ?
j.product_id,
j.quantity,
j.price
from json_table(
:new.order_items, -- I changed 'lines' to 'order_items' so I changed this from :new.lines,
'$[*]' columns ( -- Would I include 'line_id' and 'order_id' in here as well?
line_number for ordinality,
product_id number path '$.product_id',
quantity number path '$.quantity',
price number path '$.price' ) ) );
Updated JSON response
[
{
"order_id": "HO9b6-ahMY-B2i9",
"order_number": 34795,
"order_date": "2022-11-02",
"store_id": 2,
"full_name": "Ronda Perfitt",
"email": "rperfitt1#microsoft.com",
"city": "Fresno",
"state": "California",
"zip_code": "93762",
"credit_card": "5108758574719798",
"order_items": [
{
"line_number": 1,
"product_id": 2,
"quantity": 1,
"price": 3418.85
},
{
"line_number": 2,
"product_id": 7,
"quantity": 1,
"price": 4070.12
}
]
},
{
"order_id": "RFvUC-sN8Y-icJP",
"order_number": 62835,
"order_date": "2022-10-09",
"store_id": 1,
"full_name": "Wash Rosenfelt",
"email": "wrosenfelt3#wisc.edu",
"city": "Chicago",
"state": "Illinois",
"zip_code": "60646",
"credit_card": "5048372443777103",
"order_items": [
{
"line_number": 1,
"product_id": 1,
"quantity": 1,
"price": 3349.05
},
{
"line_number": 2,
"product_id": 3,
"quantity": 1,
"price": 4241.29
},
{
"line_number": 3,
"product_id": 1,
"quantity": 1,
"price": 3560.03
}
]
},
]
I apologize for making this confusing. I really want to learn how to do this right. Your support is much appreciated. Thank you.
In the trigger code, the :old and :new prefixes reference the row of your table, before and after the trigger operation. So ...
In the UPDATING case, :old.{column-name} references the value of a table column column before the update, :new.{column-name} references the value after the update.
In the INSERTING case, there is no :old.{column-name} (thus that would be NULL); :new.{column-name} references the inserted value.
And in the DELETING case, there is no :new.{column-name} value; only :old.{column-name} is available.
You see the compiler error, as my trigger pseudo-code contained :new.id, but your table does not have a column named ID; it's ORDER_ID in your case. So you need to adjust that code accordingly.
https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/plsql-triggers.html#GUID-E76C8044-6942-4573-B7DB-3502FB96CF6F

How to query data in Cosmos db from nested json

I have some difficulty in writing a query to query data from nested json in Cosmos db.
Sample json -
{
"id": xyz
"items": [
{
"arr_id": 1,
"randomval": "abc"
},
{
"arr_id": 2,
"randomval": "mno"
},
{
"arr_id": 1,
"randomval": "xyz"
}
]
}
Lets say in above case, if i want to get all jsons data with arr_id = 1.
Expected Result -
{
"id": xyz
"items": [
{
"arr_id": 1,
"randomval": "abc"
},
{
"arr_id": 1,
"randomval": "xyz"
}
]
}
If i write a query like below, it still gives me entire json.
Select * from c where ARRAY_CONTAINS(c.items, {"arr_id": 1},true)
I want it to filter it items level too. I guess it just filters at header level and provides entire json where even a single arr_id matches.
You can use either
SELECT c.id, ARRAY(SELECT VALUE i FROM i in c.items where i.arr_id = 1) as items
FROM c
WHERE EXISTS(SELECT VALUE i FROM i in c.items where i.arr_id = 1)
or
SELECT c.id, ARRAY(SELECT VALUE i FROM i in c.items where i.arr_id = 1) as items
FROM c
depending on whether you expect an empty array if no arrayItem with arr_id=1 exists or you wnat to filter out those records compeletely.
Also see this link for a good overview of query options across arrays - https://devblogs.microsoft.com/cosmosdb/understanding-how-to-query-arrays-in-azure-cosmos-db/

Union Results of Multiple OPENJSON calls

I have a table that stores 1 json object per row, I want to call OPENJSON on the json object stored in each row and union together all of the results. I don't know the number of rows I will have ahead of time.
Here is some example data to reference
DROP TABLE #tmp_json_tbl
DECLARE #json1 NVARCHAR(2048) = N'{
"members": [
{
"name": "bob",
"status": "subscribed"
},
{
"name": "larry",
"status": "unsubscribed"
}
]
}';
SELECT #json1 as json_obj,1 as jid into #tmp_json_tbl
INSERT into #tmp_json_tbl
VALUES ( N'{
"members": [
{
"name": "bob",
"status": "subscribed"
},
{
"name": "larry",
"status": "unsubscribed"
}
]
}',2 );
SELECT * from #tmp_json_tbl
--how can i recursively union together results for all values of jid?
-- I could use a cursor but I would rather figure out a way to do it using a recursive cte
SELECT * FROM OpenJson((SELECT json_obj from #tmp_json_tbl where jid=1), '$.members')
WITH (
name VARCHAR(80) '$.name',
mstatus varchar(100) '$.status'
)```
This is what I wanted
SELECT name, m_status
FROM #tmp_json
CROSS APPLY OPENJSON(j, '$.members')
WITH (
name VARCHAR(80) '$.name',
m_status varchar(100) '$.status'
)
Found my answer here: How to use OPENJSON on multiple rows

Get value from JSON on conditional base

how to get the value from a specific attribute on the basis of value check of another attribute value in oracle 12c. Below is the JSON
{
"Operational_Cost21":[
{
"Input1":"20000",
"Operational_cost23":"Diesel"
},
{
"Input1":"5000",
"Operational_cost23":"Maintenance"
},
{
"Input1":"20000",
"Operational_cost23":"Other Variable Cost"
},
{
"Input1":"100000",
"Operational_cost23":"Driver Salary"
}
]
}
I want to get the value of input value where operational_cost23 = 'Driver Salary'
expected Value = 100000
You should first add this constraint into your table.CONSTRAINT ensure_json2 CHECK (SAMP IS JSON). Then you can use JSON_TABLE function.
Documentation
DROP TABLE TESTTABLE CASCADE CONSTRAINTS ;
CREATE TABLE TESTTABLE
(
SAMP CLOB
CONSTRAINT ensure_json2 CHECK (SAMP IS JSON));
INSERT INTO TESTTABLE
VALUES (
'{ "Operational_Cost21": [
{
"Input1": "20000",
"Operational_cost23": "Diesel"
},
{
"Input1": "5000",
"Operational_cost23": "Maintenance"
},
{
"Input1": "20000",
"Operational_cost23": "Other Variable Cost"
},
{
"Input1": "100000",
"Operational_cost23": "Driver Salary"
}
]
}');
SELECT J.Input1,J.Operational_cost23
FROM TESTTABLE,
JSON_TABLE(SAMP,'$.Operational_Cost21[*]' COLUMNS
Input1 VARCHAR2(20) PATH '$.Input1',
Operational_cost23 VARCHAR2(20) PATH '$.Operational_cost23'
) J
where operational_cost23 = 'Driver Salary'

Return the content of a specific object in an array — CosmosDB

This is a follow up to question 56126817
My current query
SELECT c.EventType.EndDeviceEventDetail FROM c
WHERE c.EventType.EndDeviceEventType.eventOrAction = '93'
AND c.EventType.EndDeviceEventType.subdomain = '137'
AND c.EventType.EndDeviceEventType.domain = '26'
AND c.EventType.EndDeviceEventType.type = '3'
AND ARRAY_CONTAINS(c.EventType.EndDeviceEventDetail,{"name":
"RCDSwitchReleased","value": "true" })
My Query Output
[
{
"EndDeviceEventDetail": [
{
"name": "Spontaneous",
"value": "true"
},
{
"name": "DetectionActive",
"value": "true"
},
{
"name": "RCDSwitchReleased",
"value": "true"
}
]
}
]
Question
How could change my query so that I select only the "value" of the array that contains the "name" "DetectionActive" ?
The idea behind is to filter the query on one array entry and get as output the "value" of another array entry. From reading here, UDF (not the best in this case) and JOIN should be used.
First attempt
SELECT t.value FROM c JOIN t in c.EventType.EndDeviceEventDetail
WHERE c.EventType.EndDeviceEventType.eventOrAction = '93'
AND c.EventType.EndDeviceEventType.subdomain = '137'
AND c.EventType.EndDeviceEventType.domain = '26'
AND c.EventType.EndDeviceEventType.type = '3'
AND ARRAY_CONTAINS(c.EventType.EndDeviceEventDetail,{"name":
"RCDSwitchReleased","value": "true" })
Gets Bad Request (400) error
Your idea and direction is right absolutely, I simplified and tested your sql.
SELECT detail.value FROM c
join detail in c.EventType.EndDeviceEventDetail
WHERE c.EventType.EndDeviceEventType.eventOrAction = '93'
AND ARRAY_CONTAINS(c.EventType.EndDeviceEventDetail,{"name":
"RCDSwitchReleased","value": "true" })
Found the error message as below:
It because that the value is the reserved word in cosmos db sql syntax,please refer to this case:Using reserved word field name in DocumentDB
You could try to modify the sql like:
SELECT detail["value"] FROM c

Resources