0

チルダで区切られたデータを含むテーブルに列があります。

このチルダで区切られたデータの少なくとも1つのトークンが有効な値の事前定義されたリストにないテーブル内のすべてのレコードを返す必要があるSINGLE sqlクエリを(パフォーマンス上の理由から)起動したいと思います。

私はさまざまなフォーラムで解決策を探していましたが、それらのほとんどは、レコードを分割したり、いくつかの正規表現を使用したりするためのユーザー定義の分割関数があると言っていましたが、単一のクエリでは機能しません。

誰かがそれを手伝ってくれますか?

4

1 に答える 1

3

正規表現を使用して、単一の SQL ステートメントでデータを解析できます。次に、任意のフィルターを適用して、事前定義されたリストにない値のセットを見つけることができます

SQL> ed
Wrote file afiedt.buf

  1  with test as
  2    (select 'ABC~DEF~GHI~JKL~MNO' str from dual)
  3  select regexp_substr (str, '[^~]+', 1, rownum) split
  4    from test
  5* connect by level <= length (regexp_replace (str, '[^~]+'))  + 1
SQL> /

SPLIT
----------------------------------------------------------------------------
ABC
DEF
GHI
JKL
MNO

このようなこともできます

SQL> ed
Wrote file afiedt.buf

  1  with test as
  2    (select 1 id, 'ABC~DEF~GHI~JKL~MNO' str from dual union all
  3     select 2, 'XY~PDQ~435' from dual union all
  4     select 3, 'This~is~a~test' from dual)
  5  select id, regexp_substr (str, '[^~]+', 1, e.lvl) split
  6    from test,
  7         (select level lvl
  8            from dual
  9         connect by level <= (select max(regexp_count(str,'~')) + 1
 10                                from test)) e
 11*  where regexp_substr (str, '[^~]+', 1, e.lvl) is not null
SQL> /

        ID SPLIT
---------- --------------------
         1 ABC
         2 XY
         3 This
         1 DEF
         2 PDQ
         3 is
         1 GHI
         2 435
         3 a
         1 JKL
         3 test
         1 MNO

12 rows selected.

もちろん、これは特に効率的ではありません。さまざまな部分文字列に効果的にインデックスを付けることができないため、テーブルを完全にスキャンする必要があります。行を生成する方法は他にもあります。Rob van Wijk のブログで、さまざまな間隔ベースの行生成手法のパフォーマンスを比較した記事があります。

通常、データ モデルを修正する方がはるかに優れています。区切りデータを列に格納することは、基本的な正規化の原則に違反します。データを別の列 (おそらく、既存のテーブルと 1 対多の関係にある別のテーブル) に格納した場合、データにインデックスを付けて、事前定義された有効なリストにマップする外部キー制約を作成できます。これにより、無効なデータが最初から挿入されるのを防ぐことができます (または、少なくとも将来的に新しい無効な行が追加されるのを防ぐことができます)。

于 2012-06-26T19:50:15.807 に答える