我想从逗号分隔的字符串中检索一组值到查询中的IN子句。有人知道为什么以下代码无法正常工作;
WITH xtable AS (
SELECT 1 ID, '116,117,169,170,173,175,9015,44008,44367,44446,45081,45083,46779,47161,47222' AGT FROM DUAL
UNION ALL
SELECT 2 ID, '456,789' AGT FROM DUAL
UNION ALL
SELECT 3 ID, '116,117,169,170,173,175,9015,44008,44367,44446,45081,45083,46779,47161' AGT FROM DUAL
)
select regexp_substr(x.AGT,'[^,]+', 1, level)
from xtable x
where x.ID = 3
connect by regexp_substr(x.AGT, '[^,]+', 1, level) is not null;
在这种情况下,结果应为
AGT
1 116
2 117
3 169
4 170
5 173
6 175
7 9015
8 44008
9 44367
10 44446
11 45081
12 45083
13 46779
14 47161
相反,我得到了几乎无限循环的相同值
答案 0 :(得分:2)
您的查询中的问题是where子句将仅应用于级别1而不是任何进一步。
使用嵌套表尝试此操作:
WITH xtable AS (
SELECT 1 ID, '116,117,169,170,173,175,9015,44008,44367,44446,45081,45083,46779,47161,47222' AGT FROM DUAL
UNION ALL
SELECT 2 ID, '456,789' AGT FROM DUAL
UNION ALL
SELECT 3 ID, '116,117,169,170,173,175,9015,44008,44367,44446,45081,45083,46779,47161' AGT FROM DUAL
)
select regexp_substr(x.AGT,'[^,]+', 1, t.column_value) agt
from xtable x cross join table(
cast(
multiset(
select level
from dual
connect by level <= regexp_count(x.AGT,',') + 1
)as sys.odcinumberlist
)
) t
where x.id = 3;
这是一个通用查询,如果你想一次转换所有这些,你甚至可以使用where子句。
在Oracle 12c +中,您可以使用OUTER APPLY
来实现相同的效果和更简单的语法:
WITH xtable AS (
SELECT 1 ID, '116,117,169,170,173,175,9015,44008,44367,44446,45081,45083,46779,47161,47222' AGT FROM DUAL
UNION ALL
SELECT 2 ID, '456,789' AGT FROM DUAL
UNION ALL
SELECT 3 ID, '116,117,169,170,173,175,9015,44008,44367,44446,45081,45083,46779,47161' AGT FROM DUAL
)
select regexp_substr(x.AGT,'[^,]+', 1, t.n) agt
from xtable x
outer apply (
select level n
from dual
connect by level <= regexp_count(x.AGT,',') + 1
) t
where x.id = 3;
答案 1 :(得分:1)
您在多行中拥有相同的值,因此您的连接在它们之间反弹。分层查询有点棘手,涉及多行。如果您真的只想要单个ID的值,则可以在子查询中进行过滤:
WITH xtable AS (
SELECT 1 ID, '116,117,169,170,173,175,9015,44008,44367,44446,45081,45083,46779,47161,47222' AGT FROM DUAL
UNION ALL
SELECT 2 ID, '456,789' AGT FROM DUAL
UNION ALL
SELECT 3 ID, '116,117,169,170,173,175,9015,44008,44367,44446,45081,45083,46779,47161' AGT FROM DUAL
)
select regexp_substr(x.AGT,'[^,]+', 1, level)
from (select AGT from xtable where ID = 3) x
connect by regexp_substr(x.AGT, '[^,]+', 1, level) is not null;
REGEXP_SUBSTR(X.AGT,'[^,]+',1,LEVEL)
----------------------------------------------------------------------------
116
117
169
170
173
175
9015
44008
44367
44446
45081
45083
46779
47161
14 rows selected.
或者您可以包含id = prior id
,但是还需要使用非确定性函数调用来阻止循环:
WITH ... (...)
select regexp_substr(x.AGT,'[^,]+', 1, level)
from xtable x
where x.ID = 3
connect by id = prior id and prior dbms_random.value is not null
and regexp_substr(x.AGT, '[^,]+', 1, level) is not null;
返回相同的14行,如果包含多个ID,则可以正常工作。
答案 2 :(得分:1)
Splitting Delimited Strings - SO Oracle Documentation page中有多种解决方案。
使用相关分层查询的解决方案是:
WITH xtable (id, agt ) AS (
SELECT 1, '116,117,169,170,173,175,9015,44008,44367,44446,45081,45083,46779,47161,47222' FROM DUAL
UNION ALL
SELECT 2, '456,789' FROM DUAL
UNION ALL
SELECT 3, '116,117,169,170,173,175,9015,44008,44367,44446,45081,45083,46779,47161' FROM DUAL
)
SELECT id,
REGEXP_SUBSTR( x.agt, '[^,]+', 1, t.COLUMN_VALUE ) AS item
FROM xtable x
CROSS JOIN
TABLE(
CAST(
MULTISET(
SELECT LEVEL
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT( x.agt, '[^,]+' )
)
) AS SYS.ODCINUMBERLIST
) t
WHERE x.id = 3;
<强>输出强>:
ID ITEM
-- -----
3 116
3 117
3 169
3 170
3 173
3 175
3 9015
3 44008
3 44367
3 44446
3 45081
3 45083
3 46779
3 47161