2016-05-06 5 views
1

この列の1つに、JSONデータがテキスト形式で格納されています。私はこの列がキーtimeout_dataための複数の日付を持っているwhomeの行を見つけるためにSQLクエリを記述する必要がOracleデータベース(11g)の列データ内に複数の文字列が存在する正規表現

{ 
    "dummy_time": "2016-04-27T18:44:55+00:00", 
    "timeout_data": "2016-04-29T16:22:35+00:00,2016-04-30T16:22:35+00:00,2016-05-29T16:22:35+00:00", 
    "time_id": "T101", 
    "time_desc": "bla bla bla" 
} 

:のようなサンプルデータが見えます。私はREGEXでそれほど良いものではありません。

SELECT * 
FROM table1 f 
WHERE REGEXP_LIKE(f.data, '.+\"timeout_data\": \".+,.+\",\"time_id\".*') 
AND ROWNUM<6; 

そして、このクエリは年齢以来実行されている:私は、キーtimeout_dataで日付の2つの出現箇所を見つけるために、単純なクエリを書きました。テーブルには約35,000,000行があります。 キーtimeout_dataに複数の日付がどのように見つかるかわかりません。詳細が必要な場合はお知らせください。

+0

Oracleのどのバージョンですか? 12cはJSONクエリをネイティブにサポートしています。 – jva

+0

バージョンは11gです。 – user613114

+0

あなたの正規表現では、2つの異なる文字列、* timeout_data *と* time_id *をチェックしますが、あなたのテキストでは*複数のtimeout_data *について話しますか?正しいものは何ですか? – dnoeth

答えて

0

おそらくinstr()が速くなります。

SELECT 'test' 
FROM (SELECT '{ 
    "dummy_time": "2016-04-27T18:44:55+00:00", 
    "timeout_data": "2016-04-29T16:22:35+00:00,2016-05-29T16:22:35+00:00", 
    "time_id": "T101", 
    "time_desc": "bla bla bla" 
}' data FROM dual) 
WHERE instr(data,',',instr(data,'"timeout_data"')) < instr(data,'"',instr(data,'"timeout_data"'),4); 

データのサブセットでテストできます。また、instr(data,'"timeout_data"')が2回使用されている可能性もあります。

更新:あなたのREGEXに問題があるようですが - 正規表現はここに制限要因ではありません - .+

\"time_id\"前にも持っている必要があります。私のマシンでは、100k SELECTのループにデュアルから4.3秒かかる。 REGEXを追加すると、さらに0.1秒かかります。 timeout_data

2と

0

1)抽出ライン)パターンの発生を数えます。

select REGEXP_COUNT(regexp_substr(json,'^.*timeout_data.*$', 1,1,'m'), '\d{4}-\d{2}-\d{2}T') 
from ( 
select '{ 
    "dummy_time": "2016-04-27T18:44:55+00:00", 
    "timeout_data": "2016-04-29T16:22:35+00:00,2016-04-30T16:22:35+00:00,2016-05-29T16:22:35+00:00", 
    "time_id": "T101", 
    "time_desc": "bla bla bla" 
}' json from dual 
); 
0

あなたは、正規表現使ってISO8601形式の日付を見つけることができます:あなたが使用することができ、それをカンマで区切った複数のコピーを望んでいた場合

\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2} 

を:

pattern(,pattern)+ 

(または正確に2つの一致のみを検索する場合は、末尾の+を削除してください)

So

クエリになるだろう
\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}(,\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2})+ 

SELECT * 
FROM table1 f 
WHERE REGEXP_LIKE(f.data, '"timeout_data":\s*"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}(,\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2})+"') 
AND ROWNUM<6; 

しかし、あなたは、具体的な日数を一致させたいとちょうどカンマで区切った複数の値がある場合は、あなたが使用することができますテストしたくない場合:

[^,"]+(,[^,"]+)+ 

(注:パターンが終了二重引用符と一致しないことを確実にすること - それ以外のパターンは属性の終わりを超えて一致する可能性があります。あなたのクエリになるだろう)

SELECT * 
FROM table1 f 
WHERE REGEXP_LIKE(f.data, '"timeout_data":\s*"[^,"]+([^,"]+)+"') 
AND ROWNUM<6; 

注:あなたがのためにフィルタリングされ、あなたが二重引用符をエスケープする必要はありませんセグメントの前または後に何を探す必要はありません。

関連する問題