Having issue with extracing date from CLOB data - oracle

Hi I am having issue when extracting fields from CLOB data. For one record I am not getting desired output.
The record is as below:
{1:F014243107336}{2:O2021216200422XXX24563}{3:{108:O2020}{121:2c02a452-5}{433:HIT}}{4:
:4A:SEC:20200901
:4B:FC5253
:4C:20042000,
:4D:XXXXXXX
:4E:RXX
:4F:RXXXX
-}{5:{CHK:87D1003B01F7}{TNG:}}{S:{SAC:}{COP:S}}<APSECSIGN>FS3sfasdfg!==</APSECSIGN>?
I want to extract data from tag :4A: into REF_NUMBER.
I am using below SQL to get the data.
NVL(TRIM(TRANSLATE(REGEXP_REPLACE(REGEXP_SUBSTR(dbms_lob.substr(CLOB, 4000, 1 ), ':4A.?:[^:]+(:|-\})'), ':20.?:([^:]+)(:|-\})', '\1'),CHR(10)||CHR(13), ' ')),' ') AS REF_NUMBER
the output I am getting is "SEC". However I want to see output as SEC:20200901.
Can any one suggest what I am missing in my query or provide me correct query.

A general suggestion. Why don't you have your data stored as JSON ? Because, JSON related functions are very fast when compared to others. And then your problem becomes quite easy.
However to answer your question:
with inputs (str) as
(
select to_clob(q'<
{1:F014243107336}{2:O2021216200422XXX24563}{3:{108:O2020}{121:2c02a452-5}{433:HIT}}{4:
:4A:SEC:20200901
:4B:FC5253
:4C:20042000,
:4D:XXXXXXX
:4E:RXX
:4F:RXXXX
-}{5:{CHK:87D1003B01F7}{TNG:}}{S:{SAC:}{COP:S}}<APSECSIGN>FS3sfasdfg!==</APSECSIGN>?
>') from dual
)
select str, regexp_substr(str,'SEC:\d+',1,1,'n') as val
from inputs;
Output:

Updated
If you know the date is always going to be 8 digits after the :4A: tag, you can use REGEXP_SUBSTR to get the value you need. Combining it with DBMS_LOB.SUBSTR removes the tag and converts it to a string.
SELECT DBMS_LOB.SUBSTR ((REGEXP_SUBSTR (clob_val, ':4A:.*\d{8}')), 4000, 5)
FROM (SELECT EMPTY_CLOB ()
|| '{1:F014243107336}{2:O2021216200422XXX24563}{3:{108:O2020}{121:2c02a452-5}{433:HIT}}{4:
:4A:SEC:20200901
:4B:FC5253
:4C:20042000,
:4D:XXXXXXX
:4E:RXX
:4F:RXXXX
-}{5:{CHK:87D1003B01F7}{TNG:}}{S:{SAC:}{COP:S}}<APSECSIGN>FS3sfasdfg!==</APSECSIGN>?' AS clob_val
FROM DUAL);

Related

Multi values search from one field PLSQL

I'm creating a report in PLSQL.
The report is working fine and additionally, I need to add when users search multiple values from one field separating by ;. It should select all the data that he entered.
Example: Salesman - Amanda; Michelle; Sharmain
Then it should select data regarding amenda, michelle and sharmain.
My code only returns data for one value only.
please refer this line from the code and ifsapp.Customer_Order_API.Get_Salesman_Code(i.order_no) LIKE '&Salesman'
where i.catalog_group='FPMB'
and i.order_no like 'M%'
and ((i.invoice_date between to_date( '&From_Date', 'YYYY/MM/DD' ) and to_date( '&To_Date', 'YYYY/MM/DD' ) ) or ('&From_Date' is null and '&To_Date' is null))
and t.source_ref1=i.order_no
and (t.source_ref3=i.release_no)
and (t.source_ref2=i.line_no)
and i.contract=t.contract
and t.transaction_code='OESHIP'
and t.qty_reversed=0
and t.source_ref1=i.order_no
and t.serial_no <> '*'
and t.cost<>0.00
and i.order_no LIKE '&Order_No
and ifsapp.Customer_Order_API.Get_Salesman_Code(i.order_no) LIKE '&Salesman'
You can use hierarchy query as follows:
ifsapp.Customer_Order_API.Get_Salesman_Code(i.order_no) IN
(SELECT TRIM(REGEXP_SUBSTR('&Salesman','[^;]+',1,LEVEL))
FROM DUAL CONNECT BY TRIM(REGEXP_SUBSTR('&Salesman','[^;]+',1,LEVEL)) IS NOT NULL)

