1

次のファイル名が与えられた場合:

xxxx/2013-02/csv/Sales_1302040000-1302050000.zip

この関数で regexp_matches が null を返す理由を誰かが説明できますか:

CREATE OR REPLACE FUNCTION get_import_batch_date(filename text) 
RETURNS DATE AS
$BODY$    
DECLARE
    matches text[];
    result date;
BEGIN

    matches := regexp_matches(filename, E'Sales_(\\d{2})(\\d{2})(\\d{2})');    
    IF matches IS NOT NULL THEN
        result := format('%s-%s-%s', 2000 + matches[1]::int, matches[2], matches[3])::DATE;
        RETURN result;
    END IF;

    RAISE WARNING 'Unable to determine batch date from %', filename;

    RETURN NULL;

END;
$BODY$
  LANGUAGE plpgsql IMMUTABLE;

ただし、次の無名関数で機能します。

DO language plpgsql $$
DECLARE
    filename text := 'xxxx/2013-02/csv/Sales_1302040000-1302050000.zip';
    matches text[];
    result date;
BEGIN

    matches := regexp_matches(filename, E'Sales_(\\d{2})(\\d{2})(\\d{2})');    
    IF matches IS NOT NULL THEN
        result := format('%s-%s-%s', 2000 + matches[1]::int, matches[2], matches[3])::DATE;
        raise notice '%', result;
    END IF;

END;
$$;      

このクエリでは regexp_matches が正しく機能しているように見えますが、関数は失敗して null を返します。

SELECT
    regexp_matches('xxxx/2013-02/csv/Sales_1302040000-1302050000.zip', E'Sales_(\\d{2})(\\d{2})(\\d{2})'),
    get_import_batch_date('xxxx/2013-02/csv/Sales_1302040000-1302050000.zip');

私のコードには、私が見ていないバグがありますか (非常に可能性が高く、最も一般的な答えです)。

私はPostgreSQL 9.1.6を使用しています

最後の注意: このファイル名を指定すると、関数が 2013-02-04 の日付値を返すようにする必要があります。

4

3 に答える 3

2

アップデート:

問題は、pgAdmin の pgScript に関する混乱であることが判明しました。@David は、pgAdmin のクエリ ツールで F6 を押して、SQL スクリプトを実行するためのF5の代わりに pgScript を実行しました。以下のコメントを参照してください。
機能自体は問題ありません。

簡易機能

あなたのエラーを再現することはできません (Postgres 9.1.6 でテストされ、返されませんでしたNULL) が、おそらく失敗しない関数のより単純なバージョンを提供できます

CREATE OR REPLACE FUNCTION get_import_batch_date(filename text, OUT result date)
  AS
$func$    
BEGIN
   result := ('20' || substring(filename, E'Sales_(\\d{6})'))::date;

   IF result IS NULL THEN
      RAISE WARNING 'Unable to determine batch date from %', filename;
   END IF;
END
$func$ LANGUAGE plpgsql IMMUTABLE;
  • パラメータを使用してOUT物事を単純化します。

  • かなり複雑なregexp_matches()式とそれに伴う配列変換は必要ありません。簡単なsubstring()呼び出しで作業が完了します。プリペンドすると、タイトアウェイ20に変換されます。形式は、どのロケールでもdate有効な ISO 8601 日付形式と一致します。元のバージョンもそれに依存しており、オプションのハイフン ( ) が追加されています。-

     `'20130204'::date` works just as well as `'2013-02-04'::date`
    

  • RETURN必要ありません。OUTパラメータの値resultは自動的に返されます。
于 2013-02-06T02:59:54.047 に答える
1

ここでも動作します: http://sqlfiddle.com/#!1/d084b/1

get_import_batch_date に渡されたファイル名とまったく同じでしたか?

于 2013-02-06T02:10:23.417 に答える
0

Ok!私はついにそれを理解しました。なぜこれが起こるのか、何が起こっているのかはわかりませんが、少なくとも修正することはできます. ここに投稿している回答は、実際にはアーウィンの回答に基づいています。彼のコードは(いつものように)私のものよりもずっと優れていますが、これは、将来誰かがこの非常にイライラする問題を抱えている場合に機能します.

基本的に、私は今夜もそれをいじっていましたが、ついに何が起こっているのかに気づきました. このコードを使用すると:

CREATE OR REPLACE FUNCTION get_import_batch_date(in filename text, out result date) AS
$BODY$
DECLARE
BEGIN
   result := substring(filename, E'Sales_(\\d{6})')::date;
   IF result IS NULL THEN
      RAISE WARNING 'Unable to determine batch date from %', filename;
   END IF;   
END
$BODY$
  LANGUAGE plpgsql IMMUTABLE
  COST 100;

...そして F6 を押して「スクリプトを実行」すると、次のメッセージが返されます。

[QUERY    ] CREATE OR REPLACE FUNCTION get_import_batch_date(in filename text, out result date) AS
            $BODY$
            DECLARE
            BEGIN
               result := substring(filename, E'Sales_(\d{6})')::date;
               IF result IS NULL THEN
                  RAISE WARNING 'Unable to determine batch date from %', filename;
               END IF;   
            END
            $BODY$
              LANGUAGE plpgsql IMMUTABLE
              COST 100

重大な問題を特定できますか? 昨夜は行けなかったのですが、今夜はできました。部分文字列関数の「\」の1つを取り除いています。

これにより、一致が失敗し、NULL が返されます。

F5 キーを押すか、関数の [実行] ボタンをクリックすると、正常に動作します。(これはおそらく人々が行っていたことか、おそらく SQLFiddle が行っていることです (ここでは完全な推測です)。

F6 を機能させるには、行を次のように変更する必要がありました。

   result := substring(filename, E'Sales_(\\\d{6})')::date;

だから、それは私のために働くものです。これはどこかのバグのように感じます。でも、どこか分からない。多分@Erwinはこれに光を当てることができます。

于 2013-02-07T03:56:57.633 に答える