方解石如何处理数据转换?

时间:2018-10-17 19:07:53

标签: sql apache apache-beam apache-calcite beam-sql

我正在尝试将存储为字符串的日期转换为日期,例如

YYYYMMDD(字符串)到YYYY-MM-DD(日期)

据我所知,没有转换函数可以检查输入格式和输出格式,我尝试了手动逻辑,例如

>>> import pyspark.sql.functions as F
>>> 
>>> df.show()
+---+----+----+----+
| id|col1|col2|col3|
+---+----+----+----+
|  1|   0|   2|   3|
|  2|   4|   2|   3|
|  3|   1|   0|   3|
|  4|   0|   0|   0|
+---+----+----+----+

>>> cols = [i for i in df.columns if i != 'id']
>>> df = df.withColumn('mean',\
...     sum([df[i] for i in cols])/ \
...     sum([F.when(df[i]>0,1).otherwise(0) for i in cols])). \
...     fillna(0,'mean')
>>> 
>>> df.show()
+---+----+----+----+----+
| id|col1|col2|col3|mean|
+---+----+----+----+----+
|  1|   0|   2|   3| 2.5|
|  2|   4|   2|   3| 3.0|
|  3|   1|   0|   3| 2.0|
|  4|   0|   0|   0| 0.0|
+---+----+----+----+----+

但是Apache SQL Validator不接受此方法,有人在这里看到问题吗?

2 个答案:

答案 0 :(得分:2)

不是直接回答问题,但可能是相关的,日期文字用DATE关键字声明,例如您可以在Beam测试onetwo和方解石docs中查看示例。

更新

似乎发生的是方解石在进行CASE时增加了一些间接性。将字符串转换为日期通常可以正常工作。例如,如果输入行的架构为(INT f_int, VARCHAR f_string),而日期位于'YYYYMMDD'中(例如(1, '2018'),则此行有效:

SELECT f_int,
   CAST(
    SUBSTRING(TRIM(f_string) FROM 1 FOR 4)
      ||'-'
      ||SUBSTRING(TRIM(f_string) FROM 5 FOR 2)
      ||'-'
      ||SUBSTRING(TRIM(f_string) FROM 7 FOR 2) as DATE)
  FROM PCOLLECTION

甚至直接投射'YYYYMMDD'的作品:

SELECT f_int,
   CAST(f_string AS DATE)
FROM PCOLLECTION

您可以查看所有受支持的日期格式here

但是,一旦将其包装在'CASE ... ELSE NULL'中,Beam / Calcite似乎就推断出表达式类型现在是'String'。这意味着'THEN CAST(... AS DATE)'成功并返回一个'Date',但是当包裹在'String'中时,它将转换为'CASE'。然后,在我的测试中返回结果时,似乎试图将其强制转换回'Date',但是字符串格式现在不是'YYYYMMDD',而是其他一些默认格式。不幸的是,该格式不在受支持的列表中,因此失败。

解决方法:

'ELSE NULL'更改为已知为'Date'的内容后,例如'ELSE DATE "2001-01-01"'然后它又可以工作了,因为Beam /方解石似乎没有经过'String'->'Date'->'String'->'Date'路径,所以可以工作:

SELECT f_int,
  CASE WHEN CHAR_LENGTH(TRIM(f_string)) = 8
    THEN CAST (
       SUBSTRING(TRIM(f_string) FROM 1 FOR 4)
       ||'-'
       ||SUBSTRING(TRIM(f_string) FROM 5 FOR 2)
       ||'-'
       ||SUBSTRING(TRIM(f_string) FROM 7 FOR 2) AS DATE)
    ELSE DATE '2001-01-01'
  END
FROM PCOLLECTION

我提交了BEAM-5789来跟踪更好的解决方案。

更新2:

因此,尽管方解石生成计划告诉Beam做什么,但在这种情况下,实际上是Beam转换/解析了日期。我们正在努力使用Calcite的基本操作的内置实现,而不是在Beam中重新实现所有功能: https://github.com/apache/beam/pull/6417。合并此拉取请求后,如果我没看错(我假设this class将用于处理日期/时间值),则此CASE ... ELSE NULL路径应自动工作。它仍然可以通过字符串,可能不必要,但是应该可以正常工作。

答案 1 :(得分:0)

如果是MYSQL。 您可以尝试

SELECT DATE_FORMAT(STR_TO_DATE('20080908', '%Y%m%d'), "%Y-%m-%d");

为进行验证,您可以检查字符串是否可以成功转换为日期。有时。 NULL表示失败。