Oracle query to read nested JSON data - oracle

I have a table which has a column with nested JSON data that I want to read for a query result. But the data type of column is VARCHAR and data inside is a JSON string with nested objects inside.
Now when I hit below query it works fine and gives me result,
select * from dataTable where regexp_like(metadata,'(*)"id":"33001"(*)');
Below is the metadata column of dataTable :
{"id":"33001",
"digits":"1234",
"requestId":"5d54-f6-48-8d-8155190",
"deliveryMethod":"ATT",
"messageStatus":"{\"status\":[
{\"tokenId\":\"Zktx\",\"deliveryStatus\":\"SUCCESS\",\"code\":\"0\"},
{\"tokenId\":\"aGsx\",\"deliveryStatus\":\"SUCCESS\",\"code\":\"0\"}
]}"
}
Above data is all String in single metadata column, I have split it just so that it is more readable.
But I also want to filter the data based on "deliveryStatus" contents. So when I try below query,
select * from dataTable where regexp_like(metadata,'(*)"id":"33001"(*)') AND regexp_like(metadata,'(*)\"deliveryStatus\":\"SUCCESS\"(*)');
It doesn't work. Does NOT show any result. There is no error though. I feel I need some other approach to read the nested JSON contents inside that string. But I am not sure how to do that.
Can someone provide any insights of how to achieve this?

Backslash is an escape character in regex, so you have to escape it with a second backslash.
-- sample data
with datatable as (select '{"id":"33001",
"digits":"1234",
"requestId":"5d54-f6-48-8d-8155190",
"deliveryMethod":"ATT",
"messageStatus":"{\"status\":[
{\"tokenId\":\"Zktx\",\"deliveryStatus\":\"SUCCESS\",\"code\":\"0\"},
{\"tokenId\":\"aGsx\",\"deliveryStatus\":\"SUCCESS\",\"code\":\"0\"}
]}"
}' metadata from dual)
-- actual query
select * from dataTable where regexp_like(metadata,'(*)"id":"33001"(*)')
AND regexp_like(metadata,'(*)\\"deliveryStatus\\":\\"SUCCESS\\"(*)'); -- note double backslashes
But I do recommend looking into the native JSON support if you're on Oracle 12c or up, like #thatjeffsmith mentioned. Regex work, but they're expensive and fragile.

Related

When I use a db2 insert statement it only runs if I use single quotes, but I don't want single quotes in the value that is inserted into the table

