我必须在toad中编写一个Oracle查询来查找字符串中所有出现的字符。例如,如果我在字符串R
中搜索SSSRNNSRSSR
,则应返回位置4,8和11。
我是Oracle的新手并试过这个。
select instr(mtr_ctrl_flags, 'R', pos + 1, 1) as pos1
from mer_trans_reject
where pos in ( select instr(mtr_ctrl_flags, 'R', 1, 1) as pos
from mer_trans_reject
);
其中mtr_ctrl_flags
是列名。我收到错误消息,指出pos
是无效的标识符。
答案 0 :(得分:13)
扩展GolezTrol的答案,您可以使用正则表达式来显着减少您执行的递归查询的数量:
select instr('SSSRNNSRSSR','R', 1, level)
from dual
connect by level <= regexp_count('SSSRNNSRSSR', 'R')
REGEXP_COUNT()返回模式匹配的次数,在这种情况下,R
中存在SSSRNNSRSSR
的次数。这会将递归级别限制为您需要的确切数字。
INSTR()只是在字符串中搜索R的索引。 level
是递归的深度,但在这种情况下,它也是字符串的 th 级别,因为我们限制了所需的递归次数。
如果您想要挑选的字符串更复杂,那么您可以使用正则表达式REGEXP_INSTR()而不是INSTR(),但它会更慢(不是太多)并且除非需要,否则它是不必要的。
根据要求提供简单的基准:
两个CONNECT BY解决方案表明,对于此大小的字符串,使用REGEXP_COUNT的速度要快20%。
SQL> set timing on
SQL>
SQL> -- CONNECT BY with REGEX
SQL> declare
2 type t__num is table of number index by binary_integer;
3 t_num t__num;
4 begin
5 for i in 1 .. 100000 loop
6 select instr('SSSRNNSRSSR','R', 1, level)
7 bulk collect into t_num
8 from dual
9 connect by level <= regexp_count('SSSRNNSRSSR', 'R')
10 ;
11 end loop;
12 end;
13 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:03.94
SQL>
SQL> -- CONNECT BY with filter
SQL> declare
2 type t__num is table of number index by binary_integer;
3 t_num t__num;
4 begin
5 for i in 1 .. 100000 loop
6 select pos
7 bulk collect into t_num
8 from ( select substr('SSSRNNSRSSR', level, 1) as character
9 , level as pos
10 from dual t
11 connect by level <= length('SSSRNNSRSSR') )
12 where character = 'R'
13 ;
14 end loop;
15 end;
16 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:04.80
流水线表函数有点慢,但看看它如何在大量字符串上执行有很多匹配会很有趣。
SQL> -- PIPELINED TABLE FUNCTION
SQL> declare
2 type t__num is table of number index by binary_integer;
3 t_num t__num;
4 begin
5 for i in 1 .. 100000 loop
6 select *
7 bulk collect into t_num
8 from table(string_indexes('SSSRNNSRSSR','R'))
9 ;
10 end loop;
11 end;
12 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:06.54
答案 1 :(得分:8)
这是一个解决方案:
select
pos
from
(select
substr('SSSRNNSRSSR', level, 1) as character,
level as pos
from
dual
connect by
level <= length(t.text))
where
character = 'R'
dual
是一个内置表,只返回一行。很方便!
connect by
允许您构建递归查询。这通常用于从树状数据(父/子关系)生成列表。它允许您或多或少地在它前面重复查询。而且你有一些特殊的字段,比如level
,可以让你检查递归的深度。
在这种情况下,我使用它将字符串拆分为字符并为每个字符返回一行。使用level
,我可以重复查询并获取一个字符,直到到达字符串的末尾。
然后只需返回包含字符pos
的所有行的'R'
答案 2 :(得分:3)
在a_horse_with_no_name's challenge取消pipelined table function是SQL Fiddle的另一个答案。
pipelined函数返回一个数组,您可以正常查询。我希望在具有大量匹配的字符串上,这将比递归查询表现得更好,但与所有内容一样先测试自己。
create type num_array as table of number
/
create function string_indexes (
PSource_String in varchar2
, PSearch_String in varchar2
) return num_array pipelined is
begin
for i in 1 .. length(PSource_String) loop
if substr(PSource_String, i, 1) = PSearch_String then
pipe row(i);
end if;
end loop;
return;
end;
/
然后为了访问它:
select *
from table(string_indexes('SSSRNNSRSSR','R'))
{{3}}