2010-08-24 1 views
0

ребята. Скажем, у меня есть следующая таблица:Разбор строки в таблицу с использованием oracle SQL

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

Это устаревший формат данных в моем приложении, которого в настоящее время невозможно избежать. Что мне нужно для того чтобы достигнуть, это:

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

Все предложения о том, как добиться этого результата, используя только простой Oracle SQL без создания каких-либо дополнительных предметов или PL-SQL процедуры?

Спасибо.

+0

Я не думаю, что вы можете сделать это без хранимых процедур. Нет никакой встроенной функции Oracle, которая делает это, насколько я знаю. – Wolph

+1

Какую версию Oracle вы используете? – APC

+0

Я использую Oracle 9i. –

ответ

5
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; 
+0

+1 - это делает работу без необходимости в каких-либо дополнительных объектах. – APC

+0

Стоит пояснять, что «выбрать уровень element_number из двойного соединения по уровню <= 5» в основном генерирует список целых чисел из тонкого воздуха. Это хороший чит для генерации последовательных данных, где у вас нет исходной таблицы, и, очевидно, мы можем использовать другие функции. – JulesLt

+0

Подзапрос в этом соединении по условию уровня не работает, но тем не менее, когда я заменяю его на константу - это прекрасно. Спасибо, спасибо. –

0

Если рассмотреть с помощью хранимых процедур в любом случае, попробуйте следующее:

Источник: 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; 
0

Попробуйте это:

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

Я пользователь MS SQL Server, так что я не конечно, если это сработает, но дайте мне знать ...

+0

Это работает, если у меня в моей строке не более двух частей данных, но у меня может быть три или более, поэтому я думаю, что это не так способ писать N союзов каждый раз. :) –

+0

oh .. так что вы также можете получить <345><23><87> ?? –

+0

Да, я могу, и у меня нет информации о том, сколько штук есть в каждой строке. Все, что я знаю, есть, скажем, не менее одного, и не более шести или семи из них в каждой строке. –