【问题标题】:Presto query: Find the key with maximum value in a mapPresto查询:在地图中查找具有最大值的键
【发布时间】:2025-04-06 23:40:01
【问题描述】:

我有一张桌子

Name  pets
--------------
Andy  {dog:2, cat:1, bird:4}
John  {tiger:3, elephant:1, fish:2}
Mary  {dog:2, pig:2}

我想要找到每个人的最大数量的宠物类型。在平局的情况下,为每只宠物复制该行。结果应如下所示:

Name  max_pet
------------------
Andy  bird
John  tiger
Mary  dog
Mary  pig

目前,我导出了表格并在 python 中完成。但我想知道我可以使用 Presto/SQL 查询来实现这一点吗?谢谢!

【问题讨论】:

  • pets的数据类型是什么?为什么要把它放在一个表中而不是放在两个表中?

标签: sql presto trino


【解决方案1】:

有几种方法可以做到这一点。一种方法是使用UNNEST 将映射转换为行,每个映射条目一行。然后,您可以使用rank() 窗口函数为每个名称的宠物分配排名,之后您只选择排名最高的项目。

WITH people (name, pets) AS (
  VALUES
    ('Andy', map_from_entries(array[('dog', 2), ('cat', 1), ('bird', 4)])),
    ('John', map_from_entries(array[('tiger', 3), ('elephant', 1), ('fish', 2)])),
    ('Mary', map_from_entries(array[('dog', 2), ('pig', 2)]))
)
SELECT name, pet AS max_pet
FROM (
    SELECT name, pet, count,
           rank() OVER (PARTITION BY name ORDER BY count DESC) rnk
    FROM people
    CROSS JOIN UNNEST(pets) AS t (pet, count)
)
WHERE rnk = 1;
 name | max_pet 
------+---------
 Andy | bird    
 John | tiger   
 Mary | dog     
 Mary | pig     
(4 rows)

使用UNNEST 简单易懂,但如果需要与其他操作结合使用,或者名称重复,则效果不佳。

另一种方法是使用map_entries() 将地图转换为数组,使用filter() 选择计数等于最大计数的宠物,然后使用transform() 仅返回宠物名称。此时,您有一个最大宠物数组。然后,您可以将UNNEST 分成多行,或将其保留为数组以供进一步处理。 filter()transform() 使用 lambda expression,这是 SQL 的 Presto 特定扩展。

WITH people (name, pets) AS (
  VALUES
    ('Andy', map_from_entries(array[('dog', 2), ('cat', 1), ('bird', 4)])),
    ('John', map_from_entries(array[('tiger', 3), ('elephant', 1), ('fish', 2)])),
    ('Mary', map_from_entries(array[('dog', 2), ('pig', 2)]))
)
SELECT
    name,
    transform(
        filter(
            map_entries(pets),
            e -> e[2] = array_max(map_values(pets))),
        e -> e[1]) AS max_pets
FROM people;
 name |  max_pets  
------+------------
 Andy | [bird]     
 John | [tiger]    
 Mary | [dog, pig] 
(3 rows)

【讨论】:

  • transform 会返回ARRAY 类型,我们需要在transform 方法之后添加[1]
  • @Xiao 我将示例输出添加到答案中。数组的使用是有意的,因为可以有多个最大宠物(如原始问题所示)。