【问题标题】:converting to timestamp with time zone failed on Athena在 Athena 上转换为带时区的时间戳失败
【发布时间】:2018-11-22 18:49:51
【问题描述】:

我正在尝试创建以下视图:

CREATE OR REPLACE VIEW view_events AS 
(
   SELECT
     "rank"() OVER (PARTITION BY "tb1"."innerid" ORDER BY "tb1"."date" ASC) "r"
   , "tb2"."opcode"
   , "tb1"."innerid"
   , "tb1"."date"
   , From_iso8601_timestamp(tb1.date) as "real_date"
   , "tb2"."eventtype"
   , "tb1"."fuelused"
   , "tb1"."mileage"
   , "tb1"."latitude"
   , "tb1"."longitude"
   FROM
     rt_message_header tb1
   , rt_messages tb2
   WHERE ((("tb1"."uuid" = "tb2"."header_uuid") AND ("tb2"."opcode" = '39')) AND ("tb2"."type" = 'event'))
   ORDER BY "tb1"."innerid" ASC, "tb1"."date" ASC
)

它给了我以下错误:

您的查询有以下错误: 不支持的 Hive 类型:带时区的时间戳

但是,当我自己运行查询时,它工作正常,并且 From_iso8601_timestamp 被提到 here 作为有效的日期函数。

谁能告诉我我做错了什么?

【问题讨论】:

    标签: sql date hive amazon-athena timestamp-with-timezone


    【解决方案1】:

    不幸的是,Athena 并不完全支持所有 Presto 功能,它有 limitations,并且在技术上落后于 Presto 几个版本。有一些尝试使 Athena 与 AWS Glue Metastore 紧密集成,虽然基于 Hive 的 Metastore 有一些不一致之处。我希望 Spark、Hive、Glue、Athena、Presto 等能够与同一个元存储一起工作,这会让生活更轻松,但回到你的问题:

    document about an older teradata fork of Presto 提到了一些关于 presto 时间戳的问题:

    Presto 声明带/不带时区的时间戳的方法不是 sql标准。在 Presto 中,两者都使用单词 TIMESTAMP 声明, 例如TIMESTAMP '2003-12-10 10:32:02.1212' 或 TIMESTAMP '2003-12-10 10:32:02.1212 UTC'。时间戳确定有无 时区取决于您是否在末尾包含时区 时间戳。在其他系统中,时间戳被明确声明为 TIMESTAMP WITH TIME ZONE 或 TIMESTAMP WITHOUT TIME ZONE

    从 Athena 派生出来的 Presto 版本确实支持 timestamp 和 timestamp with timezone,但正如 teradata 文档中提到的那样,这应该不是问题。真正的问题是Athena does not support timestamp with timezone。

    您链接到的 presto 文档显示该函数返回的值属于不受支持的类型 timestamp with timezone,因此您需要将其转换为受支持的其他内容。 Athena 允许函数和强制转换为不受支持的数据类型,这是一个疏忽,希望这将得到纠正,但现在您必须解决它。

    您需要做的是在该函数调用周围使用CAST() 函数,这会将类型从timestamp with time zone 更改为timestamp

    不幸的是,您可能无法将字符串直接转换为时间戳,尽管这取决于字符串的格式。您也不能使用在字符串之前写入timestamp 的转换样式,例如不能timestamp '2018-01-01 15:00:00',原因我将在下面解释。

    from_iso1601_timestamp() 函数返回的类型

    SELECT typeof("real_date") AS real_date_type
    FROM
    (
    SELECT From_iso8601_timestamp('2018-01-01T15:00:00Z') as "real_date"
    )
    

    带有时区的时间戳

    这不起作用

    SELECT typeof("real_date") AS real_date_type
    FROM
    (
    SELECT CAST('2018-01-01T15:00:00Z' AS timestamp) as "real_date"
    )
    

    SQL 错误 [FAILED]:INVALID_CAST_ARGUMENT:值无法转换为 时间戳

    这种类型的 Casting 还返回带时区的时间戳:(

    请注意,其中的 SELECT 部分有效,它表示它是 timestamp,但由于某些内部不一致的原因,您无法创建视图并且会出现错误。

    CREATE OR replace VIEW test 
    AS 
    SELECT typeof( "real_date" ) AS real_date_type
    FROM
    (
    SELECT  timestamp '2018-01-01 15:00:00' as "real_date"
    )
    

    SQL 错误 [FAILED]:无法初始化类 com.facebook.presto.util.DateTimeZoneIndex

    无论出于何种原因,创建视图都需要 java 类,而解析 select 中的值则不需要。这是一个应该解决的错误。

    这很好用

    CREATE OR REPLACE VIEW test
    AS
    SELECT typeof("real_date") AS real_date_type
    FROM
    (
    SELECT CAST(From_iso8601_timestamp('2018-01-01T15:00:00Z') AS timestamp) as "real_date"
    )
    

    【讨论】:

      【解决方案2】:

      您可以在 Athena 中通过 Timestamp 数据类型 (dt) 使用以下语法:

      SELECT id,dt,dt AT TIME ZONE 'America/New_York' as dateTimeNY FROM Table
      

      【讨论】:

        【解决方案3】:

        在我最近正在做的事情上遇到了类似的事情。 AWS Support 向我指出了 Davos 解决方案,但它最终对我的情况不起作用。我最终得到的解决方案是:

        create or replace view db_name.vw_name AS
        select
            from_unixtime(cast(to_unixtime(current_timestamp) AS bigint)) as field_name
        from db_name.tbl_name
        

        这会将current_timestamp(即timestamp with time zone)的输出转换为timestamp

        如果要验证字段的数据类型,可以使用:

        select typeof(field_name) from db_name.vw_name
        

        希望有帮助!

        【讨论】:

        • 感谢您的补充,这似乎是一个有用的替代方案。
        猜你喜欢
        • 2021-09-22
        • 2018-12-18
        • 1970-01-01
        • 2019-10-07
        • 2015-10-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多