Retrive an object from json string using JSON_QUERY in oracle - sql

Below the code which I'm trying but getting null value.
SELECT json_query(object_data,'$.AOF.LEAD_DATA.DIRECTOR[*]')
FROM TB_COP_BUSS_OBJ_TXN FD,
JSON_TABLE(FD.OBJECT_DATA,'$.AOF.LEAD_DATA.DIRECTOR[*]' columns
( AUS_FLAG VARCHAR2(40) PATH '$.CHECKBOX.AUS_FLAG.value')) j
WHERE FD.OBJECT_PRI_KEY_1 = 'XXXXXXX' and j.AUS_FLAG ='Y'
I'm trying to get full data which is inside director object/array. when I'm using 0,1,2, instead of * then I'm getting the data but I need to check aus flag and need those index data of that array object. please help
please help.

If you have the sample data:
CREATE TABLE TB_COP_BUSS_OBJ_TXN (
OBJECT_PRI_KEY_1 VARCHAR2(20) PRIMARY KEY,
OBJECT_DATA CLOB CHECK (OBJECT_DATA IS JSON)
);
INSERT INTO TB_COP_BUSS_OBJ_TXN (
OBJECT_PRI_KEY_1,
OBJECT_DATA
) VALUES (
'XXXXXX',
'{"AOF":{"LEAD_DATA":{"DIRECTOR":[1,2,3]}}}'
);
Then you can use:
SELECT JSON_QUERY(OBJECT_DATA,'$.AOF.LEAD_DATA."DIRECTOR"')
from TB_COP_BUSS_OBJ_TXN FD
WHERE OBJECT_PRI_KEY_1 = 'XXXXXX'
Which outputs:
JSON_QUERY(OBJECT_DATA,'$.AOF.LEAD_DATA."DIRECTOR"')
[1,2,3]
Or you can use:
SELECT value
from TB_COP_BUSS_OBJ_TXN FD
CROSS APPLY JSON_TABLE(
fd.object_data,
'$.AOF.LEAD_DATA."DIRECTOR"[*]'
COLUMNS (
value NUMBER PATH '$'
)
)
WHERE OBJECT_PRI_KEY_1 = 'XXXXXX'
Which outputs:
VALUE
1
2
3
db<>fiddle here

Related

Parse field form xml clob

