Найти максимальное значение из столбца, в котором есть объект json с парами ключ-значение - PullRequest
2 голосов
/ 02 июля 2019

У меня есть таблица, в которой есть столбец строки JSON (пары ключ-значение) элементов, я хочу вернуть только пару ключ-значение наибольшего значения

. Сначала я могу сделать этоUNNEST с использованием объекта JSON с последующим получением наибольшего значения ORDER BY item, value (DESC) и использованием array_agg для получения наибольшего значения.Проблема в том, что это означает создание нескольких таблиц и медленная.Я надеюсь, что в одной операции я смогу извлечь самую большую пару ключ-значение.

Это:

| id | items                              |
| -- | ---------------------------------- |
|  1 | {Item1=7.3, Item2=1.3, Item3=9.8}  |
|  2 | {Item2=4.4, Item3=5.2, Item1=0.1}  |
|  3 | {Item5=6.6, Item2=1.4, Item4=1.5}  |
|  4 | {Item6=0.9, Item7=11.2, Item4=8.1} |

Должно стать:

| id | item  | value |
| -- | ----- | ----- |
|  1 | Item3 |  9.8  |
|  2 | Item3 |  5.2  |
|  3 | Item5 |  6.6  |
|  4 | Item7 |  11.2 |

На самом деле мне не нужно это значение, если элемент является наибольшим из объекта JSON, поэтому будет хорошо и следующее:

| id | item  |
| -- | ----- |
|  1 | Item3 |
|  2 | Item3 |
|  3 | Item5 |
|  4 | Item7 |

Ответы [ 2 ]

4 голосов
/ 03 июля 2019

Производительность Presto UNNEST улучшена в Presto 316. Однако в этом случае вам не нужно UNNEST.

Вы можете

Используйте запрос как

SELECT 
    id,
    reduce(
        -- conver JSON to array of key/value pairs
        map_entries(CAST(data AS map(varchar, double))),
        -- initial state for reduce (must be same type as key/value pairs)
        (CAST(NULL AS varchar), -1e0), -- assuming your values cannot be negative
        -- reduction function
        (state, element) -> if(state[2] > element[2], state, element),
        -- reduce output function
        state -> state[1]
    ) AS top
FROM (VALUES
    (1, JSON '{"Item1":7.3, "Item2":1.3, "Item3":9.8}'),
    (4, JSON '{"Item6":0.9, "Item7":11.2, "Item4":8.1}'),
    (5, JSON '{}'),
    (6, NULL)
) t(id, data);

Вывод

 id |  top
----+-------
  1 | Item3
  4 | Item7
  5 | NULL
  6 | NULL
(4 rows)
2 голосов
/ 02 июля 2019

Сохраните значения по одному на строку в дочерней таблице.

CREATE TABLE child (
 id INT NOT NULL,
 item VARCHAR(6) NOT NULL,
 value DECIMAL(9,1),
 PRIMARY KEY (id, item)
);

Вам не нужно объединяться, чтобы найти наибольшую группу, просто используйте оконную функцию:

WITH cte AS (
  SELECT id, item, ROW_NUMBER() OVER (PARTITION BY id ORDER BY value DESC) AS rownum
  FROM mytable
)
SELECT * FROM cte WHERE rownum = 1;

Решить это с помощью JSON - плохая идея. Это делает вашу таблицу денормализованной, усложняет разработку запросов, и я предсказываю, что это ухудшит производительность запросов.

...