How substr works on dates

I am trying to understand a query in my application where it uses substr function.
I have gone through the documentation for substr, which looks simple and clear.
Now below is my query without using substr:
select last_day(to_date(to_char(add_months(TO_DATE('2004/10/25', 'yyyy/mm/dd'),1),'YYYY')||'0201','YYYYMMDD')) from dual;
This gives me result as 2/29/2004. The above query just returns last day of Feb in simple words.
Now I am using substr as below:
select substr(last_day(to_date(to_char(add_months(TO_DATE('2004/10/25', 'yyyy/mm/dd'),1),'YYYY')||'0201','YYYYMMDD')),5,1) from dual;
So here the start value is 5 & length is 1, so I am expecting output as 2 looking at 2/29/2004. but the actual output is E, I am not clear from where this E is coming as result.
You cannot use SUBSTR() on DATE values. SUBSTR() works only on strings!
When you run SUBSTR({DATE_VALUE}, ...) then Oracle actually does following:
SELECT
SUBSTR(
TO_CHAR(
{DATE_VALUE}, (SELECT VALUE FROM nls_session_parameters WHERE parameter = 'NLS_DATE_FORMAT')
), ...
)
FROM dual;
What is the purpose of this query? Do you like to find out whether input year is a leap-year?
Try this instead -
select substr(to_char(last_day(to_date(to_char(add_months(TO_DATE('2004/10/25', 'yyyy/mm/dd'),1),'YYYY')||'0201','YYYYMMDD')),'dd/mm/yyyy'),5,1)
from dual;

Oracle invalid number in clause

