2012-02-07 3 views
1

4文字以下の長い文字列(たとえば、??????01 '、0??1など)を格納する列があります。 0??1のような各文字列に対して、0001から0991の値を別のテーブルに挿入する必要があります。文字列??01の場合、値は0001〜9901になります。文字列????の値は0000〜9999のようになります。文字列関数を使用してPL/SQLでワイルドカードを使用して文字列を拡張するには

PL/SQLと文字列関数を使用してこれをどのように達成できますか?

EDIT

現在のコードは次のとおりです。

declare 

    v_rule varchar2(50) := '????52132'; 
    v_cc varchar2(50); 
    v_nat varchar2(50); 
    v_wild number; 
    n number; 

begin 

    v_cc := substr(v_rule,1,4); 
    v_nat := substr(v_rule,5); 

    dbms_output.put_line (v_cc || ' '|| v_nat); 

    if instr(v_cc, '????') <> 0 then 
    v_wild := 4; 
    end if; 

    n := power(10,v_wild); 

    for i in 0 .. n - 1 loop 
    dbms_output.put_line(substr(lpad(to_char(i),v_wild,'0'),0,4)); 
    end loop; 

end; 
/

答えて

2

次のようなヘルプがありますか?

BEGIN 
    FOR source_row IN (SELECT rule FROM some_table) 
    LOOP 
    INSERT INTO some_other_table (rule_match) 
     WITH numbers AS (SELECT LPAD(LEVEL - 1, 4, '0') AS num FROM DUAL CONNECT BY LEVEL <= 10000) 
     SELECT num FROM numbers WHERE num LIKE REPLACE(source_row.rule, '?', '_'); 
    END LOOP; 
END; 
/

これは、あなたがテキストのような??010??1????を含む列rulesome_tableと呼ばれるテーブルを、前提としています。これらのワイルドカードパターンと一致する0000〜9999の数字がすべてsome_other_tableに挿入されます。

サブクエリ

SELECT LPAD(LEVEL - 1, 4, '0') AS num FROM DUAL CONNECT BY LEVEL <= 10000) 

9999範囲0000内のすべての数値を生成します。 LIKEを使用して、このパターンに一致する数字のリストから除外します。 _は、LIKEを使用する場合は1文字のワイルドカードであり、?ではないことに注意してください。私は、次のデータでこれを設定

:PL/SQLブロックの上に実行した後

CREATE TABLE some_table (rule VARCHAR2(4)); 

INSERT INTO some_table (rule) VALUES ('??01'); 
INSERT INTO some_table (rule) VALUES ('0??1'); 
INSERT INTO some_table (rule) VALUES ('????'); 
COMMIT; 

CREATE TABLE some_other_table (rule_match VARCHAR2(4)); 

、テーブルsome_other_tableは、それに与えられたパターンの3つのすべてにマッチした全ての数字を10200行を持っていました。

+0

恐ろしい!それは私の問題に完全に合った。返信ありがとうございました。そうしないと、instringとsubstringを扱うのに苦労したでしょう:) – Arcs

+0

もう一つ質問したいことがあります。 'some_table'には1000万レコードあります。各レコードが拡張されると仮定すると、私はsome_other_tableに挿入する膨大な数のレコードを持つでしょう。私はそのようなプログラムのパフォーマンスが心配です。これを処理する効率的な方法はありますか? – Arcs

+0

@Arcs:このアプローチのパフォーマンスが懸念される場合は、1000個のレコードでテストし、10000または100000レコード、またはそれ以上でテストしてください。私はこの機能について何らかの性能テストを行っていないので、パフォーマンスがどれくらいうまくいくかはわかりません。 'some_table'に1,000万行があり、それぞれが100行を生成できる場合は、10億行があります。どのように挿入するにしても、10億行を挿入するのに常に時間がかかります。 –

2

は、%に*を置き換えますか?その結果の値とともにLIKE句を使用します。

+0

どのように役立つでしょうか?説明してください。ために '????'私はこのような何かをしています:宣言 v_rule varchar2(50):= '???? 52132'; v_cc varchar2(50); v_nat varchar2(50); v_wild number; n番; begin v_cc:= substr(v_rule、1,4); v_nat:= substr(v_rule、5); dbms_output.put_line(v_cc || '' || v_nat); if instr(v_cc、 '????')<> 0 次にv_wild:= 4; end if; n:= power(10、v_wild); for i in 0..n-1 ループ dbms_output.put_line(substr(lpad(to_char(i)、v_wild、 '0')、0,4)); エンドループ。 end; – Arcs

1

アンダースコアが%と同じであることを意味する少し知られている事実を使っている@Oleg Dokの答えを拡張するには、一文字とPL \ SQLを使ってください。これは最も単純な方法です。 connect byの使い方の良い説明はhereです。

declare 

    cursor c_min_max(Crule varchar2) is 
    select to_number(min(numb)) as min_n, to_number(max(numb)) as max_n 
     from (select '0000' as numb 
       from dual 
       union 
      select lpad(level, 4, '0') as numb 
       from dual 
      connect by level <= 9999) 
    where to_char(numb) like replace(Crule, '?', '_'); 

    t_mm c_min_max%rowtype; 

    l_rule varchar2(4) := '?091'; 

begin 

    open c_min_max(l_rule); 

    fetch c_min_max 
    into t_mm; 

    close c_min_max; 

    for i in t_mm.min_n .. t_mm.max_n loop 

    dbms_output.put_line(lpad(i, 4, '0')); 

    end loop; 

end; 
/
関連する問題