2014-01-07 4 views
5

文または文字列内の単語の位置を逆にする必要があります。 SQLを使用してWordでWordを逆順

For example : "Hello World! I Love StackOverflow", to be displayed as "StackOverflow Love I World! Hello". 

はそれが SQLで行うことができますか?単語の長さは、テーブルの列の最大長のサポートである VARCHAR2(4000)を超えないようにしてください。

私だけ

+0

あなたがPL/SQL関数を記述し、直接SQLでそれを使用することができます。 –

+0

スペースの次のインスタンスを検索し、関数を使って文字列操作を行うのは比較的簡単です。何を試しましたか? –

+2

面白い宿題の問題では、インストラクターはおそらくコレクションやカーソルの使い方を教えたり、あなたの巧みさを見たりしようとしていました。私はSOからのコピー/ペーストも賢明だと思う;) – tbone

答えて

5

機能作成した文字列を反転させるためのソリューション(逆の順序で文字)を得た:

REGEXP_SUBSTR('Your text here','[^ ]+', 1, ?)を区切り文字としてスペースを使用してテキストから単語を抽出します。 Ttは元のString自体をException!に返します。

CREATE OR REPLACE FUNCTION reverse_words (v_STRING IN VARCHAR2) 
RETURN VARCHAR2 
IS 
    L_TEMP_TEXT VARCHAR2(4000); 
    L_FINAL_TEXT VARCHAR2(4000); 
    V_LOOPCOUNT NUMBER :=0; 
    T_WORD VARCHAR2(4000); 
BEGIN 
     L_TEMP_TEXT := regexp_replace(V_STRING,'[[:space:]]+',' '); -- Replace multiple spaces as single 
     LOOP 
     v_LOOPCOUNT := v_LOOPCOUNT+1; 
     T_WORD  := REGEXP_SUBSTR(L_TEMP_TEXT,'[^ ]+', 1, V_LOOPCOUNT); 
     L_final_TEXT := T_WORD||' '||L_final_TEXT; 
     EXIT WHEN T_WORD IS NULL; 
     END LOOP; 
    RETURN(TRIM(L_final_TEXT)); 
EXCEPTION 
    WHEN OTHERS THEN 
     DBMS_OUTPUT.PUT_LINE(sqlerrm||chr(10)||dbms_utility.format_error_backtrace); 
     RETURN V_STRING; 
END reverse_words; 
/

サンプル結果:

独自の関数を定義しないようにするXMLベースのバージョンreverse_words(yourcolumn) from your_table

SQL> select reverse_words('Hello World! I Love StackOverflow') "Reversed" from dual; 

Reversed 
-------------------------------------------------------------------------------- 
StackOverflow Love I World! Hello 
8

を呼び出すことができます。 listagg()ため11gの必要:

select listagg(word, ' ') within group (order by rn desc) as reversed 
from (
    select word, rownum as rn 
    from xmltable('for $i in ora:tokenize($STR, " ") return $i' 
    passing 'Hello World! I Love StackOverflow' as str 
    columns word varchar2(4000) path '.' 
) 
); 

REVERSED        
---------------------------------------- 
StackOverflow Love I World! Hello   

XMLTable()をtokenisingを行い、そして行番号を割り当て:

select rownum as rn, word 
from xmltable('for $i in ora:tokenize($STR, " ") return $i' 
    passing 'Hello World! I Love StackOverflow' as str 
    columns word varchar2(4000) path '.' 
); 

     RN WORD    
---------- -------------------- 
     1 Hello     
     2 World!    
     3 I      
     4 Love     
     5 StackOverflow   

listagg()次に片はバック一緒に逆の順序です。ここで

+0

ありがとうアレックス!私はxmltableを聞いたことがないと私はあなたのアプローチを得る。申し訳ありません初心者です!今のところ私はより良いものに合っているので、カスタム関数を使います! – ahairshi

2

あなたが行く:

WITH sel_string AS 
     (SELECT 'Hello World! I Love StackOverflow' AS fullstring FROM DUAL) 
    SELECT SUBSTR(fullstring, beg + 1, end_p - beg - 1) AS token 
    FROM (SELECT beg, LEAD(beg) OVER (ORDER BY beg) AS end_p, fullstring 
      FROM (SELECT beg, fullstring 
        FROM (SELECT LEVEL beg, fullstring 
          FROM sel_string 
          CONNECT BY LEVEL <= LENGTH(fullstring)) 
        WHERE INSTR(' ', SUBSTR(fullstring, beg, 1)) > 0 
        UNION ALL 
        SELECT 0, fullstring FROM sel_string 
        UNION ALL 
        SELECT LENGTH(fullstring) + 1, fullstring FROM sel_string)) 
    WHERE end_p IS NOT NULL AND 
      end_p > beg + 1 
    ORDER BY ROWNUM DESC; 

すべて1つのSQLクエリで。私はこのクエリのクレジットを請求することができますが、私はそれを何年も前にネットで見つけて以来それを使用しています。

共有して楽しんでください。

+1

私はLEADとLAGを学んだ..ありがとう! +1 :) –

2

もう一つの解決策

WITH str_tab(str1, rn) AS 
(SELECT regexp_substr(str, '[^\[:space:]]+', 1, LEVEL), 
     LEVEL 
    FROM (SELECT 'Hello World! I Love StackOverflow' str 
      FROM dual) tab 
CONNECT BY LEVEL <= LENGTH(str) - LENGTH(REPLACE(str, ' ')) + 1) 
SELECT listagg(str1, ' ') WITHIN GROUP (ORDER BY rn DESC) AS new_text 
    FROM str_tab; 
関連する問題