3

セミコロンで区切られた値ではなく、クエリを使用して別の行を取得しています。

テーブルは次のようになります。

row_id  aggregator
1       12;45
2       25

クエリを使用して、出力を次のようにします。

row_id  aggregator
1       12
1       45
2       25

次のクエリを使用しています。

SELECT
DISTINCT ROW_ID,
REGEXP_SUBSTR(AGGREGATOR,'[^;]+',1,LEVEL) as AGGREGATOR
FROM DUMMY_1
CONNECT BY REGEXP_SUBSTR(AGGREGATOR,'[^;]+',1,LEVEL) IS NOT NULL;

300 レコードでも非常に遅く、40000 レコードで作業する必要があります。

4

4 に答える 4

4

CONNECT BY正規表現は高価な関数であることが知られているため、パフォーマンスが重要な場合 (節で標準関数を使用するなど) は使用を最小限に抑えるようにしてください。

標準関数 ( INSTRSUBSTRREPLACE) を使用するとより効率的になりますが、結果のコードは読みにくく、理解しにくく、保守しにくくなります。

私は、正規表現と標準関数の両方よりもはるかに効率的な再帰 QTE を書くことに抵抗できませんでした。さらに、再帰的な QTE クエリには間違いなく洗練されたものがあります。Oracle 11.2 が必要です。

WITH rec_sql(row_id, aggregator, lvl, tail) AS (
SELECT row_id, 
       nvl(substr(aggregator, 1, instr(aggregator, ';') - 1), 
           aggregator),
       1 lvl,
       CASE WHEN instr(aggregator, ';') > 0 THEN
          substr(aggregator, instr(aggregator, ';') + 1)
       END tail
  FROM dummy_1 initialization
UNION ALL
SELECT r.row_id, 
       nvl(substr(tail, 1, instr(tail, ';') - 1), tail), 
       lvl + 1, 
       CASE WHEN instr(tail, ';') > 0 THEN
          substr(tail, instr(tail, ';') + 1)
       END tail
  FROM rec_sql r
 WHERE r.tail IS NOT NULL
)
SELECT * FROM rec_sql;

SQLFiddleで、このソリューションが非常にパフォーマンスが高く、@ABCade のソリューションと同等であることがわかります。(テストケースを提供してくれた ABCade に感謝します)。

于 2013-02-27T09:55:54.877 に答える
4

パイプライン化されたテーブルの方が高速な場合があります。これを試してください。

create or replace type t is object(word varchar2(100), pk number);
/
create or replace type t_tab as table of t;
/

create or replace function split_string(del in varchar2) return t_tab
  pipelined is

  word    varchar2(4000);
  str_t   varchar2(4000) ;
  v_del_i number;
  iid     number;

  cursor c is
    select * from DUMMY_1; 

begin

  for r in c loop
    str_t := r.aggregator;
    iid   := r.row_id;

    while str_t is not null loop

      v_del_i := instr(str_t, del, 1, 1);

      if v_del_i = 0 then
        word  := str_t;
        str_t := '';
      else
        word  := substr(str_t, 1, v_del_i - 1);
        str_t := substr(str_t, v_del_i + 1);
      end if;

      pipe row(t(word, iid));

    end loop;

  end loop;

  return;
end split_string;

ここにsqlfiddleのデモがあります

そして、アグリゲーターごとに 3 つの val を含む 22 行の別のデモがあります。最初のクエリと 2 番目のクエリの違いを確認してください。

于 2013-02-27T07:30:52.160 に答える
-1

DISTINCT が問題になる可能性があると思います。その上、なぜ CONNECT BY REGEXP_SUBSTR(AGGREGATOR,'[^;]+',1,LEVEL) IS NOT NULL が必要なのかわかりません。select and connect by で正規表現を使用しています。connect by の代わりに where AGREGATOR IS NOT NULL を使用できますか? distinct を取り除き、クエリを修正する方法を見つけてください。個別の代わりに EXISTS を使用できます... さらに役立つには、テーブルとデータが必要です。

SELECT * FROM
(
 SELECT REGEXP_SUBSTR(AGGREGATOR ,'[^;]+',1,LEVEL) as AGGREGATOR                      
   FROM your_table
)
WHERE AGGREGATOR IS NOT NULL
/
于 2013-02-27T20:35:07.740 に答える