parsing oracle 11g - sql

I have the following snippet of a file that needs parsing :
000000837002100302015-04-13-15.55.12.1922082015-04-1300032128CHECK CLEARED CHECK CLEARED 00000000000030000000000000000000000000000000016594703
The respective positions for the string are as follows:
RECORD1 - POS (1 :10 ) - DUR 10
RECORD2 - POS (11 :13 ) - DUR 3
RECORD3 - POS (14 :17 ) - DUR 4
RECORD4 - POS (18 :43 ) - DUR 26
RECORD5 - POS (44 :53 ) - DUR 10
RECORD6 - POS (54 :61 ) - DUR 8
RECORD7 - POS (62 :95 ) - DUR 34
RECORD9 - POS (96 :215) - DUR 120
RECORD10 - POS (216:233) - DUR 18
RECORD11 - POS (234:251) - DUR 18
RECORD12 - POS (252:266) - DUR 15
RECORD13 - POS (267:268) - DUR 2
I need to parse the string to extract these records from that string. Can anyone help with the substr/instr functionality to account for the string and blank spaces. The extracted data would then get inserted into a table. Thank you in advance!

Can you not simply use a sqlloader control file e.g.
echo "OPTIONS (DIRECT=TRUE)"
echo "LOAD DATA"
echo "INFILE '/path/to/file/$1'"
echo "BADFILE '/path/to/file/log/$1.bad'"
echo "DISCARDFILE '/path/to/file/log/$1.dsc'"
echo "APPEND INTO TABLE table.t"
echo "("
echo " RECORD1 POSITION (1:10),"
echo " RECORD2 POSITION (11:13),"
etc...
echo ")"

You don't need instr, because the position is already specified. Instead
use substr
insert into some_table
select substr(text, 1, 10) rec1, substr(text, 11, 3) rec2, ...
from text_table;

Related

Substring replacement

I have string values like below
002 - KLAMPFER - Sy 52-5-5+L
002 - KLMGEEDD - SR 53-5-5+L
002 - LREFDGRE - SU 54-5 etc...
I want to make this like below output
002 - XXXXXXX - Sy 52-5-5+L
002 - XXXXXXX - SR 53-5-5+L
002 - XXXXXXX - SU 54-5
I tried but I did not get the output expected.
I am looking for substring function with replace.
Try to use regular expressions.
In Oracle the following SQL statement worked for me:
select regexp_replace('002 - KLAMPFER - Sy 52-5-5+L', '- [A-Z]+ -', '- XXXXXXX -')
from dual;
This answers the original version of the question.
You can use update:
update t
set col2 = 'XXXXXXX'
where col2 = 'KLAMPFER';
If that value is a single string, then:
update t
set col = replace(col, 'KLAMPFER', 'XXXXXXX')
where col like '%KLAMPFER%';

unable to get get all occurrences of matched regex_substr in single row oracle

