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 来运行 pgScript 而不是F5来运行 SQL 脚本。请参阅下面的评论
功能本身很好。

简化功能

我无法重现您的错误(在 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`
    

  • 不需要RETURNOUT参数的值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

好的!我终于弄明白了。我不确定为什么会发生这种情况,或者发生了什么,但我至少可以解决它。我在这里发布的答案实际上是基于 Erwin 的答案。他的代码(像往常一样)比我的要好得多,但是如果其他人将来遇到这个非常令人沮丧的问题,这将有效。

基本上,我今晚又在玩它,它终于引起了我的注意。如果我采用此代码:

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

你能发现关键问题吗?我昨晚不能,但今晚做了。它正在剥离子字符串函数上的“\”之一。

这将导致匹配失败并返回 NULL。

如果您按 F5 或单击该功能的“运行”按钮,则它可以正常工作。(这可能是人们正在做的事情,或者可能是 SQLFiddle 正在做的事情(这里总猜测)。

为了让 F6 为我工作,我不得不将行更改为:

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

所以,这对我有用。这感觉就像某个地方的错误。但是,我不知道在哪里。也许@Erwin 可以对此有所了解。

于 2013-02-07T03:56:57.633 回答