如何在SQL中对字符串进行标记后反转字符串

时间:2010-10-13 04:29:51

标签: sql oracle

我需要将字符串标记化并在SQL中将其反转。例如,如果字符串是'L3:L2:L1:L0',我需要将其反转为'L0:L1:L2:L3'。可以使用分隔符':'进行标记化,然后将其反转。请在SQL中建议一个函数。

提前致谢, 格塔

7 个答案:

答案 0 :(得分:4)

如果可能,最好的解决方案是更改数据,以便将每个值存储在不同的行中。

如果这不起作用,您可以创建PL / SQL函数。

如果您想要一个纯粹的SQL解决方案,通常您必须将每个值拆分为多个行(​​与对象表交叉连接,或按级别连接< =最大项目数),然后重新聚合数据使用十几种不同的方法之一(listagg,collect,stragg,xml,sys_connect_by_path等)

另一种SQL专用方法是使用正则表达式。这可能是最快的,但它最多只能用于9个项目,因为Oracle仅支持9个反向引用:

--Get everything except the extra ':' at the end.
select substr(string, 1, length(string) - 1) string from
(
  select regexp_replace(
    --Add a delimter to the end so all items are the same
    'L3:L2:L1:L0'||':'
    --Non-greedy search for anything up to a : (I bet there's a better way to do this)
    ,'(.*?:)?(.*?:)?(.*?:)?(.*?:)?(.*?:)?(.*?:)?(.*?:)?(.*?:)?(.*?:)?(.*?:)?'
    --Reverse the back-references
    ,'\9\8\7\6\5\4\3\2\1') string
  from dual
);

答案 1 :(得分:1)

类似的东西:

SELECT
  REGEXP_REPLACE('L1:L2:L3',
                 '([[:alnum:]]{1,}):([[:alnum:]]{1,}):([[:alnum:]]{1,})',
                 '\3 \2 \1') "REGEXP_REPLACE"
from dual

但您可能需要详细说明构成令牌的内容。

答案 2 :(得分:1)

以下是使用PL / SQL流水线函数拆分元素的解决方案:

create type t_str_array as table of varchar2(4000);

create or replace function split_str (p_str in varchar2,
                                      p_separator in varchar2 := ':') return t_str_array pipelined
as
  l_str varchar2(32000) := p_str || p_separator;
  l_pos pls_integer;
begin

  loop
    l_pos := instr(l_str, p_separator);
    exit when (nvl(l_pos,0) = 0);
    pipe row (ltrim(rtrim(substr(l_str,1,l_pos-1))));
    l_str := substr(l_str, l_pos+1);
  end loop;

  return;

end split_str;

然后你将使用普通的SQL来排序元素:

select * from table(split_str('L3:L2:L1:L0')) order by column_value

答案 3 :(得分:1)

declare
  s varchar2(1000) := 'L 1 0:L9:L8:L7:L6:L5:L4:L3:L2:L1:L0';
  j number := length(s);
begin
  for i in reverse 1..length(s) loop
    if substr(s, i, 1) = ':' then
      dbms_output.put(substr(s, i + 1, j - i) || ':');
      j := i - 1;
    end if;
  end loop;    
  dbms_output.put_line(substr(s, 1, j));
end;

答案 4 :(得分:0)

将CSV字符串中的元素转换为记录,从而抑制所有NULL:

SELECT  REGEXP_SUBSTR( :csv,'[^,]+', 1, LEVEL )  AS element
FROM    dual
CONNECT BY REGEXP_SUBSTR( :csv, '[^,]+', 1, LEVEL ) IS NOT NULL ;

将CSV字符串中的元素转换为记录,保留NULL(但不是顺序):

SELECT   REGEXP_SUBSTR( :csv,'[^,]+', 1, LEVEL )  AS element
FROM    dual
CONNECT BY LEVEL <= LENGTH( :csv ) - LENGTH( REPLACE( :CSV, ',' ) ) + 1 ;

答案 5 :(得分:0)

改进Kevan的答案,这就是我的尝试:

select listagg(TOKEN, ':') WITHIN GROUP (ORDER BY TOKEN_LEVEL DESC)
from
(SELECT  REGEXP_SUBSTR( myStr,'[^:]+', 1, LEVEL )  AS TOKEN, LEVEL TOKEN_LEVEL
FROM    dual
CONNECT BY REGEXP_SUBSTR( myStr, '[^:]+', 1, LEVEL ) IS NOT NULL);

答案 6 :(得分:-1)

由于您使用Oracle,因此很容易生成传递字符串的java存储过程,然后

  1. 将sting分成数组
  2. 向后循环数组并连接生成的字符串
  3. 返回结果字符串
  4. 这将是一个小的java代码,并不比pl / sql慢。但是如果你想使用pl / sql,你也可以使用DBMS_UTILITY.table_to_comma / .comma_to_table。但是,正如函数名称假设 - &gt;你必须使用“,”作为代币。