Sql oracle--将oracle表中的多个逗号分隔值拆分为多行
我对oracle拆分查询有问题 在oracle查询中使用connect by和正则表达式将逗号分隔的数据拆分为多行时,我得到了更多的重复行。例如,实际上我的表有150行,其中一行和两行有逗号分隔的字符串,所以总体上我只能得到155行,但我得到2000行。如果我使用distinct,它工作正常,但我不希望查询结果中出现重复行 我尝试了以下查询,但它在查询结果中生成了重复的行:Sql oracle--将oracle表中的多个逗号分隔值拆分为多行,sql,regex,oracle,split,Sql,Regex,Oracle,Split,我对oracle拆分查询有问题 在oracle查询中使用connect by和正则表达式将逗号分隔的数据拆分为多行时,我得到了更多的重复行。例如,实际上我的表有150行,其中一行和两行有逗号分隔的字符串,所以总体上我只能得到155行,但我得到2000行。如果我使用distinct,它工作正常,但我不希望查询结果中出现重复行 我尝试了以下查询,但它在查询结果中生成了重复的行: WITH CTE AS (SELECT 'a,b,c,d,e' temp,1 slno FROM DUAL
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查询只能拆分一个逗号分隔的字符串,但是,在具有多行的表上执行时,它会生成重复的行。如何限制重复行?可以使用下面的查询转换行中以逗号分隔的值
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 );
试着这样,
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;
最后我想出了这个答案
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
接受的答案使用DBMS_RANDOM.VALUE为非空的条件,这是不合适的。它只是防止了循环循环,然而一个直截了当的问题是dbms_random.VALUE如何以及何时可以为null?从逻辑上讲,它永远不会为空 更合适的解决方案是使用sys.odciNumberList并防止循环循环 比如说, 设立 所需查询: 有很多方法可以完成这项任务,比如范本条款。有关更多示例,请参见不使用连接方式的:
添加unique子句可以实现以下目的:
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;
关于你的评论,为什么这个工作,不产生重复行?TherRandom似乎阻止了循环循环。从逻辑上讲,先前的DBMS_random.VALUE不为NULL是没有意义的。dbms_random.VALUE如何以及何时可以为空?更好的方法是使用sys.odciNumberList。请看这里的几个演示。这个问题与另一个标记为重复的问题不同。另一个问题是拆分一行,这个问题是关于多行的。接受的答案使用的条件DBMS_RANDOM.VALUE不为NULL,这是不合适的。它只是防止了循环循环,然而一个直截了当的问题是dbms_random.VALUE如何以及何时可以为null?从逻辑上讲,它永远不会为空。更合适的解决方案是使用sys.odciNumberList并防止循环循环。请看下面我的答案。+1更简单易懂-将每个逗号分隔的行与一个虚拟表连接起来,该虚拟表足够大,可以包含比每个逗号分隔列表中的值更多的行,这样就可以得到笛卡尔结果,并使用上面的substr或regexp_substr。太好了。这可以扩展到多列吗。。?我有一个表,有3列,其中2列是分开的,我需要将它们转换成多行。COL1=a,b,c COL2=x,y,z,我需要9行a-x,a-y,a-z,b-x,b-y,b-z,c-y,c-y,c-z-这是可能的吗?@NuthanKumar只是将select正则表达式中的两列串联起来。我刚刚找到了这个答案。我不理解您反对使用以前的dbms_random.value不为空。请注意,这一点的全部内容是先验运算符。当然,该值永远不会为空;该条件的要点不是提供一种打破其他条件所起作用的递归的方法,而是在Oracle用于在分层查询中查找循环的伪列中添加一个不重复的伪列。这些天以前的sys_guid not null出现得更频繁,扮演着完全相同的角色。@mathguy因为从逻辑上讲它从不为null,sys.odciNumberList更有意义。
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.
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>
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;
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;