【问题标题】:Why is my python udf returning empty output in redshift?为什么我的 python udf 在 redshift 中返回空输出?
【发布时间】:2018-04-26 10:06:08
【问题描述】:

我有一个表,其中有一列包含具有不同格式的日期时间值 - 有毫秒,没有毫秒,有零填充,没有零填充。 我需要使用该数据来计算时间间隔。因此,我编写了一个 python UDF 函数并尝试在我的查询中调用它。但是在表上调用时我得到空值,而用字符串调用时会出错。 我的UDF函数是:

create or replace function everyonesdb.validateDate(tzDate varChar)
  returns varchar
stable
as $$
    from datetime import datetime
    try:
        return datetime.strftime(datetime.strptime(tzDate,'%Y-%m-%d %H:%M:%S:%f %z'),'%Y-%m-%d %H:%M:%S %z')
    except ValueError:
        pass
$$ language plpythonu;

我这样称呼它:

Select validateDate('2018-04-19 09:29:52 +1000')

我得到的错误:

[Amazon](500310) Invalid operation: function validatedate("unknown") is not unique;

我也在我的查询中尝试过。有了这个,我只会得到空值。

SELECT DISTINCT date_time_tz,
   validateDate(date_time_tz) from table1

O/P:

     date_time_tz                   validatedate
    2018-04-19 12:37:33:359 +0800   
    2018-04-19 10:23:27:492 +1000   
    2018-04-19 11:02:58:810 +1000   
    2018-04-19 09:39:42:820 +1000   
    2018-04-19 10:30:18:017 +0530   
    2018-04-19 16:14:49:581 +1000   

这是我第一次尝试 Python UDF。任何帮助将不胜感激。

【问题讨论】:

  • pass on error 是非常错误的形式。在这种情况下,至少要使return None 明确,以便清楚您打算这样做。也就是说,我看不到在这里返回错误NULL 背后的逻辑。这样的错误可能表明数据格式错误,在这种情况下,应将错误返回给调用者。如果您尝试将日期分类为有效或无效,您的函数可能应该返回 boolean,而不是日期或 NULL。例如,考虑输入日期本身可能是NULL;您的函数无法区分 NULL 输入和无效输入。
  • @jpmc26:感谢您的回复。我同意这不是最好的方法。但我只是在尝试我的选择。如果成功了,我会改进返回语句。这暂时不会进入生产环境。再次感谢!

标签: python amazon-redshift user-defined-functions


【解决方案1】:

validateDate('2018-04-19 09:29:52 +1000')

由于某种原因(可能是 SQL 和 Python 之间的数据类型映射),该字符串未被识别为 varchar。尝试明确指定数据类型以避免该问题

validateDate('2018-04-19 09:29:52 +1000'::varchar)

在查询中,您在 datetime 上使用函数,看起来它接受 datetime 作为 varchar 参数,但代码抛出异常并在 pass 行结束,返回 null。尝试对第二个查询执行相同的操作(添加 ::varchar

【讨论】:

  • 感谢您回复@AlexYes。我尝试将输入转换为 varchar。我现在没有收到任何错误,但输出仍然为 Null。
  • @IshaGarg 你的函数在 Python 中是否可以使用相同的输入?
【解决方案2】:

这对我有用,根据需要进行修改。不确定究竟你的有什么问题。

CREATE OR REPLACE FUNCTION f_validate_date(tz_date VARCHAR(50))
    RETURNS TIMESTAMP
STABLE
AS $$
    if tz_date is None:
        return None
    else:
        from datetime import datetime
        dtm = datetime.strptime(tz_date,'%Y-%m-%d %H:%M:%S:%f')
        return dtm
$$ LANGUAGE plpythonu
;

结果

SELECT f_validate_date('2018-05-01 18:18:00:000');
   f_validate_date
---------------------
 2018-05-01 18:18:00

或者你可以用老式的方式来做。它更快,但不喜欢分号毫秒分隔符。

SELECT '2018-05-01 18:18:00.000'::TIMESTAMP;
      timestamp
---------------------
 2018-05-01 18:18:00

--Leading zeroes
SELECT '0002018-05-01 18:18:00.000'::TIMESTAMP;
      timestamp
---------------------
 2018-05-01 18:18:00

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-15
  • 1970-01-01
  • 2020-10-13
相关资源
最近更新 更多