I'm struggling with getting a query to work, and I could really use some help. We have an in house app that we use for building small web apps where I work. It's basically a drag and drop GUI. There's functionality built in to access query string values using the key.
I'm passing a comma separated list of values into a page through the query string. I'm then trying to use the list of values as part of an in clause in a query.
I can see that the value is correct in the query string.
orders=1,2,3
Here's the specific part of the query
"AND OrderNumber IN (this is where it maps from the query string)
I've tried running similar queries in Toad, and I think I've found the issue. It's giving an invalid number error, and I think it's wrapping the query string value in single quotes. I can replicate the error when I do "AND OrderNumber IN ('1,2,3')" in Toad.
Here's where I get really confused. The following works in Toad.
"AND OrderNumber IN ('1','2','3')"
So I tried recreating that by doing
select replace('1,2,3', ',', chr(39)||','||chr(39)) from dual;
I have confirmed that returns '1','2','3' in Toad.
However, I still get an Invalid Number error when I run the following in Toad.
AND OrderNumber IN (replace('1,2,3', ',', chr(39)||','||chr(39))
I've been racking my brain over this, and I can't figure it out. It seems to me that if "AND OrderNumber IN ('1','2','3')" works, and replace('1,2,3', ',', chr(39)||','||chr(39)) returns '1','2','3', that "AND OrderNumber IN (replace('1,2,3', ',', chr(39)||','||chr(39))" should work.
Any help you might be able to offer on this would be greatly appreciated. I know the rest of the query works. That's why I didn't post it. I'm just stuck on trying to get this IN clause working.
A change to phonetic_man's answer that will allow for NULL elements in the list. The regex format of '[^,]+' for parsing delimited lists does not handle NULL list elements and will return an incorrect value if one exists and thus its use should be avoided. Change the original by deleting the number 2 for instance and see the results. You will get a '3' in the 2nd element's position! Here's a way that handles the NULL and returns the correct value for the element:
SELECT TRIM(REGEXP_SUBSTR(str, '(.*?)(,|$)', 1, LEVEL, NULL, 1)) str
FROM ( SELECT '1,,3,4' str FROM dual )
connect by level <= regexp_count(str, ',') + 1;
See here for more info and proof: https://stackoverflow.com/a/31464699/2543416
Can you try the following query.
SELECT * FROM orders
WHERE orderno IN
(
SELECT TRIM(REGEXP_SUBSTR(str, '[^,]+', 1, LEVEL)) str
FROM ( SELECT '1,2,3,4' str FROM dual )
CONNECT BY INSTR(str, ',', 1, LEVEL - 1) > 0
)
The inline query splitting the string in different rows. So, on executing it you will get the following result.
SELECT trim(regexp_substr(str, '[^,]+', 1, LEVEL)) str
FROM ( SELECT '1,2,3,4' str FROM dual )
CONNECT BY instr(str, ',', 1, LEVEL - 1) > 0
1
2
3
4
Now, passing this result to the main query IN clause should work.
I think the desired clause to be built is:
AND OrderNumber IN (1,2,3)
A numeric list. The example you tested:
AND OrderNumber IN ('1','2','3')
works because an implicit conversion from a VARCHAR2 to a NUMBER is occurring for each element in the list.
The following clause will not work because no implicit conversion of the string '1,2,3' can be made (note the clause has a single string element):
AND OrderNumber IN ('1,2,3')
When doing a replace, you are converting the single string: 1,2,3 with the single string: 1','2','3 and this single string cannot be implicitly converted to a number.

Oracle Select where NCLOB is Like some string

I have an Oracle table, and in this table I have a column of type NCLOB. I would like to perform a SELECT LIKE on it like so:
SELECT
*
FROM
T_WEB_TASK_IT
WHERE DBMS_LOB.substr( T_WEB_TASK_IT.ISSUE_DESCRIPTION , 32000, 1)
LIKE '%Turning on the%'
But it isn't working, I get an error saying:
String buffer too small
But I don't understand how can that be, cause I know for a fact that there aren't that many characters in that column for that particular record!
You can use DBMS_LOB.INSTR function to search for strings in the lob. Like this:
SELECT *
FROM T_WEB_TASK_IT
WHERE DBMS_LOB.INSTR( T_WEB_TASK_IT.ISSUE_DESCRIPTION , 'Turning on the') > 0
Apart from DBMS_LOB.INSTR, you could also use Regular Expressions:
SELECT *
FROM T_WEB_TASK_IT
WHERE regexp_like(issue_description, 'Turning on the')

Max Timestamp not giving correct result

I have a simple code to display latest error msg based on timestamp:
SELECT
line_item || ': ' || error_msg as RejectionMsg
FROM reqs
WHERE reqs_number = 'XXXXXXX'
and rqj_timestamp = (select max(rqj_timestamp) from reqs
WHERE reqs_number = 'XXXXXX' )
My data is something like :
rqj_timestamp line_item Error_msg
08-MAY-2009 14:00:04 8928 INVALID (RC4C) E
08-MAY-2009 14:00:04 8929 INVALID (R4CO) EY0
05-AUG-2013 00:13:42 11760 OO_USR_1 - NO_DATA_FOUND:No Data found for REQUEST
05-AUG-2013 00:13:42 11761 OO_USR_1 - NO_DATA_FOUND:No Data found for REQUEST
05-AUG-2013 00:13:42 11762 OO_USR_1 - NO_DATA_FOUND:No Data found for REQUEST
05-AUG-2013 00:14:59 11763 OO_USR_1 - NO_DATA_FOUND:No Data found for REQUEST
06-AUG-2013 06:55:59 11807 OO_45_ERROR_REGION_DERIV
06-AUG-2013 06:55:59 11808 OO_45_ERROR_REGION_DERIV
06-AUG-2013 06:55:59 11809 OO_45_ERROR_REGION_DERIV
My query is giving me output for 08-MAY-2009 14:00:04 time-stamp instead of the 06-AUG-2013 06:55:59 time-stamp.
3: INVALID (RC4C) E
3: INVALID (R4CO) EY0
Any idea where I am going wrong in this?OR how i can improve my query.. if i remove 08-MAY-2009 14:00:04 rows, it works perfectly fine.
Thanks in advance for help.
I would assuem your timestamp is not a date or similar data type, but a character data type like nvarchar2. Change you table to the proper data type.
A working but less clean solution would be to use something like
cast((select max(cast(rqj_timestamp as date)) from reqs) as nvarchar2)
which might depend on national language settings etc.
You would use the character data type that the column has in the outer cast.
Try something like (untested):
select *
from (
select r.*,
row_number() over (partition by reqs_number order by rqj_timestamp desc nulls last) rnum
from reqs r
where reqs_number = 'XXXXXXX'
)
where rnum = 1;
Also, the assumption is the "rqj_timestamp" is actually a timestamp (or at least a date).
Thanks for pointing out to check the datatype..turns out it was varchar, adding to_date(rqj_timestamp,'DD-MON-YYYY HH24:MI:SS') worked.

Resources