首页 > 解决方案 > Calcite 如何处理数据转换?

问题描述

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

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

据我所知,没有检查输入格式和输出格式的转换功能,我尝试了手动逻辑,例如

CASE 
  WHEN CHAR_LENGTH(TRIM(some_string_date)) = 8
  THEN
    CAST(
      SUBSTRING(TRIM(some_string_date) FROM 1 FOR 4)
      || '-'
      || SUBSTRING(TRIM(some_string_date) FROM 5 FOR 2)
      ||'-'
      || SUBSTRING(TRIM(some_string_date) FROM 7 FOR 2)
    as DATE) 
  ELSE
    NULL 
END

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

标签: sqlapache-beamapache-calcitebeam-sql

解决方案


不直接回答问题,但可能相关,日期文字是用DATE关键字声明的,例如,您可以在 Beam tests: one , two和 Calcite docs中的测试中看到示例。

更新:

似乎发生的是 Calcite 在做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

您可以在此处查看所有支持的日期格式。

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

解决方法:

一旦您更改'ELSE NULL'为已知为 a 的东西'Date',例如'ELSE DATE "2001-01-01"',它就会再次工作,因为 Beam/Calcite 似乎没有通过'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:

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


推荐阅读