views:

63

answers:

3

Hi, guys. Say I have the following table:

ID | String
---+---------  
1  | <123><345>  
2  | <1-2><45-67>  
3  | <345-321><234>

This is a legacy data format in my app which is currently impossible to avoid. What I need to acheive, is:

ID | String
---+---------
1  | <123>  
1  | <345>  
2  | <1-2>  
2  | <45-67>  
3  | <345-321>  
3  | <234>  

Any suggestions about how to acheive this result using only plain Oracle SQL without creating any additional objects or pl-sql procedures?

Thanks.

A: 

If you consider using stored procedures anyway, try this:

Source: http://jasonvogel.blogspot.com/2006/11/oracle-sql-converting-one-row-into-two.html

CREATE OR REPLACE FUNCTION split (
 s_delimited_list_in     VARCHAR2,
 s_delimiter_in          VARCHAR2 := ',')
RETURN prod_types.type_string_array PIPELINED
IS
/*
@Usage Example:
select * from table(split('one,two,three'));
*/
 l_idx               PLS_INTEGER;
 l_list              VARCHAR2(32767) := s_delimited_list_in;
 l_value             VARCHAR2(32767);
 ls_delimiter        VARCHAR2(100) := NVL(s_delimiter_in,',');
BEGIN
LOOP
 l_idx := INSTR(l_list,ls_delimiter);

 IF (l_idx > 0) THEN

    PIPE ROW(SUBSTR(l_list,1,l_idx-1));
    l_list := SUBSTR(l_list,l_idx+LENGTH(ls_delimiter));

 ELSE

    PIPE ROW(l_list);
    EXIT;

 END IF;
END LOOP;

RETURN;

END SPLIT;
WoLpH
A: 

Try this:

SELECT Id, SUBSTR(String,1,INSTR(String,'>',1,1)) FROM MyTable
UNION ALL
SELECT Id, SUBSTR(String,INSTR(String,'<',1,2)) FROM MyTable

I am an MS SQL Server user so I am not sure if it'll work but let me know...

Raze2dust
It works if I have not more than two pieces of data in my line, but I can have three or more, so I guess it's no way to write N unions each time. :)
be here now
oh.. so you can also have <345><23><87> ??
Raze2dust
Yes, I can, and I have no information about how many pieces are there in each line. All I know there are, say, no less than one, and at most six or seven of them in each line.
be here now
See Jon Earle's answer above - you can take a similar approach by doing a cartesian join against a fake table that returns N rows, where N is the count of data items, and then using the count to drive the offset of the INSTR.
JulesLt
+4  A: 
select id, string
  ,substr(string, instr(string, '<', 1, element_number)
    ,instr(string, '>', 1, element_number) - instr(string, '<', 1, element_number) + 1) result
from test
cross join
(
  select level element_number from dual connect by level <=
    (select max(length(string) - length(replace(string, '<', null))) max_elements from test)
) extra_rows
where element_number <= length(string) - length(replace(string, '<', null))
order by id, element_number;
jonearles
+1 - this does the job without the need for any additional objects.
APC
Worth explaining that "select level element_number from dual connect by level <= 5" basically generates a list of integers from thin air. It's a good cheat for generating sequential data where you have no source table, and can obviously we fed into other functions.
JulesLt
Subquery in this connect by level clause doesn't work, but nevertheless, when I replace it by constant - it does fine. That would work for me, thanks.
be here now
@BeHereNow - this use of the CONNECT BY syntax (without a PRIOR clause) was controversial in 9i, as it wasn't documented and didn't work exactly the same in all versions of the database (sometimes we had to wrap things in extra brackets). But Jon's code worked without a hitch in my 11g database.
APC
It seems 'Kyte approved' (i.e. even though undocumented, it has been used in a few AskTom answers - I doubt Oracle would change/remove the behavior by now).
JulesLt
@JulesLt - indeed it does have the Tom seal of approval but Tom - great though he be - is not the Oracle documentation. Still, it is behaviour that I rely on in my 11g database. I am just saying, the same statement wouldn't work uniformly across all versions of 9i; I remember 9.2.0.6 was a problem in this regard. The solution was to wrap it in `SELECT * FROM ( ... )` which is precisely the sort of annoying workaround which can happen when we use undocumented features.
APC