2013-09-12 8 views
5

У меня возникла проблема с запросом оракула.oracle - Разделить несколько разделенных запятыми значений в таблице оракула на несколько строк

Разделение разделенных запятыми данных на несколько строк с использованием соединения и регулярного выражения в запросе оракула. ​​Я получаю больше дубликатов строк. например, на самом деле моя таблица имеет 150 строк в том, что две строки имеют разделенные запятой строки, поэтому в целом мне нужно получить только 155 строк, но я получаю 2000 строк. Если я использую отличную работу, но я не хочу дублировать строки в результате запроса.

Я попытался следующий запрос, однако, что генерирует повторяющиеся строки в результате запроса:

WITH CTE AS (SELECT 'a,b,c,d,e' temp,1 slno FROM DUAL 
       UNION 
       SELECT 'f,g',2 from dual 
       UNION 
       SELECT 'h',3 FROM DUAL) 

SELECT TRIM(REGEXP_SUBSTR(TEMP, '[^,]+', 1, LEVEL)) ,SLNO FROM CTE 
CONNECT BY LEVEL <= LENGTH(REGEXP_REPLACE(temp, '[^,]+')) + 1 

EDIT

Приведенный выше запрос на выборку только в состоянии разделить запятая строки с разделителями, однако , он создает повторяющиеся строки при выполнении в таблице с несколькими строками. Как ограничить дублирующиеся строки?

+0

Этот вопрос не является дубликатом другой вопрос помечено как дубликат , Другой вопрос - разделение одной строки, и этот вопрос касается нескольких строк. –

+0

В принятом ответе используется условие 'DBMS_RANDOM.VALUE IS NOT NULL', которое неуместно. Он просто предотвращает циклическую петлю, однако прямой вопрос будет возникать как ** Как и когда dbms_random.VALUE может быть нулевым? ** Логически, он никогда не будет NULL. Более подходящим решением является использование 'sys.odciNumberList' и предотвращение циклического цикла. См. Мой ответ ниже. –

ответ

6

Наконец я придумал этот ответ

WITH CTE AS (SELECT 'a,b,c,d,e' temp, 1 slno FROM DUAL 
       UNION 
       SELECT 'f,g' temp, 2 slno FROM DUAL 
       UNION 
       SELECT 'h' temp, 3 slno FROM DUAL) 
SELECT TRIM(REGEXP_SUBSTR(temp, '[^,]+', 1, level)), slno 
FROM CTE 
CONNECT BY level <= REGEXP_COUNT(temp, '[^,]+') 
    AND PRIOR slno = slno 
    AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL 
+1

Что касается вашего комментария [здесь] (http://stackoverflow.com/a/14331055/696632), почему это работает и не создает дублирующие строки? Кажется, что случайный случай не позволяет циклическую петлю. –

+0

Логически, 'ПРИОР DBMS_RANDOM.VALUE IS NOT NULL' не имеет смысла. Как и когда 'dbms_random.VALUE' может быть нулевым? Лучший способ - использовать 'sys.odciNumberList'. См. Несколько демонстраций здесь. Https://lalitkumarb.wordpress.com/2015/03/04/split-comma-delimited-strings-in-a-table-using-oracle-sql/ –

0

Можно использовать ниже запрос для преобразования разделенных запятыми значений в строках

SELECT trim(x.column_value.extract('e/text()')) COLUMNS 
from t t, table (xmlsequence(xmltype('<e><e>' || replace(valuestring,':','</e><e>')|| 
'</e></e>').extract('e/e'))) x ); 
5

Попробуйте, как это,

WITH CTE AS (SELECT 'a,b,c,d,e' temp,1 slno FROM DUAL 
       UNION 
       SELECT 'f,g',2 from dual 
       UNION 
       SELECT 'h',3 FROM DUAL) 
    SELECT regexp_substr (temp, '[^,]+', 1, rn)temp, slno 
    FROM cte 
    CROSS JOIN 
    (
      SELECT ROWNUM rn 
      FROM (SELECT MAX (LENGTH (regexp_replace (temp, '[^,]+'))) + 1 max_l 
       from cte 
       ) 
      connect by level <= max_l 
     ) 
    WHERE regexp_substr (temp, '[^,]+', 1, rn) IS NOT NULL 
    order by temp; 
2

Принятая ответ использует условие DBMS_RANDOM.VALUE IS NOT NULL, что неуместно. Он просто предотвращает циклическую петлю, однако прямой вопрос будет возникать как Как и когда dbms_random.VALUE может быть пустым? Логически, он никогда не будет NULL.

Более подходящим решением является использование sys.odciNumberList и предотвращение циклического цикла.

Например,

Настройка

SQL> CREATE TABLE t (
    2 ID   NUMBER GENERATED ALWAYS AS IDENTITY, 
    3 text  VARCHAR2(100) 
    4 ); 

