从具有带有键值对的json对象的列中查找最大值

时间:2019-07-02 20:39:37

标签: sql json tsql greatest-n-per-group presto

我有一个表,其中包含一个项目的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 个答案:

答案 0 :(得分:4)

Presto's UNNEST performance got improved在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)

答案 1 :(得分:2)

在子表中每行存储一个值。

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解决这个问题不是一个好主意。它会使您的表非规范化,使查询更难以设计,并且我预计它将使查询性能变差。