Create JSON from XML - JSON_AGG OUTPUT PROBLEM - sql

I have a problem with converting XML content to JSON format (with plain oracle select statement), where more then 1 sub level of data is present in the original XML - with my code the result of level 2+ is presented as string and not as JSON_OBJECT. Please, could someone tell me, where is fault in my code or what I'm doing wrong:
source:
<envelope>
<sender>
<name>IZS</name>
<country>SU</country>
<address>LOCATION 10B</address>
<address>1000 CITY</address>
<sender_identifier>SU46794093</sender_identifier>
<sender_address>
<sender_agent>SKWWSI20XXX</sender_agent>
<sender_mailbox>SI56031098765414228</sender_mailbox>
</sender_address>
</sender>
</envelope>
transformation select statement:
WITH SAMPLE AS (SELECT XMLTYPE ('
<envelope>
<sender>
<name>IZS</name>
<country>SU</country>
<address>LOCATION 10B</address>
<address>1000 CITY</address>
<sender_identifier>SU46794093</sender_identifier>
<sender_address>
<sender_agent>SKWWSI20XXX</sender_agent>
<sender_mailbox>SI56031098765414228</sender_mailbox>
</sender_address>
</sender>
</envelope>') XMLDOC FROM DUAL)
SELECT JSON_SERIALIZE (
JSON_OBJECT (
KEY 'envelope' VALUE
JSON_OBJECTAGG (
KEY ID_LEVEL1 VALUE
CASE ID_LEVEL1
WHEN 'sender' THEN
( SELECT JSON_OBJECTAGG (
KEY ID_LEVEL2 VALUE
CASE ID_LEVEL2
WHEN 'sender_address' THEN
( SELECT JSON_OBJECTagg (KEY ID_LEVEL22 VALUE TEXT_LEVEL22)
FROM XMLTABLE ('/sender/sender_address/*'
PASSING XML_LEVEL2
COLUMNS ID_LEVEL22 VARCHAR2 (128) PATH './name()',
TEXT_LEVEL22 VARCHAR2 (128) PATH './text()'
)
)
ELSE
TEXT_LEVEL2
END)
FROM XMLTABLE ('/sender/*'
PASSING XML_LEVEL2
COLUMNS ID_LEVEL2 VARCHAR2 (1024) PATH './name()',
TEXT_LEVEL2 VARCHAR2 (1024) PATH './text()'
)
)
ELSE
'"' || TEXT_LEVEL1 || '"'
END FORMAT JSON)
) PRETTY
)JSON_DOC
FROM SAMPLE, XMLTABLE ('/envelope/*'
PASSING XMLDOC
COLUMNS ID_LEVEL1 VARCHAR2 (1024) PATH './name()',
TEXT_LEVEL1 VARCHAR2 (1024) PATH './text()',
XML_LEVEL2 XMLTYPE PATH '.'
);
wrong result:
{
"envelope" :
{
"sender" :
{
"name" : "IZS",
"country" : "SU",
"address" : "LOCATION 10B",
"address" : "1000 CITY",
"sender_identifier" : "SU46794093",
"sender_address" : "{\"sender_agent\":\"SKWWSI20XXX\",\"sender_mailbox\":\"SI56031098765414228\"}"
}
}
}
wrong part:
***"sender_address" : "{\"sender_agent\":\"SKWWSI20XXX\",\"sender_mailbox\":\"SI56031098765414228\"}"***

For the level 1 text you're wrapping the value in double-quotes and specifying format json; you aren't doing that for level 2. If you change:
ELSE
TEXT_LEVEL2
END
to:
ELSE
'"' || TEXT_LEVEL2 || '"'
END FORMAT JSON)
then the result is:
{
  "envelope" :
  {
    "sender" :
    {
      "name" : "IZS",
      "country" : "SU",
      "address" : "LOCATION 10B",
      "address" : "1000 CITY",
      "sender_identifier" : "SU46794093",
      "sender_address" :
      {
        "sender_agent" : "SKWWSI20XXX",
        "sender_mailbox" : "SI56031098765414228"
      }
    }
  }
}
fiddle

The problem is that you need kind of conditional "FORMAT JSON" in the "SELECT JSON_OBJECTAGG ( KEY ID_LEVEL2 VALUECASE ID_LEVEL2": when the ID_LEVEL2 is 'sender_address' but not in the ELSE part, but the syntax requires you put after the END of CASE, and of course this fails for the "ELSE TEXT_LEVEL2" part.

Related

ORACLE : renaming a key in a json field by oracle

I have a table in which in one of the columns there is a json data as below
COLUMN NAME : JSON_CODE
{
"DataElaborazione" : "20220718",
"DataMovimento" : "20220531",
"DataRiferimento" : "20220715",
}
I want to rename DataRiferimento to datarif
expected result
COLUMN NAME : JSON_CODE
{
"DataElaborazione" : "20220718",
"DataMovimento" : "20220531",
"datarif" : "20220715",
}
see image for structure
thank you
You can use JSON_TRANSFORM function:
select JSON_TRANSFORM('{ "DataElaborazione" : "20220718", "DataMovimento" : "20220531", "DataRiferimento" : "20220715" }',
RENAME '$.DataRiferimento' = 'datarif')
from dual
Or JSON_OBJECT_T:
declare
v_json JSON_OBJECT_T;
begin
v_json := JSON_OBJECT_T('{ "DataElaborazione" : "20220718", "DataMovimento" : "20220531", "DataRiferimento" : "20220715" }');
v_json.rename_key('DataRiferimento', 'datarif');
dbms_output.put_line(v_json.stringify);
end;
You can create function and use it in your query:
create or replace function renameJsonKey(p_json IN VARCHAR2,
p_old_key IN VARCHAR2,
p_new_key IN VARCHAR2) return VARCHAR2
RESULT_CACHE RELIES_ON (your_table)
is
v_json JSON_OBJECT_T;
begin
v_json := JSON_OBJECT_T(p_json);
v_json.rename_key(p_old_key, p_new_key);
return v_json.stringify;
end;
select renameJsonKey(col, 'DataRiferimento', 'datarif') from your table

Migrating data from jsonb to integer[] SQL

I have jsonb field(data) in Postgresql with a structure like:
{ "id" => { "some_key" => [1, 2, 3] } }
I need to migrate the value to a different field.
t.jsonb "data"
t.integer "portals", default: [], array: true
When I'm trying to do like this:
UPDATE table_name
SET portals = ARRAY[data -> '1' ->> 'portals']
WHERE id = 287766
It raises an error:
Caused by PG::DatatypeMismatch: ERROR: column "portals" is of type integer[] but expression is of type text[]
Here is one way to do it. But if you search the site, as you should had to do, you get more.
Schema
create table t (
data jsonb
);
insert into t values ('{"1" : { "k1" : [1,2,3,5]} }');
insert into t values ('{"2" : { "k2" : [4,5,6,7]} }');
create table i (
id int,
v int[]
)
Some tests
select data -> '1' -> 'k1'
from t
where data ? '1'
;
insert into i values(1,ARRAY[1,2,3]);
update i
set v = (select replace(replace(data -> '1' ->> 'k1', '[', '{'), ']', '}')::int[] from t where data ? '1')
where id = 1;
select * from i;
The above gets array as a text, as you did. After that, just some text replacements to cast the text to an integer array literal.
DB Fiddle

How to use JSON_EXTRACT without having a key name?

how do I extract value frm key "Nome" from JSON using JSON_EXTRACT in google bigquery?
I cannot use the key 135 in the query because it is dynamic (Like this JSON_EXTRACT(vista, '$.Agencia.135.Nome'))
How to use JSON_EXTRACT without having a key '135' name?
JSON Record Sample:
{
"Campanha": "Campanha A",
"Ad": "Ad A",
"Agencia": {
"135": {
"Celular": ".",
"Codigo": "135",
"CodigoPai": "105",
"DDD": "00",
"Email": "email-A#email.com",
"Nome": "Nome A",
"Fone": "00 0000.0000",
"Fone2": ".",
"Foto": "foto-A.jpg"
}
}
}
Not sure if your json is formatted correctly. Is the key '135' an array? If so, format it properly and you can access it as the example below:
SELECT JSON_EXTRACT(json_text, '$.Agencia.135[1]') AS nome
FROM UNNEST([
'{"Agencia":{"135":[{"Codigo":"135"},{"Nome":"Nome A"}]}}'
]) AS json_text;
That would give you:
[
{
"nome": "{\"Nome\":\"Nome A\"}"
}
]
For more references about the JSON_EXTRACT: https://cloud.google.com/bigquery/docs/reference/standard-sql/json_functions#json_extract
Use below approach
execute immediate (
select string_agg("select " || key || ''' key
, JSON_EXTRACT_SCALAR(vista, '$.Agencia.''' || key || '''.Nome') AS Nome
from `project.dataset.table`''', " union all ")
from `project.dataset.table`, unnest(regexp_extract_all(regexp_replace(JSON_EXTRACT(vista, '$.Agencia'), r':{.*?}+', ''), r'"(.*?)"')) key
);
If applied to sample data in your question - output is
Also, depends on your use case - you might try below option too
execute immediate (
select 'select * from (' || string_agg("select " || key || ''' key
, JSON_EXTRACT_SCALAR(vista, '$.Agencia.''' || key || '''.Nome') AS Nome
from `project.dataset.table`''', " union all ") || ') where not Nome is null'
from `project.dataset.table`, unnest(regexp_extract_all(regexp_replace(JSON_EXTRACT(vista, '$.Agencia'), r':{.*?}+', ''), r'"(.*?)"')) key
);

How to update XML attribute in clob Oracle using XMLQuery

Oracle table name: SR_DATA;
Table field name: XMLDATA type CLOB;
Field value:
<module xmlns="http://www.mytest.com/2008/FMSchema">
<tmEsObjective modelCodeScheme="A" modelCodeSchemeVersion="01" modelCodeValue="ES_A"></tmEsObjective>
</module>
I need to update the value of the attribute "modelCodeValue" into ES_B.
This is the code:
UPDATE SR_DATA
SET XMLDATA =
XMLQuery('copy $i := $p1 modify
((for $j in $i/module/tmEsObjective/#modelCodeValue
return replace value of node $j with $p2))
)
return $i'
PASSING XMLType(REPLACE(xmldata, 'xmlns="http://www.mytest.com/2008/FMSchema"', '')) AS "p1",
'ES_B' AS "p2"
RETURNING CONTENT);
This code returns the error code: ORA-00932: inconsistent datatypes: expected CLOB got -
Use getclobval() like this:
UPDATE SR_DATA
SET XMLDATA =
XMLTYPE.GETCLOBVAL(XMLQuery('copy $i := $p1 modify
((for $j in $i/module/tmEsObjective/#modelCodeValue
return replace value of node $j with $p2))
return $i'
PASSING XMLType(REPLACE(xmldata, 'xmlns="http://www.mytest.com/2008/FMSchema"', '')) AS "p1",
'ES_B' AS "p2"
RETURNING CONTENT ));

How to get value of nested Map using parameter

I'm trying to get value of nested Map using parameter of SQL component expression but it failed.
I have this json (unmarshal to java.util.Map):
{ "username" : "john",
"company" : { "companycode" : "stackoverflow.inc",
"address" : "Street 12" }
}
And I have this SQL expression with parameters on my Route builder:
...
.unmarshal().json(JsonLibrary.Jackson)
.to("sql:INSERT INTO user_tab VALUES (:#username, :#company.companycode)")
...
I was able to get the value of username but I can not get the value of companycode. What is the right way to do it? Thank you.
according: http://camel.apache.org/sql-component.html
From Camel 2.14 onward you can use Simple expressions as parameters as shown:
sql:select * from table where id=:#${property.myId} order by name[?options]
this work fine for me:
{guid=67, properties={last_seen=1472034553348, _type=business_service, name=Anna, created_at=1472033602648, status=USUNIĘTY}}
<to uri="dbSQL:insert into table_name (
guid,name,description,type,status,changedate,transid,transseq
) values (
:#${body[guid]}::integer, :#${body[properties][name]}, :#${body[properties][name]}, :#${body[properties][_type]}, :#${body[properties][staus]}, now(), 0, 0
)"/>