Table created. 

SQL> 
SQL> INSERT INTO t (text) VALUES ('word1, word2, word3'); 

1 row created. 

SQL> INSERT INTO t (text) VALUES ('word4, word5, word6'); 

1 row created. 

SQL> INSERT INTO t (text) VALUES ('word7, word8, word9'); 

1 row created. 

SQL> COMMIT; 

Commit complete. 

SQL> 
SQL> SELECT * FROM t; 

     ID TEXT 
---------- ---------------------------------------------- 
     1 word1, word2, word3 
     2 word4, word5, word6 
     3 word7, word8, word9 

SQL> 

Обязательный запрос:

SQL> SELECT t.id, 
    2   trim(regexp_substr(t.text, '[^,]+', 1, lines.column_value)) text 
    3 FROM t, 
    4 TABLE (CAST (MULTISET 
    5 (SELECT LEVEL FROM dual CONNECT BY LEVEL <= regexp_count(t.text, ',')+1) 
    6     AS sys.odciNumberList 
    7    ) 
    8   ) lines 
    9 ORDER BY id 
10/

     ID TEXT 
---------- -------------------------------------------------- 
     1 word1 
     1 word2 
     1 word3 
     2 word4 
     2 word5 
     2 word6 
     3 word7 
     3 word8 
     3 word9 

9 rows selected. 

Альтернативное решение с использованием XMLTABLE:

SQL> SELECT id, 
    2   trim(COLUMN_VALUE) text 
    3 FROM t, 
    4 xmltable(('"' 
    5 || REPLACE(text, ',', '","') 
    6 || '"')) 
    7/

     ID TEXT 
---------- ------------------------ 
     1 word1 
     1 word2 
     1 word3 
     2 word4 
     2 word5 
     2 word6 
     3 word7 
     3 word8 
     3 word9 

9 rows selected. 

SQL> 

Существует множество способов достижения этой задачи, как статья MODEL.Дополнительные примеры см Split comma delimited strings in a table

+0

это можно расширить до нескольких столбцов .. ? У меня есть таблица с 3 столбцами, в которой 2 из них разделены, мне нужно преобразовать их в несколько строк. COL1 = a, b, c COL2 = x, y, z и мне нужны 9 строк a-x, a-y, a-z, b-x, b-y, b-z, x-z, c-y, c-z - Это что-то возможно? –

+0

@NuthanKumar Просто соедините два столбца в регулярном выражении select. –

+0

Я только наткнулся на этот ответ. Я не понимаю, что ваше возражение против использования 'previous dbms_random.value() не является нулевым. (Обратите внимание, что все это является оператором 'ПРИОР'.) Конечно, это значение никогда не равно NULL; точка этого условия не должна обеспечивать способ выхода из рекурсии (другие условия играют эту роль), но для добавления не повторяющегося псевдоколона к тем, которые Oracle использует для поиска циклов в иерархическом запросе. В наши дни PRIOR sys_guid() не является нулевым, чаще рассматривается, играя точно такую ​​же роль. – mathguy

1

без использования подключения по:

WITH CTE AS (SELECT 'a,b,c,d,e' temp,1 slno FROM DUAL 
     UNION 
     SELECT 'f,g',2 from dual 
     UNION 
     SELECT 'h',3 FROM DUAL 
) 
,x as (
    select 
    ','||temp||',' temp 
    ,slno 
    from CTE 
) 
,iter as (SELECT rownum AS pos 
    FROM all_objects 
) 
select 
SUBSTR(x.temp 
    ,INSTR(x.temp, ',', 1, iter.pos) + 1 
    ,INSTR(x.temp, ',', 1, iter.pos + 1)-INSTR(x.temp, ',', 1, iter.pos)-1 
) temp 
,x.slno 
from x, iter 
where iter.pos < = (LENGTH(x.temp) - LENGTH(REPLACE(x.temp, ','))) - 1; 
+0

+1 намного проще и понятнее - присоединяйте каждую разделенную запятыми строку с манекеном, достаточно большим, чтобы содержать больше строк, чем значений в каждом из разделенных запятыми списков (так что вы получаете декартовы результат), и используйте либо субстрат, как указано выше, или REGEXP_SUBSTR. Великий. –

0

Добавление уникального положение делает трюк:

WITH cte AS (
     SELECT 'a,b,c,d,e' temp, 1 slno FROM DUAL UNION 
     SELECT 'f,g',2 FROM DUAL UNION SELECT 'h',3 FROM DUAL 
    ) SELECT UNIQUE(slno),REGEXP_SUBSTR(temp,'[^,]+', 1, LEVEL)temp FROM cte 
    CONNECT BY LEVEL<=REGEXP_COUNT(temp, '[^,]+') ORDER BY slno; 
Смежные вопросы