I am trying to get specific data from my database column in oracle 11g but my regular expression is returning me only the first occurrence. Any idea how can i get all the occurrences in same row seperated by "|"??
My query:
SELECT regexp_substr(
'"Error:" {user_1#domain.com}<"User_2" {user_2#domain.com};"Error:" {user_3#domain.com}<"User_4" {user_4#domain.com};',
'Error:[^<]+<'
) AS emails
FROM DUAL;
My Output should be:
Error:" {user_1#domain.com}< Error:" {user_3#domain.com}<
Current output is:
Error:" {user_1#domain.com}<
For clear understanding, I am attaching dml of insert statement in my table:
insert into tests(result) values ('</span></td></tr><tr><td><span class="inputlabel">[14].</span>&nbsp&nbsp<span class="label">ORC|Boston Medical Center|||||||||||||
</span></td></tr><tr><td><span class="inputlabel">[15].</span>&nbsp&nbsp<span class="label">OBR|05-123|LOINC-Lcl-11546-9-1|20050415||||||||||LocalCode: Abscess2||||c|||||
</span></td></tr><tr><td class="errorlabel" nowrap>Error: Report Status Code (ReportStatusCode of type ID) value (c) is invalid Vocabulary code.</td></tr><tr><td class="errorlabel" nowrap>Message rejected.</td></tr><tr><td><span class="inputlabel">[17].</span>&nbsp&nbsp<span class="label">PID||||||||RecCtl_ID|FORTES|AVERY||||||||||||||||||
</span></td></tr><tr><td><span class="inputlabel">[18].</span>&nbsp&nbsp<span class="label">NK1|NK Last Name|NK First Name||||||||||
</span></td></tr><tr><td><span class="inputlabel">[19].</span>&nbsp&nbsp<span class="label">ORC|Boston Medical Center|||||||||||||
</span></td></tr><tr><td><span class="inputlabel">[20].</span>&nbsp&nbsp<span class="label">OBR|05-123|LOINC-Lcl-11546-9-1|20050415||||||||||Local 128477000||||Report_Status_Code 12345678_30|||||
</span></td></tr><tr><td><span class="inputlabel">[21].</span>&nbsp&nbsp<span class="label">OBX|LOINC-Lcl-11546-9-4|SMED-Lcl-78181009-4|||||F|200504231010|BMC
</span></td></tr><tr><td class="inputlabel" nowrap>Processing Results: 3 Messages Accepted, <span class="errorlabel">1 Messages Rejected.</span></td></tr><tr><td class="inputlabel" nowrap>End Time: 2011-08-07 18:47:47.312</td></tr></table>
</span></td></tr><tr><td class="errorlabel" nowrap>Error: Report Status Code (ReportStatusCode of type ID) value (c) is invalid Vocabulary code.</td></tr><tr><td class="errorlabel" nowrap>Message rejected.</td></tr><tr><td><span class="inputlabel">[17].</span>&nbsp&nbsp<span class="label">PID||||||||RecCtl_ID|FORTES|AVERY||||||||||||||||||
')
Table Creation:
create table TESTS
(
result CLOB
)
Now i want all the error messages from the above HTML i.e. output should be like this:
Error: Report Status Code (ReportStatusCode of type ID) value (c) is invalid Vocabulary code Error: Report Status Code (ReportStatusCode of type ID) value (c) is invalid Vocabulary code
Right now i am getting only 1 error message.
I'm not particularly good at it, but - see if it helps.
sample data from line #1 - 4
TEMP CTE splits the string into rows
final select (line #10 onward) aggregates results that contain "Error"
SQL> select * From v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
CORE 11.2.0.2.0 Production
TNS for 64-bit Windows: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production
SQL> with test (col) as
2 (select '"Error:" {user_1#domain.com}<"User_2" {user_2#domain.com};"Error:" {user_3#domain.com}<"User_4" {user_4#domain.com};'
3 from dual
4 ),
5 temp as
6 (select regexp_substr(col, '[^<;]+', 1, level) val
7 from test
8 connect by level <= regexp_count(col, '<') + 1
9 )
10 select listagg(val, '< ') within group (order by val) result
11 from temp
12 where instr(val, 'Error') > 0;
RESULT
--------------------------------------------------------------------------------
"Error:" {user_1#domain.com}< "Error:" {user_3#domain.com}
SQL>
With sample data you posted:
SQL> set pagesize 100
SQL> set long 10000
SQL>
SQL> with
2 temp as
3 (select regexp_substr(result, '[^<;]+', 1, level) val
4 from tests
5 connect by level <= regexp_count(result, '<') + 1
6 )
7 select replace(val, 'td class="errorlabel" nowrap>', '') result
8 from temp
9 where instr(val, 'Error') > 0;
RESULT
--------------------------------------------------------------------------------
Error: Report Status Code (ReportStatusCode of type ID) value (c) is invalid Voc
abulary code.
Error: Report Status Code (ReportStatusCode of type ID) value (c) is invalid Voc
abulary code.
SQL>
This answers the original version of the question.
If you want multiple substrings, then the right strategy is regexp_replace(). I think this is doing what you specify:
SELECT regexp_replace(
'"Error:" {user_1#domain.com}<"User_2" {user_2#domain.com};"Error:" {user_3#domain.com}<"User_4" {user_4#domain.com};',
'"(Error:[^<]+<)[^;]+;',
'\1'
) AS emails
FROM DUAL;
Here is a db<>fiddle.

SQL sub queries error

select(select SUM(HOME_SCORE) total from MATCH )
+
(select SUM(AWAY_SCORE) total from MATCH)
as "GOALS SCORED"
From dual ;
this is meant to return the sum of HOME_SCORE and AWAY_SCORE I get the following error
Error starting at line : 242 in command -
select(select SUM(HOME_SCORE) total from MATCH )
Error report -
Unknown Command
Error starting at line : 243 in command -
+
Error report -
Unknown Command
Query Run In:Query Result
Maybe your lacking in parenthesis if you want that way please rewrite your script to this select((select SUM(HOME_SCORE) total from MATCH )
+
(select SUM(AWAY_SCORE) total from MATCH))
as "GOALS SCORED"
From dual ;
or to simplify this you can try this select(select SUM(HOME_SCORE) + SUM(AWAY_SCORE) total from MATCH )
as "GOALS SCORED"
From dual ;

How to convert interger numbers into brazilain price format

i have integer numbers like below on left side in a file for products and need to convert them into brazilaian format like on right side.
100 =>100,00
84 => 84,00
1011 => 1.011,00
Use number_format() -
echo number_format(100, 2, ',', '.');
echo number_format(84, 2, ',', '.');
echo number_format(1011, 2, ',', '.');
Output -
100,00
84,00
1.011,00
Docs

How to extract and split IDs from nvarchar column surrounded by spaces and a slash to compare to other table's value

I feel my problem is very complicated.I have a Table A with a column named AbsenceLinks.
The table would look like this:
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
| Description | AbsenceLinks ||- - - - - - - - - - - - - + - - - - - - - - - - - - - -|
| Illness | 14/3 15/9
||- - - - - - - - - - - - - + - - - - - - - - - - - - - -|
| Education | 19/3 18/9
||- - - - - - - - - - - - - + - - - - - - - - - - - - - -|
|Leave of Absence| 20/3
||- - - - - - - - - - - - - + - - - - - - - - - - - - - -|
| Holiday | 8/3
|l- - - - - - - - - - - - - - - - - - - - - - - - - - - -l
I have another table B where I have a column named AbsenceID that matches the number before the slash-symbol in the AbsenceLinks column.
(Table A AbsenceLinks value '20/9' matches AbsenceID 20 in table B)
This table would look like this:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| Absence | AbsenceID
|| - - - - - - - - - - - - - - - -+ - - - - - - - - - - - - - -|
| Illness (Days) | 14
|| - - - - - - - - - - - - - - - -+ - - - - - - - - - - - - - -|
| Illness | 15
|| - - - - - - - - - - - - - - - -+ - - - - - - - - - - - - - -|
| Leave of Absence | 20
|| - - - - - - - - - - - - - - - -+ - - - - - - - - - - - - - -|
|Holiday Without Salary| 8
|l- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -l
I tried to see how I could retrieve some of the string from AbsenceLinks and made a case statement:
CASE
WHEN LEN(AbsenceLink) = 3 THEN SUBSTRING(AbsenceLink,1,1) --1/3
WHEN LEN(AbsenceLink) = 4 and SUBSTRING(AbsenceLink,1,4) LIKE '%/' THEN SUBSTRING(AbsenceLink,1,1)--1/10
WHEN LEN(AbsenceLink) = 4 AND SUBSTRING(AbsenceLink,1,4) LIKE '%/%' THEN SUBSTRING(AbsenceLink,1,2)--17/3
WHEN LEN(AbsenceLink) = 8 AND SUBSTRING(AbsenceLink,1,2) like '%/' AND SUBSTRING(AbsenceLink,5,2) like '%/' THEN SUBSTRING(AbsenceLink,1,1)+', '+SUBSTRING(AbsenceLink,5,1)--2/9 1/10
WHEN LEN(AbsenceLink) = 8 AND SUBSTRING(AbsenceLink,1,3) like '%/' AND SUBSTRING(AbsenceLink,5,3) like '%/' THEN SUBSTRING(AbsenceLink,1,2)+', '+SUBSTRING(AbsenceLink,5,2)--10/3 9/9
WHEN lenLENAbsenceLink) = 9 AND SUBSTRING(AbsenceLink,1,3) like '%/' AND SUBSTRING(AbsenceLink,5,4) like '%' THEN SUBSTRING(AbsenceLink,1,2)+', '+SUBSTRING(AbsenceLink,5,3)--14/3 15/9
End AS AbsLink
I have to compare theese values in a report for some statistic for a customer.
I need theese two tables to be linked and theese columns are the only columns which can be linked.
I want to do like this:
SELECT A.col1, A.col2, B.col1, B.col2
FROM TableA A, TableB B
WHERE A.AbsenceLink = B.Absence
The problem is:
The value of AbsenceLink is a nvarchar value like '20 / 3 1/9 ', there may be one or many spaces before or after the AbsenceID
Absence is a int value like 20 and 1.
I want 20 and 1 from '20/3 1/9' to be compared and linked with the Absence value.
It is a database at my work and I can't change the data or make another table.
So dearest wise and clever programmers - what can I do?
UPDATE: Method with substring and join only.
There is a similar question expand-comma-separated-values-into-separate-rows answered by #KM. we could reference.
Your case is a little different from that one. You should take all the parts within some spaces before and a slash after. It's little harder than split string from a single character. But you can divide it into several steps to solve it.
Extract every part stopped by '/' into rows
The method of #KM. works well of doing this.
Take the last part with spaces ahead.
There may have spaces before the last '/', we need to find the position of the last space after trim the spaces before the last '/'. So we use the trick of revers like this charindex(' ', reverse(rtrim(left(AbsenceLink,number-1))),0).
Here is the result:SQLFiddle
with numbers as
(select 1 as number
union all
select number +1
from numbers
where number<100)
select
Description ,
right(rtrim(left(AbsenceLink,number-1)),charindex(' ', reverse(rtrim(left(AbsenceLink,number-1))),0)) as AbsenceID
from
(select Description, ' '+AbsenceLink as AbsenceLink
from t) as t1
left join numbers
on number<= len(AbsenceLink)
where substring(AbsenceLink,number,1)='/'
NOTE:
If you care about the performance, create an permanent numbers table instead of temp table may be helpful.
More specific explain in this answer.
Method with CTE recursive query
SqlFiddle
with links as
(select
Description,
substring(AbsenceLink,1,charindex('/',AbsenceLink, 0)-1) as AbsenceID,
case when
charindex(' ',AbsenceLink, 0) > 0 then
substring(AbsenceLink,charindex(' ',AbsenceLink, 0)+1,255)
else '' end as left_links
from (select convert(varchar(255),ltrim(rtrim(substring(AbsenceLink,1,charindex('/',AbsenceLink, 0)-1) )) + '/' +ltrim(substring(AbsenceLink,charindex('/',AbsenceLink, 0)+1, 255) ) )as AbsenceLink,
Description
from t) as t1
union all
select
Description,
substring(left_links,1,charindex('/',left_links, 0)-1) as AbsenceID,
case when
charindex(' ',left_links, 0) > 0 then
substring(left_links,charindex(' ',left_links, 0)+1,255)
else '' end as left_links
from (select convert(varchar(255),ltrim(rtrim(substring(left_links,1,charindex('/',left_links, 0)-1) )) + '/' +ltrim(substring(left_links,charindex('/',left_links, 0)+1, 255) ) )as left_links,
Description
from links
where left_links<>'') as t2
)
select
* from links
order by Description
With recursive CTE table, to get first link's absence id in every iteration until all links processed.
If there are more than one space before or after /, ltrim(rtrim(substring(AbsenceLink,1,charindex('/',AbsenceLink, 0)-1) )) + '/' + ltrim(substring(AbsenceLink,charindex('/',AbsenceLink, 0)+1, 255) ) can get rid off all the spaces before or after the first / in each recursive step.
To convert varchar to integer, can reference to SqlServer document here about convert function.
Two methods can get the same result like this:
DESCRIPTION ABSENCEID
Illness 14
Illness 15
Education 18
Education 19
Holiday 8
Leave of Absence 20
you can retrieve id with this query :
SELECT(SUBSTRING(AbsenceLink,0,CHARINDEX('/', AbsenceLink))) FROM table_name
and do your work
OK dude, with this function you can split your field value and get the id
CREATE FUNCTION return_id(#Str VARCHAR(10), #part INT)
RETURNS INT
AS
BEGIN
DECLARE #part1 VARCHAR(10),
#part2 VARCHAR(10)
DECLARE #Spc_Indx INT,
#retVal INT
SET #retVal = 0
SET #part1 = #Str
SET #part2 = ''
IF CHARINDEX(' ', #Str) > 0
BEGIN
SET #Spc_Indx = CHARINDEX(' ', #Str)
SELECT #part1 = SUBSTRING(#str, 0, #Spc_Indx),
#part2 = SUBSTRING(#Str, #Spc_Indx + 1, LEN(#str) -#Spc_Indx)
END
IF #part = 1
SET #retVal = CAST(SUBSTRING(#part1, 0, CHARINDEX('/', #part1)) AS INT)
IF #part = 2
SET #retVal = CAST(SUBSTRING(#part2, 0, CHARINDEX('/', #part2)) AS INT)
RETURN #retVal
END
and you should to use this in your query :
SELECT return_id(AbsenceLink,1),return_id(AbsenceLink,2) FROM table_name
With help from Jaugar Chang I found out the solution to my problem. The code below will show the following result:
______________________________
| Description | AbsenceLinks |
|- - - - - - - - - - - - - - + - - - - - - - - - - - - |
| Education | 19 |
|- - - - - - - - - - - - - - + - - - - - - - - - - - - |
| Education | 18 |
|- - - - - - - - - - - - - - + - - - - - - - - - - - - |
| Holiday | 8 |
|- - - - - - - - - - - - - - + - - - - - - - - - - - - |
| Illness | 14 |
|- - - - - - - - - - - - - - + - - - - - - - - - - - - |
| Illness | 15 |
|- - - - - - - - - - - - - - + - - - - - - - - - - - - |
|
Leave of Absence | 20 |
|______________________________|
WITH links AS
(
SELECT
Description,
SUBSTRING(AbsenceLink,0,CHARINDEX('/',AbsenceLink, 0)) AS AbsenceID,
CASE
WHEN CHARINDEX(' ',AbsenceLink, 0) > 0
THEN SUBSTRING(AbsenceLink,CHARINDEX(' ',AbsenceLink, 0)+1,255)
ELSE ''
END AS linkAbsNr
FROM TableA
UNION ALL
SELECT
Description,
SUBSTRING(linkAbsNr,0,CHARINDEX('/',linkAbsNr, 0)) AS AbsenceID,
CASE
WHEN CHARINDEX(' ',linkAbsNr, 0) > 0
THEN SUBSTRING(linkAbsNr,CHARINDEX(' ',linkAbsNr, 0)+1,255)
ELSE ''
END AS RightAbsNr
FROM links
where linkAbsNr <> ''
)
SELECT Description, AbsenceID
FROM links
ORDER BY Description