web-dev-qa-db-ja.com

Postgres-正規表現の一致が失敗した場合にデフォルト値を返す

正規表現の一致を試み、失敗した場合はnullを返します。

次のクエリは、文字列の最初の数値を見つけようとします。結果は、テキスト'blah'のエントリを無視します。代わりにnull値を返す方がいいです。

この質問は、おそらく正規表現についてではなく、集合代数についてです。私の直感は、グーグルが無駄であることを証明していますが、何もleft joinする必要なしに、エレガントな方法があることです。

with test_data as (
  select 'abc 123' as txt
  union
  select 'abc 456' as txt
  union
  select 'blah' as txt
)

select
  txt,
  (regexp_matches(txt, '\d+'))[1] as first_num
from
  test_data
1
Ryan Tuck

あなたの答えregexp_matches()の問題を解決する一方で、avoidより適切な関数の問題 substring() まずは次のとおりです。

_WITH test_data(txt) AS (
   VALUES
      (text 'abc 123')
    , ('abc 456')
    , ('blah')
   )
SELECT txt, substring(txt FROM '\d+') AS first_num
FROM   test_data;
_

文字列の最初の一致を返すか、またはno matchの場合はNULLを返します。

substring(string FROM pattern)は標準SQL構文です。
それをsubstring(string [FROM int] [FOR int])またはsubstring(string FROM pattern FOR escape)と混同しないでください。

短い、同等の、現在文書化されていないPostgres実装substring(text, text)を使用することもできます(FROMの代わりにコンマ(_,_)を使用)。

regexp_matches() を使用して、allの一致をsetとして返します。 (単一の正規表現では複数の一致が発生する可能性があるため、テキストのセットarrays)に注意してください。フラグ_'g'_を追加してすべての行を取得しない限り、最初の行のみが引き続き取得されます(同じ正規表現に対して追加の一致がある場合は、それらを取得します)。関連:

複雑化を避けるために、Postgres 10より前のバージョンでは、セットを返す関数をFROMリストに移動します。

または、Postgres 10以降で regexp_match() を使用して、最初の行のみを返します。これも元の問題を示しません。

_WITH test_data(txt) AS (
   VALUES
      (text 'abc 123')
    , ('abc 456')
    , ('blah')
   )
SELECT txt, (regexp_match(txt, '\d+'))[1] AS first_num
from   test_data;
_

ただし、目的に応じてsubstring()を使用してください。

db <> fiddle ここ

3

副選択を使用します。

the docs から:

副選択を使用することにより、regexp_matches()が常に1行を返すように強制することが可能です。これは、一致しない行も含めてすべての行を返す必要があるSELECTターゲットリストで特に役立ちます。

解決策は次のとおりです。

with test_data as (
  select 'abc 123' as txt
  union
  select 'abc 456' as txt
  union
  select 'blah' as txt
)

select
  txt,
  (select regexp_matches(txt, '\d+'))[1] as first_num
from
  test_data
0
Ryan Tuck