想象一下,我有一张像
这样的表Name
----
ABCDEFG
ABChello world
ABCDEfoo
ABbar
ABCDEF
ABCDEFGHIJKLMNOP
zzz
qABCD
ABCqqqGH
ABCABC
我想做一个查询并找出每个字符串中有多少个字符匹配所需的字符串“ABCDEFGHIJ”,始终从头开始。那是......
Name MatchingLength
---- ----
ABCDEFG 7
ABChello world 3
ABCDEzoo 5
ABbar 2
ABCDEF 6
ABCDEFGHIJKLMNOP 10
zzz 0
qABCD 0
ABCqqqGH 3
ABCABC 3
有没有办法在Oracle中干净利落地完成这项工作?我很茫然。
答案 0 :(得分:4)
不知道“干净”,但这里有两个解决方案。
-- The hardcoded, bad performance. No transformation of your string though.
with patterns as (
select substr('ABCDEFGHIJ', 1, rownum) txt
from dual
connect by level <= length('ABCDEFGHIJ')
)
select d.txt, coalesce(max(length(p.txt)), 0)
from dummy d
left join patterns p
on instr(d.txt, p.txt) = 1
group by d.txt
order by 2 desc;
-- The cool one with regex.
-- Though transforming your input string,
-- this can also be done with ease making something that transorms it for you
-- like in the previous example, more complicated task than the previous,
-- as oracle sucks with string manipulation. You can however write it in java.
select d.txt, coalesce(LENGTH(REGEXP_SUBSTR(d.txt, '^A(B(C(D(E(F(G(H(I(J)?)?)?)?)?)?)?)?)')), 0)
from dummy d;
http://www.sqlfiddle.com/#!4/85ba6/23
<强>更新强>
with patterns as (
select substr('ABCDEFGHIJ', 1, rownum) txt
from dual
connect by level <= length('ABCDEFGHIJ')
)
select d.txt, coalesce(max(length(p.txt)), 0)
from dummy d
left join patterns p
on instr(d.txt, p.txt) = 1
where d.txt LIKE substr('ABCDEFGHIJ', 1, 1) || '%'
group by d.txt
order by 2 desc;
更新了小提琴:http://www.sqlfiddle.com/#!4/37400/6
在oracle 10g上测试生成的查询计划
SELECT STATEMENT, GOAL = ALL_ROWS
SORT ORDER BY
SORT GROUP BY NOSORT
NESTED LOOPS OUTER
INDEX RANGE SCAN I <<<< Uses the index.
VIEW
COUNT
CONNECT BY WITHOUT FILTERING
FAST DUAL
答案 1 :(得分:0)
假设您希望仅匹配那些以字母开头的字符串的匹配计数
ABCDEFGHIJ
以及qABCD
等字符串,匹配计数为0
SELECT STR,DECODE(SUBSTR(STR,1,1),'A',LENGTH(STR)-
NVL(LENGTH(REPLACE(TRANSLATE(STR,'ABCDEFGHIJ',' '),' ','')),0),0) MATCHING_LENGTH FROM table
答案 2 :(得分:0)
如果您使用的是Oracle 11gR2,则可以使用Recursive Common Table Expressions,如下所示:
with rcte(txt,t, p, c) as
(
select d.txt , d.txt t, 'ABCDEFGHIJ' p, 0 c
from dummy d
union all
select txt ,substr(t, 2), substr(p, 2), case when substr(t, 1, 1) = substr(p, 1, 1) then 1 else 0 end
from rcte
where length(t) > 0 and length(p) > 0 and substr(t, 1, 1) = substr(p, 1, 1)
)
select txt, sum(c) from rcte
group by txt;
Here is a sqlfiddle demo(感谢@Roger)
答案 3 :(得分:0)
假设匹配条件是符号和位置相等(模式ABCqqqGH
的值是5),您可以尝试这样做:
17:57:03 SYSTEM@sandbox> @sf test
VAL
------------------------------
ABCDEFG
ABChello world
ABCDEzoo
ABbar
ABCDEF
ABCDEFGHIJKLMNOP
zzz
qABCD
8 rows selected.
Elapsed: 00:00:00.01
17:57:05 SYSTEM@sandbox> @get match
1 select t.val, count(l)
2 from test t
3 left join (select level l from dual connect by level <= length('ABCDEFGHIJ')) i
4 on substr(t.val, i.l, 1) = substr('ABCDEFGHIJ', i.l, 1)
5 group by t.val
6* order by 2 desc
17:57:07 SYSTEM@sandbox> /
VAL COUNT(L)
------------------------------ ----------
ABCDEFGHIJKLMNOP 10
ABCDEFG 7
ABCDEF 6
ABCDEzoo 5
ABChello world 3
ABbar 2
zzz 0
qABCD 0
8 rows selected.
Elapsed: 00:00:00.02
答案 4 :(得分:0)
declare
v_1 number := 0;
v_pattern VARCHAR(26) := '&n';
v_f number;
v_spaces VARCHAR(30) := ' ';
v_l number;
v_c varchar(20) := ' ';
v_n varchar(20) := ' ';
BEGIN
v_f := Ascii(SubStr(v_pattern,1,1));
v_l := Ascii(SubStr(v_pattern,Length(v_pattern)));
v_spaces := LPad(' ',Length(v_pattern),' ');
for i in (select str,TRANSLATE(REPLACE(str,' ',''),v_pattern,v_spaces) c1,length(REPLACE(str,' ',''))-nvl(length(replace(TRANSLATE(REPLACE(str,' ',''),v_pattern,v_spaces),' ','')),0) c2 from table
where ascii(substr(str,1,1)) IN (SELECT DISTINCT Ascii(SubStr(v_pattern,LEVEL,1)) FROM dual CONNECT BY LEVEL<=Length(v_pattern))) loop
for j in 1..i.c2 loop
v_c :=instr(i.c1,' ',1,j);
v_n :=instr(i.c1,' ',1,j+1);
if v_c+1=v_n then
v_1 := v_1+1;
end if;
end loop;
if(v_1+1 = i.c2) then
dbms_output.put_line('String : '||i.str||' and Matching count : '||i.c2);
else
dbms_output.put_line('String : '||i.str||' and Matching count : '||((v_1)-1));
end if;
v_1 := 0;
end loop;
FOR k IN (SELECT str FROM table WHERE NOT(Ascii(substr(str,1,1)) IN (SELECT DISTINCT Ascii(SubStr(v_pattern,LEVEL,1)) FROM dual CONNECT BY LEVEL<=Length(v_pattern)))) LOOP
dbms_output.put_line('String : '||k.str||' and Matching count : '||v_1);
END LOOP;
end;
答案 5 :(得分:-1)
我希望以下内容有所帮助:
CREATE TABLE TESTME ( TNAME VARCHAR2(30));
INSERT INTO TESTME VALUES('ABCDEFG');
INSERT INTO TESTME VALUES('ABChello world');
INSERT INTO TESTME VALUES('ABCDEzoo');
INSERT INTO TESTME VALUES('ABbar');
INSERT INTO TESTME VALUES('ABCDEF');
INSERT INTO TESTME VALUES('ABCDEFGHIJKLMNOP');
INSERT INTO TESTME VALUES('zzz');
INSERT INTO TESTME VALUES('qABCD');
CREATE OR REPLACE FUNCTION GET_MLENGTH( P_INPUT VARCHAR2)
RETURN NUMBER
IS
-- COMBARING STRING
C VARCHAR2(10) := ('ABCDEFGHIJ');
N NUMBER := 0;
BEGIN
FOR I IN 1..LENGTH(P_INPUT) LOOP
IF SUBSTR(P_INPUT,I,1) = SUBSTR(C,I,1) THEN
N := N + 1;
ELSE
RETURN N;
END IF;
END LOOP;
RETURN N;
END;
/
SELECT TNAME , GET_MLENGTH(TNAME) FROM TESTME ;
TNAME GET_MLENGTH(TNAME)
------------------------------ ------------------
ABCDEFG 7
ABChello world 3
ABCDEzoo 5
ABbar 2
ABCDEF 6
ABCDEFGHIJKLMNOP 10
zzz 0
qABCD 0