我需要将字符串标记化并在SQL中将其反转。例如,如果字符串是'L3:L2:L1:L0',我需要将其反转为'L0:L1:L2:L3'。可以使用分隔符':'进行标记化,然后将其反转。请在SQL中建议一个函数。
提前致谢, 格塔
答案 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存储过程,然后
这将是一个小的java代码,并不比pl / sql慢。但是如果你想使用pl / sql,你也可以使用DBMS_UTILITY.table_to_comma / .comma_to_table。但是,正如函数名称假设 - &gt;你必须使用“,”作为代币。