如何在 Oracle SQL 中 arrange/sort 字符串 - 11g

How to arrange/sort string in Oracle SQL - 11g

我有一个字符串 "ADBDkK",我需要将其排序为 "ABDDKk",例如 java 中的 Arrays.sort()。我知道可以通过使用 PL/SQL 来完成,但我需要在 Oracle SQL 语句中使用它。

输入:

ADBDkK
ZXYABC

输出:

ABDDKk
ABCXYZ

SQL Fiddle

Oracle 11g R2 模式设置:

CREATE TABLE test ( value ) AS
SELECT 'ADBDkK' FROM DUAL UNION ALL
SELECT 'ZXYABC' FROM DUAL;

查询 1:

WITH chars ( id, value, ch, lvl ) AS (
  SELECT ROWNUM, value, SUBSTR( value, 1, 1 ), 1
  FROM   test
UNION ALL
  SELECT id, value, SUBSTR( value, lvl+1, 1 ), lvl+1
  FROM   chars
  WHERE  lvl < LENGTH( value )
)
SELECT LISTAGG( ch ) WITHIN GROUP ( ORDER BY ch ) AS value
FROM   chars
GROUP BY id
ORDER BY id

Results:

|  VALUE |
|--------|
| ABDDKk |
| ABCXYZ |

查询 2:

SELECT LISTAGG( COLUMN_VALUE )
         WITHIN GROUP ( ORDER BY COLUMN_VALUE ) AS value
FROM   (
  SELECT value,
         ROWNUM AS id
  FROM test
) t
CROSS JOIN
TABLE(
  CAST(
    MULTISET(
      SELECT SUBSTR( t.value, LEVEL, 1 )
      FROM   DUAL
      CONNECT BY LEVEL <= LENGTH( t.value )
    )
    AS SYS.ODCIVARCHAR2LIST
  )
) c
GROUP BY t.id
ORDER BY t.id

Results:

|  VALUE |
|--------|
| ABDDKk |
| ABCXYZ |

对于单个字符串:

select listagg(regexp_substr('ADBDkK', '\w', 1 ,level),'') 
   within group (order by 1) from dual
connect by regexp_substr('ADBDkK', '\w', 1 ,level) is not null;

使用 function 的方式略有不同:

CREATE OR REPLACE FUNCTION sort_string(my_string IN VARCHAR2)
  RETURN VARCHAR2 IS
  ret_string VARCHAR2(4000);
BEGIN
  SELECT LISTAGG(regexp_substr(my_string, '\w', 1, level), '') WITHIN
   GROUP(
   ORDER BY 1)
    INTO ret_string
    FROM dual
  CONNECT BY regexp_substr(my_string, '\w', 1, level) IS NOT NULL;
  RETURN ret_string;
END;

然后从sqlplus:

SQL> select sort_string('ADBDkK') as RESULT from dual;

RESULT
------
ABDDKk

SQL> select sort_string('ZXYABC') as RESULT from dual;

RESULT
------
ABCXYZ
with t1 as (
select 'London Singapur' tmp  from dual union all
select 'Singapur China'  tmp  from dual union all
select 'USA JAPAN '      tmp  from dual union all
select 'JAPAN USA'       tmp  from dual union all 
select 'Singapur London' tmp  from dual 
),
dst as ( select ROWNUM rwn,tmp,REGEXP_COUNT(tmp,'[^[:space:]]+') cnt_array  from t1 ),

rc(id, cnt_id, tmp, CNT_ARRAY, SL) AS (
   SELECT rwn id,1 cnt_id,tmp, CNT_ARRAY, regexp_substr(tmp,'[^[:space:]]+',1,1) sl FROM   dst   
      UNION ALL
    SELECT rc.id, rc.cnt_id+1 cnt_id, rc.tmp, rc.CNT_ARRAY, regexp_substr(rc.tmp,'[^[:space:]]+',1,rc.cnt_id+1) sl
    FROM   dst tr, rc 
    WHERE  tr.rwn = rc.id and rc.cnt_id+1<=tr.CNT_ARRAY
),

srt as (select  rc.*,row_number() over (partition by id order by id) nb,
                listagg(sl,' ') WITHIN GROUP (ORDER BY sl) over(partition by id) fiel_srt
        from rc)

select * from srt where nb=1