oracle – 在oracle表中将多个以逗号分隔的值拆分为多行

我有一个Oracle分裂查询的问题。

虽然分裂逗号分隔数据到多个行使用连接通过和正则expression式在oracle查询我得到更多的重复行 。 例如,实际上我的表有150行,在这两个行中有逗号分隔的string,所以总的来说,我只得到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 

编辑

上面的select查询只能够分割一个逗号分隔的string ,但是当它在多行的表上执行时会产生重复的 。 如何限制重复的行?

最后我想出了这个答案

 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 

像这样尝试,

 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; 

接受的答案使用条件DBMS_RANDOM.VALUE IS NOT NULL这是不合适的。 它只是防止循环,但是一个简单的问题会出现, 如何和何时dbms_random.VALUE可以为空? 从逻辑上讲,它永远不会是NULL

更合适的解决scheme是使用sys.odciNumberList并防止循环循环。

例如,

build立

 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的备用解决scheme:

 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子句。 有关更多示例,请参阅将逗号分隔的string拆分为表格

不使用连接

 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; 

可以使用下面的查询在行中转换逗号分隔值

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

添加一个独特的子句的诀窍是:

  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;