我有一列带有用##和组名分隔的城市值。我想按字母顺序对文本列进行排序
问题:
group | values
group1 | jammu##bhopal##chandigardh
group2 | Mumbai##kolkatta
group3 | bangalore
预期结果
group | values
group1 | bhopal##chandigardh##jammu
group2 | kolkatta##Mumbai
group3 | bangalore
我尝试了以下代码
select group,listagg(city,'#') within group (order by city asc) as city
from (
select group, regexp_substr(city,'[^##+',1, LEVEL) as city
from (
select group,city from city_group
)
connect by regexp_substr(city,'[^##+',1, LEVEL) us not null)
group by group
代码永远运行,不会产生任何结果。
答案 0 :(得分:0)
也许以下代码对您有用。
-- Data preparation
CREATE TABLE CITY_GROUP (GROUPS VARCHAR2(100), VALUE VARCHAR2(4000));
INSERT INTO CITY_GROUP VALUES('group1','jammu##bhopal##chandigardh');
INSERT INTO CITY_GROUP VALUES('group2','mumbai##kolkatta');
INSERT INTO CITY_GROUP VALUES('group3','bangalore');
-- Your query
SELECT
GROUPS,
LISTAGG(CITY, '##') WITHIN GROUP(
ORDER BY
CITY
) AS CITY
FROM
(
SELECT DISTINCT
GROUPS AS GROUPS,
REGEXP_SUBSTR(VALUE, '[^##]+', 1, LEVEL) AS CITY
FROM
CITY_GROUP
CONNECT BY
REGEXP_SUBSTR(VALUE, '[^##]+', 1, LEVEL) IS NOT NULL
)
GROUP BY
GROUPS;
输出
希望这就是您想要的。
这里是Demo
答案 1 :(得分:0)
您遗漏了一点JOIN
,因此您的代码可以永远运行。注意第10-12行;这对您来说很重要。
SQL> with test (c_group, c_values) as
2 (select 'group1', 'jammu##bhopal##chandigardh' from dual union all
3 select 'group2', 'mumbai##kolkatta' from dual union all
4 select 'group3', 'bangalore' from dual
5 ),
6 temp as
7 (select c_group,
8 regexp_substr(c_values, '[^##]+', 1, column_value) col
9 from test join
10 table(cast(multiset(select level from dual
11 connect by regexp_substr(c_values, '[^##]+', 1, level) is not null
12 ) as sys.odcinumberlist)) on 1 = 1
13 )
14 select c_group,
15 listagg(col, '##') within group (order by col) result
16 from temp
17 group by c_group
18 order by c_group;
C_GROU RESULT
------ ----------------------------------------
group1 bhopal##chandigardh##jammu
group2 kolkatta##mumbai
group3 bangalore
SQL>
答案 2 :(得分:0)
在SQL中,有多种将字符串拆分为行的方法。我的首选方法是使用递归子因子查询(非Oracle人群使用通用表函数或CTE)。
with city_group(grp, cities) as (
select 'group1', 'jammu##bhopal##chandigardh' from dual union all
select 'group2', 'Mumbai##kolkatta' from dual union all
select 'group3', 'bangalore' from dual
), Recur (grp, cities, city, nxt, lst) as (
-- Anchor Query
select grp, cities
, REGEXP_SUBSTR(cities,'(.+?)(##|$)',1,1,'',1)
, REGEXP_INSTR(cities,'(.+?)(##|$)',1,1,1)
, length(cities)
from city_group
-- Recursive part
union all
select grp, cities
, REGEXP_SUBSTR(cities,'(.+?)(##|$)',nxt,1,'',1)
, REGEXP_INSTR(cities,'(.+?)(##|$)',nxt,1,1)
, lst
from Recur
where nxt <= lst
)
select grp
, listagg(city,'##') within group (order by city)
from Recur
group by grp;
在上面的代码中,“锚查询”返回第一个列表元素,并设置其他列以迭代值列表。具体来说,它返回字符串中的下一个开始搜索位置(nxt
)和字符串中最后一个(lst
)字符的位置,用作递归部分的停止条件。
在查询的递归部分中,随后的列表项将以新的nxt
起始位置重新返回。
利用移动的起始位置可以减少在进一步移入值列表时执行字符串搜索所需的工作量。
现在就使用的正则表达式一词。我使用了一个非贪婪的捕获组[^##]+
来代替错误的[^#]+
搜索字符串,该字符串在功能上与#
等效,并且可以将单个(.+?)
误识别为字符串分隔符。然后是与字符串分隔符或字符串字符(##|$)
的末尾明确匹配的捕获组。然后,REGEXP_SUBSTR
函数使用第6个参数指示第一个捕获组包含应返回的值,而REGEXP_INSTR
函数的最后一个参数指示应返回匹配的子字符串之后的字符位置。
作为最终的奖励解决方案,如果您的数据库安装了最新版本的APEX,则可以使用APEX_STRING.split
表值函数,如下所示:
with city_group(grp, cities) as (
select 'group1', 'jammu##bhopal##chandigardh' from dual union all
select 'group2', 'Mumbai##kolkatta' from dual union all
select 'group3', 'bangalore' from dual
)
select grp
, listagg(column_value,'##') within group (order by column_value)
from city_group cg
cross apply apex_string.split(cities,'##')
group by grp;