Presto 查询:查找映射中具有最大值的键

问题描述 投票:0回答:4

我有一张桌子

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

sql presto trino
4个回答
10
投票

有几种方法可以做到这一点。一种方法是使用

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 表达式,它是 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)

2
投票

对于 Athena 用户,通过索引访问行字段不可用(至少对于引擎的第二个版本是这样,尚未检查第三个),可以使用

map_keys
重写答案中的第二种方法并按索引映射访问:

-- sample data
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)]))
)

-- query
SELECT
    name,
    transform(
        filter(
            map_keys(pets),
            e -> pets[e] = array_max(map_values(pets))), -- we now that e is present in pets
        e -> e) AS max_pets
FROM people;

输出:

名字 最大宠物数
安迪 [鸟]
约翰 [老虎]
玛丽 [狗、猪]

或者只是使用

map_filter
:

SELECT
    name,
    map_keys(
        map_filter(
            pets,
            (k,v) -> v = array_max(map_values(pets)))) max_pets
FROM people;

0
投票

使用map_top_n_keys函数:

SELECT map_top_n_keys(map(ARRAY[‘a’, ‘b’, ‘c’], ARRAY[1, 2, 3]), 2) — [‘c’, ‘b’]


0
投票

由于 AWS Athena 目前不支持 map_top_n_keys 我必须使用以下表达式:

SELECT REDUCE(MAP_ENTRIES(MAP(ARRAY['a', 'b', 'c'], ARRAY[1, 2, 3])), ('',0), (s, x) -> IF(x[2] > s[2], x, s), s -> s)[1]

它获取一个映射,将其转换为键值元组数组,然后使用 REDUCE 函数查找具有最大值的元组。最后它返回找到的元组键

© www.soinside.com 2019 - 2024. All rights reserved.