在 Athena 上转换为带时区的时间戳失败

converting to timestamp with time zone failed on Athena

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

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
)

它给了我以下错误:

Your query has the following error(s): Unsupported Hive type: timestamp with time zone

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

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

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

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

Presto’s method for declaring timestamps with/with out timezone is not sql standard. In Presto, both are declared using the word TIMESTAMP, e.g. TIMESTAMP '2003-12-10 10:32:02.1212' or TIMESTAMP '2003-12-10 10:32:02.1212 UTC'. The timestamp is determined to be with or without timezone depending on whether you include a time zone at the end of the timestamp. In other systems, timestamps are explicitly declared as TIMESTAMP WITH TIME ZONE or TIMESTAMP WITHOUT TIME ZONE

Athena 派生的 Presto 版本确实支持 timestamptimestamp with timezone,但是 teradata 文档中提到的怪癖应该不是问题。真正的问题是 Athena does not support timestamp with timezone.

您链接的 presto 文档表明函数 returns 是不受支持的类型 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"
)

timestamp with time zone

这行不通

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

SQL Error [FAILED]: INVALID_CAST_ARGUMENT: Value cannot be cast to timestamp

这种类型的 Casting 也 returns 带时区的时间戳 :(

请注意,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 Error [FAILED]: Could not initialize class com.facebook.presto.util.DateTimeZoneIndex

无论出于何种原因,创建视图需要 java class 而解析 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"
)

运行 与我最近正在做的事情类似。 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

希望对您有所帮助!

您可以在 Athena 中对时间戳数据类型 (dt) 使用以下语法:

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