presto查询:在Map中查找具有最大值的键

tag5nh1u  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(498)

我有一张table

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查询来实现这一点吗?谢谢!

ewm0tg9j

ewm0tg9j1#

有几种方法可以做到这一点。一种方法是使用 UNNEST 将Map转换为行,每个Map条目一行。然后你可以使用 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表达式,它是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)

相关问题