Oracle函数以无序方式比较字符串
Posted
技术标签:
【中文标题】Oracle函数以无序方式比较字符串【英文标题】:Oracle function to compare strings in a not ordered way 【发布时间】:2018-03-08 11:50:51 【问题描述】:我需要一个函数来比较两个字符串,而不考虑 oracle 中的顺序。 即“asd”和“sad”应该被认为是平等的。 有没有类似的功能?还是我需要自己写函数?
【问题讨论】:
【参考方案1】:这可以通过一个简单的 java 函数来按字母顺序对字符串的字符进行排序:
CREATE AND COMPILE JAVA SOURCE NAMED SORTSTRING AS
public class SortString
public static String sort( final String value )
final char[] chars = value.toCharArray();
java.util.Arrays.sort( chars );
return new String( chars );
;
/
然后您可以创建一个 PL/SQL 函数来调用:
CREATE FUNCTION SORTSTRING( in_value IN VARCHAR2 ) RETURN VARCHAR2
AS LANGUAGE JAVA NAME 'SortString.sort( java.lang.String ) return java.lang.String';
/
然后你可以对排序后的字符串做一个简单的比较:
SELECT CASE
WHEN SORTSTRING( 'ads' ) = SORTSTRING( 'das' )
THEN 'Equal'
ELSE 'Not Equal'
END
FROM DUAL;
【讨论】:
不错的解决方案。对于高效版本,可以在排序之前添加长度相等性测试。【参考方案2】:不完全是一门火箭科学,但有效(有点,至少在简单的情况下)。
它有什么作用?按字母顺序对每个字符串中的字母进行排序并进行比较。
SQL> with test (col1, col2) as
2 (select 'asd', 'sad' from dual),
3 inter as
4 (select
5 col1, regexp_substr(col1, '[^.]', 1, level) c1,
6 col2, regexp_substr(col2, '[^.]', 1, level) c2
7 from test
8 connect by level <= greatest(length(col1), length(col2))
9 ),
10 agg as
11 (select listagg(c1, '') within group (order by c1) col1_new,
12 listagg(c2, '') within group (order by c2) col2_new
13 from inter
14 )
15 select case when col1_new = col2_new then 'Equal'
16 else 'Different'
17 end result
18 From agg;
RESULT
---------
Equal
SQL> with test (col1, col2) as
2 (select 'asd', 'sadx' from dual),
<snip>
RESULT
---------
Different
SQL>
【讨论】:
好的,它可以工作,但我需要迭代地传递值。我能怎么做?可以添加到select子句中(或where)? 为此+1,太棒了。我有一个小建议,如果在第一个 SQL 中添加了 lower 函数,那么无论大小写如何,都会进行比较。例如。lower('asD'), lower('sad')
Manuel:您可以将其重写为接受两个 IN 参数并返回 VARCHAR2(如我的示例)或布尔值的函数(请注意,您不能在纯 SQL 中使用它) . @user75ponic:好吧,问题是 asD 是否等于 AsD;曼努埃尔应该知道:)【参考方案3】:
另一个解决方案,使用SUBSTR
函数和CONNECT BY
循环。
SQL Fiddle
查询 1:
WITH a
AS (SELECT ROWNUM rn, a1.*
FROM ( SELECT SUBSTR ('2asd', LEVEL, 1) s1
FROM DUAL
CONNECT BY LEVEL <= LENGTH ('2asd')
ORDER BY s1) a1),
b
AS (SELECT ROWNUM rn, a2.*
FROM ( SELECT SUBSTR ('asd2', LEVEL, 1) s2
FROM DUAL
CONNECT BY LEVEL <= LENGTH ('asd2')
ORDER BY s2) a2)
SELECT CASE COUNT (NULLIF (s1, s2)) WHEN 0 THEN 'EQUAL' ELSE 'NOT EQUAL' END
res
FROM a INNER JOIN b ON a.rn = b.rn
Results:
| RES |
|-------|
| EQUAL |
编辑:一个 PL/SQL Sort
函数用于字母数字字符串。
CREATE OR replace FUNCTION fn_sort(str VARCHAR2)
RETURN VARCHAR2 DETERMINISTIC AS
v_s VARCHAR2(4000);
BEGIN
SELECT LISTAGG(substr(str, LEVEL, 1), '')
within GROUP ( ORDER BY substr(str, LEVEL, 1) )
INTO v_s
FROM dual
CONNECT BY LEVEL < = length(str);
RETURN v_s;
END;
/
select fn_sort('shSdf3213Js') as s
from dual;
| S |
|-------------|
| 1233JSdfhss |
【讨论】:
【参考方案4】:如果您想创建自己的排序功能,可以使用以下代码,
CREATE OR REPLACE FUNCTION sort_text (p_text_to_sort VARCHAR2) RETURN VARCHAR2
IS
v_sorted_text VARCHAR2(1000);
BEGIN
v_sorted_text := p_text_to_sort;
FOR i IN 1..LENGTH(p_text_to_sort)
LOOP
FOR j IN 1..LENGTH(p_text_to_sort)
LOOP
IF SUBSTR(v_sorted_text, j, 1)||'' > SUBSTR(v_sorted_text, j+1, 1)||'' THEN
v_sorted_text := SUBSTR(v_sorted_text, 1, j-1)||
SUBSTR(v_sorted_text, j+1, 1)||
SUBSTR(v_sorted_text, j, 1)||
SUBSTR(v_sorted_text, j+2);
END IF;
END LOOP;
END LOOP;
RETURN v_sorted_text;
END;
/
SELECT SORT_TEXT('zlkdsadfsdfasdf') SORTED_TEXT
FROM dual;
SORTED_TEXT
---------------
aaddddfffklsssz
【讨论】:
以上是关于Oracle函数以无序方式比较字符串的主要内容,如果未能解决你的问题,请参考以下文章
Oracle:比较两个不同表中没有主键的字符串列以查找匹配/不匹配的字符串