2017-02-22 15 views
2

У меня есть следующая строка, как этотразделить запятые строки на столбцы с пустой строкой

str:=',1,,3,4,5,6,,8,9'; 
str2:=',a,l,,gj,,b'; 

Как я могу разделить запятые и отделенную строку в столбцы, как это с помощью только SQL? (Упорядочение должно быть таким же, как показано ниже)

COL 
--------- 
NULL 
1 
NULL 
3 
4 
5 
6 
NULL 
8 
9 

COL2 
---------- 
NULL 
a 
l 
NULL 
gj 
NULL 
b 

Благодаря

+0

Только одна строка для преобразования? – GurV

+0

Есть ли известный максимум по числу запятых? –

+0

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

ответ

1

Вы можете использовать cross apply с иерархической connect by для достижения этого:

with t (text) as (select ',1,,3,4,5,6,,8,9' from dual union all 
        select ',1,,2' from dual) 
select regexp_substr(text, '[^,]+', 1, lvl) x 
from t cross apply (
    select level lvl 
    from dual 
    connect by level <= regexp_count(t.text, ',') + 1 
    ); 

Вышеупомянутое работает для нескольких строк одновременно.

Если у вас есть только один ряд для преобразования, используйте:

with t (text) as (select ',1,,3,4,5,6,,8,9' from dual) 
select 
    regexp_substr(text, '[^,]+', 1, level) x 
from t connect by level <= regexp_count(text, ',') + 1; 

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

with t (text) as (select ',1,,3,4,5,6,,8,9' from dual union all 
        select ',1,,2' from dual) 
select replace(regexp_substr(text, '[^,]*,?', 1, lvl),',') x 
from t cross apply (
    select level lvl 
    from dual 
    connect by level <= regexp_count(t.text, ',') + 1 
    ); 

Если ваш разделитель ^|{, убедитесь, что вы избегаете специальных символов должным образом. Попробуйте это:

with t (text) as (select '^|{1^|{^|{3^|{4^|{5^|{6^|{^|{8^|{9' from dual union all 
        select '^|{1^|{^|{2' from dual) 
select replace(regexp_substr(text, '[^(\^\|\{)]*(\^\|\{)?', 1, lvl),'^|{') x 
from t cross apply (
    select level lvl 
    from dual 
    connect by level <= regexp_count(t.text, '\^\|\{') + 1 
    ); 
+0

спасибо за ваши анны, но результат не такой, как указано. –

+0

нужна последовательность, например следующая (NULL, 1, NULL, 3,4,5,6, NULL, 8,9) –

+0

Работайте как шарм. благодаря! –

-1

использование как ниже:

declare @ids varchar(max), @xml XML 
       set @ids='135,136' 
       SET @xml = cast(('<X>' + replace(@ids, ',', '</X><X>') + '</X>') as xml) 


       SELECT xmlNode.value('.', 'varchar(50)') 
       FROM @xml.nodes('X') as T(xmlNode) 
+0

Просьба отложить первую строку кода с четырьмя позициями, поэтому она будет отображаться как код –

+2

Вопрос для Oracle, поэтому этот синтаксис недействителен. –

0

regex_replace + подключаться с делает то, что вам нужно, но за исключением NULL значений, поэтому трюк необходим для того, чтобы избежать пустых строк из вывода регулярных выражений замены. В этом случае я добавляю символ # на вход, перед каждым ',', после чего я удаляю его после того, как regex_replace выполнил задание.

Вы можете попробовать следующее (это, конечно, запрос для одного столбца, вам просто нужно скопировать его на 2)

select 
replace(result,'#','') from 
(select 
regexp_substr(replace(',SMITH,ALLEN,WARD,JONES',',','#,'),'[^,]+',1,level) result from dual 
connect by regexp_substr(replace(',SMITH,ALLEN,WARD,JONES',',','#,'), '[^,]+', 1, level) is not null 
); 
0

Вот еще один с помощью xmltable:

SELECT DECODE (column_value, '-~-', NULL, COLUMN_VALUE) 
FROM xmltable(('"' || REPLACE(REGEXP_REPLACE(',1,,3,4,5,6,,8,9','^,|,$|,,', ',-~-,'), 
       ',', '","') || '"')) 

Если вам нужен буквальный NULL:

SELECT TRIM(column_value) 
FROM xmltable(('"' || REPLACE(REGEXP_REPLACE(',1,,3,4,5,6,,8,9','^,|,$|,,', ',NULL,'), 
       ',', '","') || '"')) 

Результаты

NULL 
1 
NULL 
3 
4 
5 
6 
NULL 
8 
9 
0

Используйте пункт факторинга рекурсивный суб-запроса (а.к.а.общее выражение таблицы); Вот пример, который использует простые строковые функции и не зависит от (дорогих) регулярных выражений:

Примеры данных:

CREATE TABLE table_name (id, list) AS 
SELECT 1, 'a,b,c,d' FROM DUAL UNION ALL -- Multiple items in the list 
SELECT 2, 'e'  FROM DUAL UNION ALL -- Single item in the list 
SELECT 3, NULL  FROM DUAL UNION ALL -- NULL list 
SELECT 4, 'f,,g' FROM DUAL;   -- NULL item in the list 

Запрос:

WITH bounds (id, list, start_pos, end_pos, lvl) AS (
    SELECT id, list, 1, INSTR(list, ','), 1 FROM table_name 
UNION ALL 
    SELECT id, 
     list, 
     end_pos + 1, 
     INSTR(list, ',', end_pos + 1), 
     lvl + 1 
    FROM bounds 
    WHERE end_pos > 0 
) 
SELECT id, 
     SUBSTR(
     list, 
     start_pos, 
     CASE end_pos 
      WHEN 0 
      THEN LENGTH(list) + 1 
      ELSE end_pos 
     END - start_pos 
     ) AS item, 
     lvl 
FROM bounds 
ORDER BY id, lvl; 

Выход :

 ID ITEM   LVL 
---------- ------- ---------- 
     1 a    1 
     1 b    2 
     1 c    3 
     1 d    4 
     2 e    1 
     3 (NULL)   1 
     4 f    1 
     4 (NULL)   2 
     4 g    3