Ciao,
i've one problem with sql.
I've some table with datatype clob where is stored a clob.
In the same table if we have the xml format we use one function for take the xml_fied
CREATE OR REPLACE FUNCTION gettagvalue (
XMLBody IN CLOB, TagXml IN VARCHAR2) RETURN VARCHAR2 IS
BEGIN
return TO_CHAR (SUBSTR (XMLBody,
INSTR (XMLBody, '<'||TagXml||'>') + length(TagXml) + 2,
INSTR (XMLBody, '</'||TagXml||'>')
- INSTR (XMLBody, '<'||TagXml||'>')
- (length(TagXml) + 2)
)
);
END GetTagValue;
/
example :
Select errorhandler.GetTagValue(xml_content,'ORDERID')
from table_order
On the same table we have also some xml in json.
How i can create a copy of same function for take the field?
On xml is eay because we have the field with same name that start with and finish with but with json
I cannot understand how define the end of field
Do NOT try to parse XML or JSON as strings; use a proper XML or JSON parser.
If you have the table with the sample data:
CREATE TABLE table_name (
xml CLOB,
json CLOB CHECK ( json IS JSON )
);
INSERT INTO table_name ( xml, json ) VALUES (
'<a><b>BBB</b><c>CCC</c><d>DDD</d></a>',
'{"a":"aaa","b":"bbb","c":[1,2,3,4],"d":"ddd"}'
);
Then you can get the c values from both using the XMLQUERY or JSON_QUERY functions:
SELECT XMLQUERY(
'*/c/text()'
PASSING XMLTYPE(xml)
RETURNING CONTENT
) AS c_xml_value,
JSON_QUERY(
json,
'$.c'
RETURNING VARCHAR2(50)
) AS c_json_value
FROM table_name
Which outputs:
| C_XML_VALUE | C_JSON_VALUE |
| :---------- | :----------- |
| CCC | [1,2,3,4] |
If you have XML and JSON values in the same column then look at whether the first character is < or not and use the appropriate parsing function; do not try and create your own function to parse the values using substring matching.
For example:
CREATE TABLE table_name ( value CLOB );
INSERT INTO table_name ( value )
SELECT '<a><b>BBB</b><c>CCC</c><d>DDD</d></a>' FROM DUAL UNION ALL
SELECT '{"a":"aaa","b":"bbb","c":[1,2,3,4],"d":"ddd"}' FROM DUAL;
Then:
SELECT CASE
WHEN value LIKE '<%'
THEN CAST(
XMLQUERY( '*/c/text()' PASSING XMLTYPE(value) RETURNING CONTENT )
AS VARCHAR2(50)
)
ELSE JSON_QUERY( value, '$.c' RETURNING VARCHAR2(50) )
END AS c_value
FROM table_name
Outputs:
| C_VALUE |
| :-------- |
| CCC |
| [1,2,3,4] |
db<>fiddle here
Update
You can also use JSON_TABLE and XMLTABLE to get all the values out:
SELECT COALESCE( j.sourceChannel, x.sourceChannel ) AS sourceChannel,
COALESCE( j.transactionId, x.transactionId ) AS transactionId,
COALESCE( j.sessionId, x.sessionId ) AS transactionId,
COALESCE( j.status, x.status ) AS status,
COALESCE( j.errorcode, x.errorcode ) AS errorcode,
COALESCE( j.errordescription, x.errordescription ) AS errordescription
FROM table_name t
OUTER APPLY JSON_TABLE(
t.value,
'$.header'
COLUMNS (
sourceChannel VARCHAR2( 50) PATH '$.sourceChannel',
transactionId VARCHAR2( 50) PATH '$.transactionId',
sessionId VARCHAR2( 50) PATH '$.sessionId',
status VARCHAR2( 50) PATH '$.status',
errorcode VARCHAR2( 50) PATH '$.errorcode',
errordescription VARCHAR2(200) PATH '$.errordescription'
)
) j
LEFT OUTER JOIN LATERAL(
SELECT *
FROM XMLTABLE(
'/header'
PASSING XMLTYPE( value )
COLUMNS
sourceChannel VARCHAR2( 50) PATH 'sourceChannel',
transactionId VARCHAR2( 50) PATH 'transactionId',
sessionId VARCHAR2( 50) PATH 'sessionId',
status VARCHAR2( 50) PATH 'status',
errorcode VARCHAR2( 50) PATH 'errorcode',
errordescription VARCHAR2(200) PATH 'errordescription'
)
) x
ON ( t.value LIKE '<%' )
Which for the sample data:
CREATE TABLE table_name ( value CLOB );
INSERT INTO table_name ( value )
SELECT '<header>
<sourceChannel>xaaa</sourceChannel>
<transactionId>xbbb</transactionId>
<sessionId>xccc</sessionId>
<status>xddd</status>
<errorcode>xeee</errorcode>
<errordescription>xfff</errordescription>
</header>' FROM DUAL UNION ALL
SELECT '{"header":{"sourceChannel":"jaaa","transactionId":"jbbb","sessionId":"jccc","status":"jddd","errorcode":"jeee","errordescription":"jfff"}}' FROM DUAL;
Outputs:
SOURCECHANNEL
TRANSACTIONID
TRANSACTIONID
STATUS
ERRORCODE
ERRORDESCRIPTION
xaaa
xbbb
xccc
xddd
xeee
xfff
jaaa
jbbb
jccc
jddd
jeee
jfff

removing null rows, where columns are dynamically subselected

I have a table with high number of value columns which looks like:
CREATE TABLE tbl ("timestamp" timestamp PRIMARY KEY, "a" real, "b" real, "c" real)
The table may contain a dynamic number of value columns (like a,b,c).
I need to delete rows with where all values are null, but timestamp is not null.
I am unable to build a select query which will return null rows only.
Doing something like:
select *
from tbl
where tbl is null
will not work, because timestamp is not null
I tried to take the following working example:
select *
from tbl
where not (a,b,c) is null
and add a subselect to it:
select *
from tbl
where not (
SELECT string_agg(column_name, ',')
FROM information_schema.columns
WHERE table_name = 'tbl' and column_name != 'timestamp'
) is null
But it is not working.
You can convert the row to a JSONB object, remove the "timestamp" column and then check for an empty value:
select *
from tbl
where jsonb_strip_nulls(to_jsonb(tbl) - 'timestamp') = '{}'::jsonb;
This can directly be used to delete the rows:
delete from tbl
where jsonb_strip_nulls(to_jsonb(tbl) - 'timestamp') = '{}'::jsonb);

Simple SQL path query?

