Oracle joining tables where the matching process starts after certain digits - oracle

I have joined two tables which contain words as well as values. The matching of the words works. The matching of the values do not. The reason is that the values in the table "GATTUNGSDATEN" always start with 4 zeros whereas in the table BONDMAPPING not. E.g. 00001234 = 1234. What query could I use in order to have the matching process started after 4 digits?
select MET_SEC_INDEX_GATTUNGSDATEN.ranl, MET_SEC_INDEX_GATTUNGSDATEN.vvranlwx,
V_AR_BONDMAPPING.MUREXEXTERNALID
from V_AR_BONDMAPPING
RIGHT JOIN MET_SEC_INDEX_GATTUNGSDATEN
ON V_AR_BONDMAPPING.MUREXEXTERNALID = MET_SEC_INDEX_GATTUNGSDATEN.ranl IN
('%%%%')
where vvranlwi=34

If it's always four leading zeroes you can use SUBSTR():
from V_AR_BONDMAPPING
RIGHT JOIN MET_SEC_INDEX_GATTUNGSDATEN
ON V_AR_BONDMAPPING.MUREXEXTERNALID = substr(MET_SEC_INDEX_GATTUNGSDATEN.ranl, 5)
This trims the leading four characters from MET_SEC_INDEX_GATTUNGSDATEN.ranl

If you know the length of the identifiers you could pad the shorter identifier with leading zeroes
select lpad(1234, 8, '0') from dual
=>
00001234
select lpad('00001234', 8, '0') from dual
=>
00001234
This will implicitly convert the numbers into VARCHAR2s however, which on the other hand is what would happen anyways during the comparison

Related

