Есть несколько способов сделать это. Один из подходов - использовать 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;
Использование UNNEST
прост для понимания, но не работает, если вам нужно комбинировать его с другими операциями или если у вас есть повторяющиеся имена.
Другой подход - преобразовать карту в массив с помощью map_entries()
, используйте filter()
, чтобы выбрать питомца (ов) с количеством, равным максимальному количеству, затем используйте transform()
, чтобы вернуть только питомца название. На данный момент у вас есть максимальное количество питомцев. Затем вы можете UNNEST
разбить его на несколько строк или сохранить как массив для дальнейшей обработки. filter()
и transform()
используют лямбда-выражение , которое является спецификацией Presto c, расширением до SQL.
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;