I am working through an intro SQL textbook and am confused by the following problem, where we are given the table and values:
CREATE TABLE LineageTable (
parent INT,
id INT,
genus_name VARCHAR(30),
PRIMARY KEY (id)
);
INSERT INTO LineageTable VALUES
(3, 1, 'FamilyA'),
(2, 4, 'FamilyB'),
(7, 2, 'FamilyC');
And I want to write a function that will return a text string representing the path from the a given name to the desired root
My Attempt:
CREATE FUNCTION LineageTable (input VARCHAR(50))
RETURNS TABLE (input VARCHAR(50))
AS $$
BEGIN
RETURN QUERY
SELECT input
FROM LineageTable1
INNER JOIN LineageTable ON LineageTable.parent = LineageTable.id
WHERE LineageTable1.genus_name = LineageTable1.genus_name;
END $$
However, I am confused as how to iterate through this table multiple times to string the path together properly. Any ideas? Thanks all!
On Postgres you can use a RECURSIVE query:
WITH RECURSIVE Rec as
(
SELECT id, parent_id, Name
FROM Hierarchy
WHERE Name = 'Sirenia'
UNION ALL
SELECT Hierarchy.id, Hierarchy.parent_id, Hierarchy.Name
FROM Hierarchy
INNER JOIN Rec
ON Hierarchy.id = Rec.parent_Id
)
SELECT string_agg(Name, '->') path
FROM Rec;
| path |
|:---------------------------------:|
| Sirenia->Paenungulata->Afrotheria |
Rextester here

Can I return fields from an insert select that were not included with the insert?

Using Postgres 9.5.
I have a table base with some records:
CREATE TABLE base
(
id serial NOT NULL
, thing varchar
, copy varchar
);
I want to insert a subset of those records into the table new:
CREATE TABLE new
(
id serial NOT NULL
, new_thing varchar
, new_copy varchar
);
new doesn't have a column to store base.id. But I would like to be able to map from new.id to the base row that the new row was created from:
CREATE TABLE base_to_new
(
base_id int NOT NULL
, new_id int NOT NULL
);
This is the gist of what I want, but it doesn't work:
WITH new_rows AS
(
INSERT INTO new
(
, new_thing
, new_copy
)
SELECT
thing
, copy
FROM base
WHERE copy = 'yes'
RETURNING
(
base.id AS base_id
, new.id AS new_id
)
)
INSERT INTO base_to_new
SELECT
new_rows.base_id
, new_rows.new_id
FROM new_rows
;
The schema of base and new is not alterable.
I also want to avoid the following, because in reality, there are many more
fields than in the example tables, the tables are very large,
and let's be real, doing a bunch of comparisons is lame.
INSERT INTO base_to_new
SELECT
base.id
, new.id
FROM base
LEFT JOIN new
ON thing = new_thing
AND item = new_item
AND stuff = new_stuff
AND last = new_last
;
Here is a SQL fiddle with schema and some data:
http://sqlfiddle.com/#!15/bbb9d
Thanks!
This works assuming that base.thing is unique:
with sel as (
select *
from base
where copy = 'yes'
),
ins as (
insert into new (new_thing, new_copy)
select thing, copy
from sel
returning *
)
insert into base_to_new
select sel.id, ins.id
from sel
join ins on sel.thing = ins.new_thing;
Btw, I do not like the model as really troublesome. Storing base.id in new is simpler and much more natural. I would also avoid the words new andcopy for table or column names as they have their own meaning in Postgres.

How to update record from alphanumeric to numeric only?

Topic : Data Cleaning - Checking for outlier - Out of pattern
I'm trying update custID from value 'A123' to '123', '22A4' to '224' I only want to keep integer inside custID, I don't want the custID contain any non-integer character (A to Z and a to z)
CREATE TABLE customer (
custID VARCHAR2(10) PRIMARY KEY,
custName VARCHAR2(30)
);
INSERT INTO customer(custID,custName) VALUES ('A123','Angel');
INSERT INTO customer(custID,custName) VALUES ('22A4','Chris');
INSERT INTO customer(custID,custName) VALUES ('2333','Chris');
UPDATE customer
SET custID = -- I want to change 'A123' to '123', '22A4' to '224'
WHERE ;
Use this...
UPDATE customer
SET custID = REGEXP_REPLACE(custID, '[^0-9]+', '')
WHERE ;
or try this...
UPDATE customer
SET custID = REGEXP_REPLACE(custID, '[^[:digit:]]+', '')
WHERE ;
UPDATE customer
SET custid = REGEXP_SUBSTR ( custid , '[0-9]*' )
WHERE
REGEXP_SUBSTR Oracle documentation