我正在尝试将存储为字符串的日期转换为日期,例如
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不接受此方法,有人在这里看到问题吗?
答案 0 :(得分:2)
不是直接回答问题,但可能是相关的,日期文字用DATE
关键字声明,例如您可以在Beam测试one,two和方解石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表示失败。