在 Athena 上转换为带时区的时间戳失败
Posted
技术标签:
【中文标题】在 Athena 上转换为带时区的时间戳失败【英文标题】:converting to timestamp with time zone failed on 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 作为有效的日期函数。
谁能告诉我我做错了什么?
【问题讨论】:
【参考方案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
希望有帮助!
【讨论】:
感谢您的补充,这似乎是一个有用的替代方案。以上是关于在 Athena 上转换为带时区的时间戳失败的主要内容,如果未能解决你的问题,请参考以下文章
DateTime<Utc> 编译但不是 DateTime<Local> 查询表,其列定义为带时区的时间戳