Oracle函数返回字符串

时间:2015-07-31 22:47:07

标签: string oracle performance plsql

我有一个有趣的问题,我想知道oracle是否有内置函数来执行此操作,或者我需要找到一种快速方法在plsql中执行此操作。

取2个字符串:

  s1 = 'abc def hijk'
  s2 = 'abc def iosk'

该函数需要返回abc def,因为字符串在此之前完全相同。

另一个例子:

  s1 = 'abc def hijk www'
  s2 = 'abc def iosk www'

该函数需要返回abc def

我能想到的唯一方法就是循环遍历string1并将每个字符与substr()再次比较为字符串2的substr。

只是想知道Oracle是否内置了一些东西。表现非常重要。

5 个答案:

答案 0 :(得分:1)

我怀疑有一些内置的SQL函数,但只能使用正则表达式在SQL中完成:

with cte1 as  (
    select 1 id, 'abc def hijk www' str from dual
    union all
    select 2 id, 'abc def iosk www' str from dual
), cte2 as (
    SELECT distinct id, trim(regexp_substr(str, '[^ ]+', 1, level)) str
    FROM cte1 t
    CONNECT BY instr(str, ' ', 1, level - 1) > 0
)
select distinct t1.str
from cte2 t1
join cte2 t2 on (t1.str = t2.str and t1.id != t2.id)

我没有做过任何性能测试,但我的经验告诉我,这很可能比任何pl / sql解决方案都快,因为你完全避免了上下文切换。

答案 1 :(得分:1)

重新阅读你的问题之后,这就是你真正想要的:

with cte1 as  (
    select 1 id, 'abc def hijk www' str from dual
    union all
    select 2 id, 'abc def iosk www' str from dual
), num_gen as (
    -- a number generator up to the minimum length of the strings
    SELECT level num
    FROM dual t
    CONNECT BY level <= (select min(length(str)) from cte1)
), cte2 as (
    -- build substrings of increasing length
    select id, num_gen.num, substr(cte1.str, 1, num_gen.num) sub
    from cte1
    cross join num_gen
), cte3 as (
    -- self join to check if the substrings are equal
    select x1.num, x1.sub sub1, x2.sub sub2
    from cte2 x1
    join cte2 x2 on (x1.num = x2.num and x1.id != x2.id)
), cte4 as (
    -- select maximum string length
    select max(num) max_num
    from cte3
    where sub1 = sub2
)
    -- finally, get the substring with the max length
    select cte3.sub1
    from cte3
    join cte4 on (cte4.max_num = cte3.num)
    where rownum = 1

基本上,这就是你在pl / sql中要做的事情:构建增加长度的子串,并在它们不再匹配的位置停止。

答案 2 :(得分:1)

您应该检查软件包UTL_MATCH以获得类似的功能,但是您必须自己编写自己的函数。

公共子字符串长度的二进制搜索为长字符串提供了良好的性能。

 create or replace function ident_pfx(str1 varchar2, str2 varchar2) return varchar2
 as
  len_beg PLS_INTEGER;
  len_end PLS_INTEGER;
  len_mid PLS_INTEGER;
  len_result PLS_INTEGER; 
 begin
    if str1 is null or str2 is null then return null; end if;
  -- 
    len_result := 0;
    len_beg := 0;
    len_end := least(length(str1),length(str2));

     LOOP  
     BEGIN
       -- use binary search for the common substring length
       len_mid := ceil((len_beg + len_end) / 2);

       IF (substr(str1,1,len_mid) = substr(str2,1,len_mid))
       THEN
          len_beg := len_mid; len_result := len_mid;
       ELSE
          len_end := len_mid;
       END IF;
      END;

      IF (len_end - len_beg) <= 1 THEN
        -- check last character
        IF (substr(str1,1,len_end) = substr(str2,1,len_end))
        THEN
         len_result := len_end;
        END IF;       
        EXIT ; 
      END IF;       
     END LOOP;
  return substr(str1,1,len_result);
 end;
 /


 select ident_pfx('abc def hijk www','abc def iosk www') ident_pfx from dual;

 abc def 

答案 3 :(得分:0)

另一种可能的解决方案是使用XOR。 如果将两个字符串放在一起,结果应该有两个字符串匹配的NUL字节。

XOR不是本机运算符,但我很确定其中一个库中支持它。

答案 4 :(得分:0)

如果&#34;表现非常重要&#34;,你应该避免&#34;循环&#34;在子串上。

这是使用XOR的替代方案(由@EvilTeach提出)。

 with string_transform as  (
     select 'abc def hijk www' str1, 'abc def iosk www' str2 from dual
 ),
 str as (
 select 
  str1, str2,
  -- add suffix to handle nulls and identical strings
  -- calculate XOR
  utl_raw.bit_xor(utl_raw.cast_to_raw(str1||'X'),utl_raw.cast_to_raw(str2||'Y')) str1_xor_str2
 from string_transform 
 ), str2 as (
 select 
   str1, str2,
   str1_xor_str2,
   -- replace all non-identical characters (not 00) with 2D = '-'
   utl_raw.translate(str1_xor_str2,
                     utl_raw.translate(str1_xor_str2,'00','01'),
                     utl_raw.copies('2D',length(str1_xor_str2))) xor1
 from str
 ), str3 as (
 select 
   str1, str2,
   -- replace all identical characters (00) with 2B (= '+') and cast back to string
   utl_raw.cast_to_varchar2(utl_raw.translate(xor1,'00','2B')) diff
   -- diff = ++++++++---+++++ (+ means identical position; - difference)
 from str2
 )
 select str1, str2, 
  -- remove the appended suffix character
  substr(diff,1,length(diff)-1) diff,
  -- calculate the length of the identical prefix
  instr(diff,'-')-1 same_prf_length
 from str3 
 ;

基本上两个字符串首先转换为RAW格式。 XOR将相同的字节(字符)设置为00.使用转换时,相同的字节将转换为&#39; +&#39;,所有其他字节转换为&#39; - &#39;。 相同的前缀长度是第一个&#39; - &#39;的位置。在字符串减1。 从技术上讲,一个(不同的)sufix字符被添加到两个字符串中以处理NULL和相同的字符串。

请注意,如果字符串长于2000,则必须添加一些额外的处理 由于UTL_RAW.CAST_TO_VARCHAR2的限制。