I am trying to insert values into a table on a db2 db, and its inputting single quotes.. argggh
So I am able to insert values using
insert into table abc.house (house_name, is_active) values ('Treasure', 1);
however when selecting the value in the table is 'Treasure' which I don't want those lovely quotes.
If I try to use:
insert into table abc.house (house_name, is_active values (Treasure, 1);
I get an error
com.ibm.db2.jcc.am.SqlSyntaxErrorException: DB2 SQL Error: SQLCODE=-206, SQLSTATE=42703, SQLERRMC=TREASURE, DRIVER=4
Any solutions? Thanks, JT
so i learned that the sql UI that was set up, was done so that for Varchar values single quotes are part of the return from a query. The UI shows 'Treasure', whereas if I query on the command line the return is simply Treasure
Good to go. using insert statement with single quotes around the value is good syntax.
That's correct. We MUST put single quotes across char/varchar/blob data.

Why the field has been cut into two parts in Hive?

Here is the code:
-- create table novaya.unnormal as
select query from default.daily_session_mobile
where dt = '20161020'
and page in ('/click_search_deal', '/click_search_product')
and query like '%memberID=33930938%'
and query like '%스텐드지퍼팩%'
The result only has one record and it is right
The value in the field of "query" is
searchCount=52&rank=39&logType=click&currentView=/search_list&searchId=4c3ecee1354943e999e0c1566243bf87&logCategory=event&itemID=22780015&itemProductID=4&q=스텐드지퍼팩&memberID=33930938&productID=4993730&eventReferrer=/click_search_list&request_time=1476889555129&tz=+0900&appVersion=4.3.8&wl_mo=LG-F400L&wl_ma=LGE&wl_sn=Android&wl_v=4.4.2&wl_r=1440x2392&wl_l=ko&wl_c=KR
and there is no space in the value. We focus on the "q=스텐드지퍼팩&" in it.
It seems good.
But when I use create table novaya.unnormal as select ...
the table novaya.unnormal's query have been cut.
The new "query" only has a part of the whole query which is
"searchCount=52&rank=39&logType=click&currentView=/search_list&searchId=4c3ecee1354943e999e0c1566243bf87&logCategory=event&itemID=22780015&itemProductID=4&q="
half of it is missing.
What is wrong with this?
When you create a table using create table novaya.unnormal as statement, without specifying any input/output format and delimiters, all defaults will be chosen which probably causes the 스 character to act as a separator.
I suggest looking at the properties of the source table (describe formatted default.daily_session_mobile), and creating the new table with similar input/output format and delimiters. (setting them between novaya.unnormal and as)

Using XMLTABLE and xquery to extract data from xml

I have the following piece of XML:
<per:Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.something.com/2014/11/bla/webservice.xsd"
xmlns:per="http://www.something.com/2014/11/bla/person">
<per:Initials>E.C.</per:Initials>
<per:FirstName>Erik</per:FirstName>
<per:LastName>Flipsen</per:LastName>
<per:BirthDate>1980-07-01</per:BirthDate>
<per:Gender>Male</per:Gender>
</per:Person>
From this xml I want to extract some data in PL/SQL. I'd like to use XMLTABLE, since the EXTRACT and EXTRACTVALUE functions are deprecated.
I am able to extract the data using this query:
select pers.Initials,
pers.Firstname
into lsInitials,
lsFirstname
from
XMLTABLE ('*:Person' passing pxRequest
columns Initials PATH '*:Initials',
Firstname PATH '*:FirstName'
) pers;
I'm using wildcards for the namespaces since I don't really care what abbreviations the sending party is using for the namespace, I know the exact path where to get my data anyway.
With this code I have two things that puzzle me:
According to the documentation on http://docs.oracle.com/database/121/SQLRF/functions268.htm#SQLRF06232 PATH should be optional, however, as soon as I remove the PATH from the COLUMNS section, I don't get any results anymore.
Edit:
I found out that when I remove the namespaces for the elements, and made them uppercase, it works. So it seems like the column names need to match the xml elements names to make it work. I didn't yet figure out how to make it work with namespaced XML.
The documentation also notes "For each resulting column except the FOR ORDINALITY column, you must specify the column data type", however, it seems to work fine without it. It also seems a bit redundant to specify it for the columns and for the variables I'm fetching the data into. Any idea if not specifying the data types could get me into trouble?
Runnable code sample:
SET SERVEROUTPUT ON;
DECLARE
pxRequest xmltype := xmltype('<per:Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.something.com/2014/11/bla/webservice.xsd"
xmlns:per="http://www.something.com/2014/11/bla/person">
<per:Initials>E.C.</per:Initials>
<per:FirstName>Erik</per:FirstName>
<per:LastName>Flipsen</per:LastName>
<per:BirthDate>1980-01-01</per:BirthDate>
<per:Gender>Male</per:Gender>
</per:Person>');
lsInitials varchar2(100);
lsFirstname varchar2(100);
begin
select pers.Initials,
pers.Firstname
into lsInitials,
lsFirstname
from
XMLTABLE ('*:Person' passing pxRequest
columns Initials PATH '*:Initials',
Firstname PATH '*:FirstName'
) pers;
dbms_output.put_line(lsInitials);
dbms_output.put_line(lsFirstname);
end;
As per your first question, the documentation you linked has this to day about omitting PATH:
The optional PATH clause specifies that the portion of the XQuery result that is addressed by XQuery expression string is to be used as the column content.
If you omit PATH, then the XQuery expression column is assumed. For example:
(... COLUMNS xyz)
is equivalent to
XMLTable(... COLUMNS xyz PATH 'XYZ')
You can use different PATH clauses to split the XQuery result into different virtual-table columns.
The reason the column xyz is assumed to be 'XYZ' is because Oracle, by default, is case insensitive (defaults to all-caps). If you had defined your column as "aBcD" then the PATH value will be assumed to be 'aBcD'
As for your second question about specifying data types: if the data you're extracting is always going to be text data, you might be able to get away with not specifying a data type.
However, if you start dealing with things like dates, timestamps, floating point numbers, etc, then you may run into issues. You'll either need to manually convert them using the TO_* functions or you can specify their data types in the column definitions. If you don't, Oracle is free to implicitly cast it however it feels fit, which may have unexpected consequences.
References:
https://stackoverflow.com/a/9976068/377141
How to parse xml by xmltable when using namespace in xml(Oracle)
It should work as expected if you load in the namespace elements in your xmltable:
select results
from xmltable(
xmlnamespaces(
default 'http://tempuri.org/',
'http://schemas.xmlsoap.org/soap/envelope/' as "soap"
),
'soap:Envelope/soap:Body/addResponse' passing xmltype(v_xml)
columns results varchar(100) path './addResult')
From your example (you may also need to register your schema/namespace ahead of time, but that should be once):
select pers.Initials,
pers.Firstname
into lsInitials,
lsFirstname
from
XMLTABLE (
xmlnamespaces(
default 'http://tempuri.org/',
'http://www.w3.org/2001/XMLSchema-instance' as "xsi",
'http://www.something.com/2014/11/bla/person' as "per"
),
passing pxRequest
columns Initials PATH '*:Initials',
Firstname PATH '*:FirstName'
) pers;
Things that used to work in previous versions of Oracle do not work in 11g+ with respect to XML, as from what I have seen, Oracle strongly verifies/types the input/output of XML operations where in previous versions you could run normal proper XQuery operations without namespace info.

Peoplecode, SQLEXEC not retrieving correct data

<-------PeopleCode------>
Hi,
I have a SQL query that i have tried executing using both SQLEXEC and SQL.fetch() but the problem is, when I am passing the values to parameters (:1,:2...) it does not return a row but when I hardcode the values in the where clause of the query itself, it retrieves the correct value.
Can anybody help?
My query looks similar to the following sample query :
Select * from PS_rec1 where emplid=:1 and plan_type=:2
it returns no data till i hardcode the values.
I have checked the values at the back end and some data is there to be fetched. Moreover, the same query retrieves data when ran in TOAD.
Have you tried outputting your binds to a log file just before you use them in your SQL statement?
If the binds aren't working, but literals are, then perhaps your binds don't contain the values that you expect them to.
You could also try explicitly setting the binds to the values that you're expecting just before the SQL statement. This will prove that the way you're passing in the binds is working correctly.
It required another update to the same record to get the values fetched in SQL exec.
M not sure what was the problem but i guess it might be that the previous update did not write the changes to the db even after an explicit commit.
Ok, you need to put your exact SQLExec statement in the question.
But, do you really have "Select * ..." in a SQLExec? How many columns are in your table? Since you mention the where clause, is your statement
SQLExec("select * from PS_rec where emplid=:1 and plan_type=:2", &var1, &var2, &vartocontainthewholerow);
Which will work in a SQL tool (toad) but probably does not work in AE or any type of Peoplecode program.
Now if your table has three columns, should you not have something like this:
SQLExec("select emplid, plan_type, column3 from PS_rec where emplid = :1 and plan_type=:2", &emplidIn, &plan_typeIn, &emplidOut, &plan_typeOut, &column3Out);
Notice that with three columns in the table that emplid and plan_type are two of them, you need to list all the columns you want, not asterisks '*'. Kind of silly to select the emplid and plan_type though.

parameter in sql query :SSRS

I am using oracleclient provider. I was wondering how do I use a parameter in the query.
select * from table A where A.a in ( parameter).
The parameter should be a multivalue parameter.
how do I create a data set?
Simple. Add the parameter to the report and make sure to check it off as multi-valued. Then in the data tab and go in and edit the query click the "..." button to edit the dataset. Under the parameters tab create a mapping parameter so it looks something like this (obviously you will have different names for your parameters):
#ids | =Parameters!ContractorIDS.Value
Then in the query tab use the coorelated sub-query like your example above. I have done this many times with SQL server and there is no reason it should not work with Oracle since SSRS is going to build an ANSI compliant SQL statement which it will pass to Oracle.
where A.myfield in (#ids)
You can't have a variable in list in oracle directly. You can however, break apart a comma seperated list into rows that can be used in your subquery. The string txt can be replaced by any number of values seperated by a comma.
select * from a where a.a in (
SELECT regexp_substr(txt,'[^,]+',1,level)
FROM (SELECT 'hello,world,hi,there' txt -- replace with parameter
FROM DUAL)
CONNECT BY LEVEL <= LENGTH (REGEXP_REPLACE (txt, '[^,]'))+1
)
The query works by first counting the number of commas that are in the text string. It does this by using a reqular expression to remove all non commas and then counts the length of the remainder.
It then uses an Oracle "trick" to return that number + 1 number of rows from the dual table. It then uses the regexp_substr function to pull out each occurence.
Firstly in SSRS with an Oracle OLEDB connection you need to use the colon, not the # symbol e.g. :parameter not #parameter but then you aren't able to do this as a multi-valued parameter, it only accepts single values. Worse, if you are using an ODBC connection you have to use the question mark by itself e.g. ? not #parameter and then the ordering of parameters becomes important, and they also cannot be multi-valued. The only ways you are left with is using an expression to construct a query (join() function for the param) or calling a stored proc.
The stored proc option is best because the SSRS can handle the parameters for stored procs to both SQL Server and Oracle very cleanly, but if that is not an option you can use this expression:
="select column1, column2, a from table A where A.a in (" + Join(Parameters!parameter.Value,", ") + ")"
Or if the parameter values are strings which need apostrophes around them:
="select column1, column2, a from table A where A.a in ('" + Join(Parameters!parameter.Value,"', '") + "')"
When you right-click on the dataset, you can select "dataset properties" and then use the fx button to edit the query as an expression, rather than using the query designer which won't let you edit it as an expression.
This expression method is limited to a maximum limit of about 1000 values but if you have that many this is the wrong way to do it anyway, you'd rather join to a table.
I don't think you can use a parameter in such a situation.
(Unless oracle and the language you're using supports array-type parameters ? )
The parameters in oracle are defined as ":parametername", so in your query you should use something like:
select * from table A where value in (:parametername)
Add the parameter to the paramaters folders in the report and mark the checkbox "Allow multiple values".
As Victor Grimaldo mentioned… below worked for me very fine. As soon as I use the :parameter in my SQL query in SSRS dataset1.. it asked me to enter the values for these parameters, for which I choose already created SSRS parameters.
SELECT * FROM table a WHERE VALUE IN (**:parametername**)
Thanks Victor.

Resources