【问题标题】:AWS Athena unnest with left join not workingAWS Athena unnest with left join 不工作
【发布时间】:2021-01-07 10:25:27
【问题描述】:

我有一个嵌套的 JSON 结构,我想在其中取消嵌套一个 JSON 子树。 A 或 B 都已填充,并且 event.type 标记为“A”或“B”。下面是两个简化的例子:

{
  "event": {
        "event_type": "A",
        "time": 1599692445083,
        "A" : {
            "name": "item1",
            "revenue": 100
        }
      }
  }
}

{
  "event": {
        "event_type": "B",
        "time": 1599692445083,
        "B" : {
            "items" : [
                {"name": "item2", revenue" : 10},
                {"name": "item3", revenue" : 20},
            ]
        }
      }
  }
}

查询到目前为止有效,但我有一个问题,即 UNNEST 仅适用于交叉连接,因此我丢失了所有“A”事件,因为我需要左连接。请注意,我进行了多次聚合,因此以更简单的方式单独计算总和就足够了。

select
    from_unixtime( (floor(event.time/1000) / (60 * 60))  *60*60) as event_hour,
    count(*) filter(where event.event_type = 'A') as A_items,
    count(*) filter(where event.event_type = 'B') as B_items
FROM mydb.event_table
   left join unnest(event.B.items) as t(b)
WHERE
    year=2020 and month=9 and day=18 and hour=1
GROUP BY
    from_unixtime( (floor(event.time/1000) / (60 * 60))  *60*60),

对于 cross join unnest 查询执行,但由于 A 没有项目数组,我没有计算任何条目。对于 left join unnest,我收到了一条错误消息(很有趣,它在那里也声明了“left”):

mismatched input 'where' expecting {'join', 'cross', 'inner', 'left', 'right', 'full', 'natural', 'using', 'on', 'tablesample'}

有没有办法在 Athena 的 unnest 中使用左连接?

【问题讨论】:

  • 我实际上并不确定您是否需要整个 unnest,这不可行吗? count(*) filter(where event.event_type = 'A') as A_items, sum(cardinality(event.B.items)) filter(where event.event_type = 'B') as B_items

标签: arrays json left-join presto amazon-athena


【解决方案1】:

Athena 基于 Presto .172 LEFT JOINUNNEST 被添加到 Presto 319

添加对涉及 UNNEST 的 INNER 和 OUTER 联接的支持。

我认为雅典娜在他们之前不会支持这一点

  • 升级到更新的 Presto 版本
  • 将该功能向后移植到他们的分支

同时,您可以运行最新最好的 Presto 版本:

另外,正如@GMB 所指出的,JOIN 需要ON 子句(可以像ON true 一样简单)。

【讨论】:

  • 感谢您对所用 presto 版本的有用评论。即使感觉不常见,JOIN 也不会强制在 Presto 中使用 ON。如果没有定义,它只是在加入时做一个笛卡尔积。请参阅 JOIN 的 Presto 文档:prestodb.io/docs/current/sql/select.html#joins 使用 UNNEST 不需要虚拟“on”子句。见:prestodb.io/docs/current/sql/select.html#unnest
  • @supernova,这仅适用于 CROSS JOIN。 LEFT/RIGHT/FULL/INNER JOIN 确实需要一个 ON 子句。在您提到的示例中,UNNEST 不需要它的原因是 UNNEST(它只是一个表函数)正在用于 CROSS JOIN(或隐式连接)的上下文中
【解决方案2】:

对于上述用例,有一种解决方法是在使用交叉连接进行 UNNESTING 时不会丢失条目。它看起来很丑,但在 Athena 支持更新的 Presto 功能之前可以完成工作。

代替

   left join unnest(event.B.items) as t(b)

可以通过合并将左连接重写为交叉连接:

   cross join unnest(coalesce(event.B.items, array[null])) as t(b)

【讨论】:

  • 这不适用于空数组的行,对吧?为此,您需要IF(event.B.items IS NULL OR cardinality(event.B.items) = 0, ARRAY[NULL], event.B.items) 之类的东西。还是在COALESCE 的眼中,空数组在某种程度上等同于NULL
  • 在我们的用例中,我们只需要所有项目。因此,我们将一个非退出 (=null) 匹配替换为一个具有一个空元素的数组(导致连接出现空行)。注意null != array[null]。否则它什么也做不了。 COALESCEnull 替换为 array[null] 即可解决问题)。如果那里有一个没有元素的数组,它不应该是unnest,你需要用一个你提到的带有空元素的数组替换它。希望这会有所帮助。
  • 您需要注意event.B.items 也是一个空数组的情况
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-21
  • 2013-11-02
  • 2018-12-04
  • 1970-01-01
  • 2017-04-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多