tags:

views:

409

answers:

2

I have a table with one column " otname " table1.otname contains multiple rows of alpha-numeric string resembling the following data sample:

11.10.32.12.U.A.F.3.2.21.249.1

2001.1.1003.8281.A.LE.P.P

2010.1.1003.8261.A.LE.B.B

I want to read the fourth number in every string ( part of the string in bold ) and write a query in Oracle 10g to read its description stored in another table. My dilemma is writing the first part of the query.i.e. choosing the fourth number of every string in a table

My second query will be something like this:

select description_text from table2 where sncode = 8281  -- fourth part of the data sample in every string

Many thanks.

novice

A: 

Works with 9i+:

WITH portion AS (
  SELECT SUBSTR(t.otname, INSTR(t.otname, ".", 1, 3)+1, INSTR(t.otname, ".", 1, 4)) 'sncode'
    FROM TABLE t)
SELECT t.description_text
  FROM TABLE2 t
  JOIN portion p ON p.sncode = t.sncode

The use of SUBSTR should be obvious; INSTR is being used to find location the period (.), starting at the first character in the string (parameter value 1), on the 3rd and 4th appearance in the string. You might have to subtract one from the position returned for the 4th instance of the period - test this first to be sure you're getting the right values:

SELECT SUBSTR(t.otname, INSTR(t.otname, ".", 1, 3)+1, INSTR(t.otname, ".", 1, 4)) 'sncode'
 FROM TABLE t

I used subquery factoring so the substring happens before you join to the second table. It can be done as a subquery, but subquery factoring is faster.

OMG Ponies
I get the following error when i run the above query:ORA: 00923: FROM keyword not found where expected :(
novice
I don't have an Oracle instance to test on, but the only point of contention I can see would be the "+1" in the first INSTR. You are sure you have a space between the FROM and the table name in what you attempted to run?
OMG Ponies
A: 

Newer versions of oracle (including 10g) have various regular expression functions. So you can do something like this:

where sncode = to_number(regexp_replace(otname, '^(\d+\.\d+\.\d+\.(\d+))?.+$', '\2'))

This matches 3 sets of digits-followed-by-a-dot, and a fourth grouped set of digits, followed by the rest of the string, and returns a string consisting of all that entirely replaced by the first group (the fourth set of digits).

Here's a complete query (if I understood your description of the two tables correctly):

select t2.description_text
from table1 t1, table2 t2
where t2.sncode = to_number(regexp_replace(t1.otname, '^(\d+\.\d+\.\d+\.(\d+))?.+$', '\2'))

Another slightly shorter alternative regex:

where t2.sncode = to_number(regexp_replace(t1.otname, '^((\d+\.){3}(\d+))?.+$', '\3'))
epost
I ran your query and i get the following error: ORA-01722: invalid number Any Suggestions ?
novice
I guess I assumed your "sncode" was a string too. Let me know if it's actually a number. In the mean time, I'm updating my answer to reflect that, so you can try it (the "to_number" func).
epost
thanks. the sncode is actually a number. otname is alphanumeric
novice
I still see the same error : ORA-01722: invalid number. Any other ideas ?
novice
Yeah, I was about to say, that shouldn't matter actually. Oracle will cast that (but it can help with respect to indexes). It's possible that there are rows with strings that don't match the pattern you described. I can adjust the regex to handle that, to return null in those cases. But can you confirm if that's possible? Or do the strings always start with 4 dotted numbers?
epost
Sorry, Maybe i should've mentioned it earlier. There is the odd row or two that does'nt match the pattern i described, but most of the data is in line with the pattern described.
novice
No problem. I just updated it to handle ones that don't match.
epost
Hi, the query now gives zero results.
novice
It could be an issue with something else in the table, which is going to be hard to figure out without knowing more about the tables and data. If the following works (returns "12"), it's probably some other issue: select regexp_replace('11.10.32.12.U.A.F.3.2.21.249.1', '^(\d+\.\d+\.\d+\.(\d+))?.+$', '\2') from dual
epost
...another possibility. When you copied my last change, did you also copy the last arg or just the regex itself? It changed from \1 to \2 (or in the last example, \2 to \3).
epost