how to trim leading zero in oracle sql from concatenation text (text:number-number-number

how to trim leading zero in oracle sql from concatenation text
(text:number-number-number)
example(word:number-number-number) word can have text or double zero
but always has char before it after word, max digits separated by '-'
all time max 3 digits i want to keep zeros in first part. and after
that if remove leading 0 in sequence but keep it if it's only one 0
MachineAbc00:1-0-03 = MachineAbc00:1-0-3
MachineAbc00:1-001-02 = MachineAbc00:1-1-2
tried many combination, not successful , like
REGEXP_REPLACE ('MachineO00:1-0-03*', '0+(?!$)', '-')
REGEXP_REPLACE ('MTROPQFMO00:1-0-03*', '(-0){1,}', '-')
If all the input strings are in the exact format you said they are, then something like this should work:
with
sample_strings (str) as (
select 'MachineAbc00:1-0-03' from dual union all
select 'MachineAbc00:1-001-02' from dual union all
select 'MachineZzzyx:200-020-002' from dual union all
select 'machineCX032:0-000-0' from dual
)
select str as old_str,
regexp_replace(str, '([:-])0*(\d+)', '\1\2') as new_str
from sample_strings
;
OLD_STR NEW_STR
------------------------ ------------------------
MachineAbc00:1-0-03 MachineAbc00:1-0-3
MachineAbc00:1-001-02 MachineAbc00:1-1-2
MachineZzzyx:200-020-002 MachineZzzyx:200-20-2
machineCX032:0-000-0 machineCX032:0-0-0
The regular expression function finds any occurrence of (colon or dash) followed by (zero or more 0 characters/digits) followed by at least one more digit. The "zero or more 0 digits" is maximal with the property that there must be at least one more digit AFTER that match (even if that extra digit hapens to be a zero - see my last test string, which I added precisely in order to test that this works correctly). The function replaces each such occurrence with the first and third fragments, removing the middle one (the zeros you must remove from your string). The references \1 and \2 refer to the first and the second parenthesized sub-expressions - the punctuation mark (colon or dash) and, respectively, the final digits (excluding the leading zeros that must be removed).

SQL regexp - replace dots between two numbers

I need to change this;
J S49-1:7.5-190 d.
to this;
J S49-1:7,5-190 d.
by replacing all dots with commas, but only between numbers.
With capture groups within REGEXP_REPLACE;
select REGEXP_REPLACE('J S49-1:7.5-190 d.', '(.*\d)\.(\d.*)', '\1,\2') from dual;
will return;
J S49-1:7,5-190 d.
But this will not work if there are multiple occurrences of periods between digits.
In case there are more than one occurrence of period between digits
I was able to trigger multi replace with capture groups;
select REGEXP_REPLACE('J S49-1:7.557.8-190 d.', '(\d)\.(\d)', '\1,\2', 1, 0) from dual;
will return;
J S49-1:7,557,8-190 d.
The last two parameters are; start_position and nth_appearance, to replace all occurrences, nth_appearance value must be 0
But still there is a problem when two capture groups share a digit, this is due to overlapping (same issue as this), and needs lookahead to resolve, but can't use it in oracle, hmmm.
In case there are more than one occurrence of period between digits, and same digit is shared between two occurrence
One solution would be to apply the secondary REGEXP_REPLACE I've shared twice, so any overlapping cases would be covered in the second run;
select REGEXP_REPLACE(
REGEXP_REPLACE('J S49-1:7.5.8.7-190 d.', '(\d)\.(\d)', '\1,\2', 1, 0),
'(\d)\.(\d)', '\1,\2', 1, 0) from dual;
will be the correct result;
J S49-1:7,5,8,7-190 d.
For more detail on REGEXP_REPLACE, check here
One way using REGEXP_SUBSTR:
select REGEXP_SUBSTR('J S49-1:7.5-190 d','[^.]+',1,1)||','||REGEXP_SUBSTR('J S49-1:7.5-190 d','[^.]+',1,2) from dual;
Here is with regexp_replce
select REGEXP_REPLACE('J S49-1:7.5-190 d','[.*]',',') from dual

Oracle 01481. 00000 - "invalid number format model"

This is my query i have used to get the value as money. Nut when concat value getting above exception. The query is
select to_char(b.balance,'9999.'||d.number_of_decimal_places) from balance b, decimal d
Am stuck with this problem.
If you have numeric number_of_decimal_places values like 1, 2, 3 etc. then you are constructing a format model like, for example, '9999.2' instead of '9999.99'.
You can convert that integer value to the format model with rpad or lpad:
select to_char(b.balance,'9999.'||rpad('9', d.number_of_decimal_places, '9'))
from balance b, decimal d
Or for trailing zeros:
select to_char(b.balance,'9999.'||rpad('0', d.number_of_decimal_places, '0'))
from balance b, decimal d
If you have string number_of_decimal_places values like '9', '99', '999' etc. then the concatenation you have will work unless you have an invalid value in one of the rows, which would be any character other than a 9 or a 0.
That includes spaces, which you could have in a varchar2 or char field. Either way you could remove those with trim:
select to_char(b.balance,'9999.'||trim(d.number_of_decimal_places))
from balance b, decimal d
But if you have any other characters then you will need to identify and correct the data in those rows; and even with spaces it would be better to fix the data if it's a varchar2 column.
It would be better to use new-style joins; I haven't changed these examples because it isn't clear if you are doing a cartesian product or have just omitted the join conditions.
If number_of_decimals returns a value like 2 then:
SELECT TO_CHAR( b.balance, RPAD( '9999.', 5 + d.number_of_decimals, '9' ) )
FROM balance b
CROSS JOIN
decimal d
For whatever reason, the concatenation of '9999.'||d.number_of_decimal_places is generating an invalid mask. We can only guess at the actual table values, presence of spaces, or whatever else may be causing issues with what it is doing.
So your solution is to run:
select '9999.'||d.number_of_decimal_places from decimal d
See what the actual format mask is that you are generating, and adjust as necessary.

Oracle cursor removes leading zero

I have a cursor which selects date from column with NUMBER type containg floating point numbers. Numbers like 4,3433 are returned properly while numbers smaller then 1 have removed leading zero.
For example number 0,4513 is returned as ,4513.
When I execute select used in the cursor on the database, numbers are formatted properly, with leading zeros.
This is how I loop over the recors returned by the cursor:
FOR c_data IN cursor_name(p_date) LOOP
...
END LOOP;
Any ideas why it works that way?
Thank you in advance.
You're confusing number format and number value.
The two strings 0.123 and .123, when read as a number, are mathematically equals. They represent the same number. In Oracle the true number representation is never displayed directly, we always convert a number to a character to display it, either implicitly or explicitly with a function.
You assume that a number between 0 and 1 should be represented with a leading 0, but this is not true by default, it depends on how you ask this number to be displayed. If you don't want unexpected outcome, you have to be explicit when displaying numbers/dates, for example:
to_char(your_number, '9990.99');
It's the default number formatting that Oracle provides.
If you want to specify something custom, you shall use TO_CHAR function (either in SQL query or PL/SQL code inside the loop).
Here is how it works:
SQL>
SQL> WITH aa AS (
2 select 1.3232 NUM from dual UNION ALL
3 select 1.3232 NUM from dual UNION ALL
4 select 332.323 NUM from dual UNION ALL
5 select 0.3232 NUM from dual
6 )
7 select NUM, to_char(NUM, 'FM999990D9999999') FORMATTED from aa
8 /
NUM FORMATTED
---------- ---------------
1.3232 1.3232
1.3232 1.3232
332.323 332.323
.3232 0.3232
SQL>
In this example, 'FM' - suppresses extra blanks, '0' indicates number digit including leading/trailing zeros, and '9' indicates digit suppressing leading/trailing zeros.
You can find many examples here:
http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm#i34570

Substring inside string

Suppose this is my table:
ID STRING
1 'ABC'
2 'DAE'
3 'BYYYYYY'
4 'H'
I want to select all rows that have at least one of the characters in the STRING column somewhere in another row's STRING variable.
For example, 1 and 2 have an A in common and 1 ad 3 have a B in common, but 4 does not have any characters in common with any of the other rows. So my query should return only the first three lines.
I don't need to know with which line it matched.
Thanks!
#A.B.Cade : Good solution but could be done without any distinct nor join.
SELECT * FROM test t1
WHERE EXISTS
(
SELECT * FROM test t2
WHERE t1.id<>t2.id AND
regexp_like(t1.string, '['|| replace(t2.string, '.[]', '\.\[\]')||']')
)
The query won't compare the string with extra rows since it'll stop the comparison as soon as 1 match is found for the current row...
See fiddle.
#GolezTrol's answer is a good one, but here is another approach:
select distinct t1."ID", t1."STRING"
from table1 t1, table1 t2
where t1."ID" <> t2."ID"
and regexp_like(t1."STRING", '['|| t2."STRING"||']')
First take a cartessian product of the table
Then make sure your not comparing the same string to itself
then create a regexp from one string for comparing to the other - [<string1>] means that the string must contain one of the letters in the [ ] which are all from string1
Here is a fiddle
Like this:
select distinct
id, name
from
(select distinct
x.id,
x.NAME,
length(x.NAME) as leng,
substr(x.name, level, 1) as namechar
from
YourTable x
start with
level = 0
connect by
level <= length(x.name)) y
where
exists
(select
'x'
from
YourTable z
where
instr(z.name, y.namechar) > 0 and
z.id <> y.id)
order by
id
What it does:
First, (inner select) use the table with a number generator that returns a number for each letter in the name. Now each record in YourTable is returned Length(Name) times, each with another number. That generated number is used to isolate that letter (substr).
Then (subselect in top level where clause) check if records exist that contain that isolated letter. Distinct is needed, because records are returned more than once if more than one letter matches. You could add namechar to the outer select field list to see the letter that match.

Resources