web-dev-qa-db-ja.com

DB2 SQLでREGEXPのような動作をエミュレートする

同じことを stackoverflow に投稿しました(削除する必要がある場合はお知らせください)。

私はDB2データベースで作業しており、確認できる限りregexpはサポートされていません(追加のライブラリなし)。

したがって、この記事で説明されているものと似たものを実装することはできません " SQLに正規表現マッチングの力をもたらす "

SQLステートメントを使用して、このような正規表現を「エミュレート」できるかどうか知っていますか?

^ a [aofdmep] {1} [a-z] {1} [a-z0-9] {4} [sidbfkfpo] {1}

編集

上記の仮説では、私のケースa[〜#〜] where [〜#〜]が述語のように受け入れられることがわかりました:

USER_NAMEが「a_______」ではない場所

しかし、これは安全ではなく、一致できる固定文字がない他の場合は対象外です。

7
tmow

まず、{1}sは冗長であるため、実際には次のようになります。

^[aofdmep][a-z][a-z0-9]{4}a[sidbfkfpo]

これは実際にはかなり単純なパターンです...文字列の最初の8文字が何であるかを調べているだけで、常に固定長の文字列なので、すべての順列のテーブルを作成してから、次のように実行できます。

WHERE SUBSTR(string_to_match, 1, 8) IN (
  SELECT valid_prefixes FROM table_of_things_to_match
)

残念ながら、それは7 * 26 * 36 ^ 4 * 9 ... 27.5億の可能な組み合わせですが、それでも固定文字列なので、次のようにすることができます。

WHERE SUBSTR(string_to_match, 1, 1) IN ('a','o','f','d','m','e','p')
  AND SUBSTR(string_to_match, 2, 1) IN ('a','b','c','d' ... 'z')
  AND SUBSTR(string_to_match, 3, 1) IN ('a','b','c','d' ... 'z','0','1' ... '9')
  AND SUBSTR(string_to_match, 4, 1) IN ('a','b','c','d' ... 'z','0','1' ... '9')
  AND SUBSTR(string_to_match, 5, 1) IN ('a','b','c','d' ... 'z','0','1' ... '9')
  AND SUBSTR(string_to_match, 6, 1) IN ('a','b','c','d' ... 'z','0','1' ... '9')
  AND SUBSTR(string_to_match, 7, 1) = 'a'
  AND SUBSTR(string_to_match, 8, 1) IN ('s','i','d','b','f','k','p','o')

...ビット、もちろん)

おっと、最後の文字クラスには2つのfsがあるため、24.5億の順列しかありません。

私はそれが速くなるとは思わない…それはおそらく速くはならないだろうが、それはあなたが探しているパターンを手に入れるだろう。これを頻繁に行う傾向がある場合は、文字のテーブルを作成するので、アルファベット/数字または英数字を簡単に選択できます。

11
Joe

この古い質問はとにかく掘り下げられているので、DB2の組み込みXQueryサポートを正規表現マッチングに使用できることを述べます。

select whatever
from users
where
   xmlcast(
     xmlquery('fn:matches($USER_NAME,"^a[aofdmep][a-z][a-z0-9]{4}[sidbfkfpo]")') 
     as integer) = 1

上記のXMLQUERYは、列USER_NAMEに対してXQuery matches関数を呼び出します。結果はXML booleanなので、XMLCASTを使用してSQLデータ型に変換します。

11
mustaccio
SELECT * FROM
   (SELECT 'afr923zs' MyString FROM SYSIBM.SYSDUMMY1)
WHERE substr(MyString,1,1) = 'a' 
AND   substr(MyString,2,1) IN ('a','o','f','d','m','e','p')
AND   substr(MyString,3,1) BETWEEN 'a' AND 'z'
AND  (substr(MyString,4,1) BETWEEN 'a' AND 'z' 
   OR substr(MyString,4,1) BETWEEN '0' AND '9')
AND  (substr(MyString,5,1) BETWEEN 'a' AND 'z' 
   OR substr(MyString,5,1) BETWEEN '0' AND '9')
AND  (substr(MyString,6,1) BETWEEN 'a' AND 'z' 
   OR substr(MyString,6,1) BETWEEN '0' AND '9')
AND  (substr(MyString,7,1) BETWEEN 'a' AND 'z' 
   OR substr(MyString,7,1) BETWEEN '0' AND '9')
AND   substr(MyString,8,1) IN ('s','i','d','b','f','k','p','o');
6
Leigh Riffel

REGEXP_LIKEがDB2 for iSeriesで使用可能になりました-参照: http://www.itjungle.com/fhg/fhg051915-story01.html

2
mikrom

Leigh RiffelとJoeの答えに基づいて、個々の文字の長いリストがある場合、または複数の文字範囲がある場合は、LIKEの使用を検討する場合があります。

SELECT *
  FROM (SELECT 'afr923zs' MyString FROM SYSIBM.SYSDUMMY1) T
 WHERE substr(MyString,1,1) = 'a'
   AND 'aofdmep' like '%'||substr(MyString,2,1)||'%'
   AND substr(MyString,3,1) BETWEEN 'a' AND 'z'
   AND 'abcdefghijklmnopqrstuvwxyz0123456789' like '%'||substr(MyString,4,1)||'%'
   AND 'abcdefghijklmnopqrstuvwxyz0123456789' like '%'||substr(MyString,5,1)||'%'
   AND 'abcdefghijklmnopqrstuvwxyz0123456789' like '%'||substr(MyString,6,1)||'%'
   AND 'abcdefghijklmnopqrstuvwxyz0123456789' like '%'||substr(MyString,7,1)||'%'
   AND 'sidbfkpo' like '%'||substr(MyString,8,1)||'%'
;

同じ文字のリストを複数回使用するため、CROSS JOINされた定数列の使用を検討することもできます。

SELECT *
  FROM (SELECT 'afr923zs' MyString FROM SYSIBM.SYSDUMMY1) T
  CROSS JOIN (SELECT 'abcdefghijklmnopqrstuvwxyz0123456789' alphanum FROM SYSIBM.SYSDUMMY1) T2
 WHERE substr(MyString,1,1) = 'a'
   AND 'aofdmep' like '%'||substr(MyString,2,1)||'%'
   AND substr(MyString,3,1) BETWEEN 'a' AND 'z'
   AND alphanum like '%'||substr(MyString,4,1)||'%'
   AND alphanum like '%'||substr(MyString,5,1)||'%'
   AND alphanum like '%'||substr(MyString,6,1)||'%'
   AND alphanum like '%'||substr(MyString,7,1)||'%'
   AND 'sidbfkpo' like '%'||substr(MyString,8,1)||'%'
;

この例では必要ありませんが、CROSS JOINされた「テーブル」は複数の名前付き文字クラス列を定義できます。

2
dbenham

DB2 for z/OSでは、SQLには次のようにPASSINGが含まれます。

select whatever
from users
where
   xmlcast(
     xmlquery('fn:matches($USER_NAME,"^a[aofdmep][a-z][a-z0-9]{4}[sidbfkfpo]")'
      PASSING USER as "USER_NAME") 
     as integer) = 1
0
Aidanh