从JSON对象数组中提取数据以获取特定的对象值

时间:2019-05-11 20:21:19

标签: sql sqlite sqlite-json1

在我的表格中,有一列JSON类型的列,其中包含描述时间偏移量的对象数组:

[
  {
    "type": "start"
    "time": 1.234
  },
  {
    "type": "end"
    "time": 50.403
  }
]

我知道我可以使用JSON_EACH()JSON_EXTRACT()提取它们:

CREATE TEMPORARY TABLE Items(
  id INTEGER PRIMARY KEY,
  timings JSON
);

INSERT INTO Items(timings) VALUES
  ('[{"type": "start", "time": 12.345}, {"type": "end", "time": 67.891}]'),
  ('[{"type": "start", "time": 24.56}, {"type": "end", "time": 78.901}]');

SELECT
  JSON_EXTRACT(Timings.value, '$.type'),
  JSON_EXTRACT(Timings.value, '$.time')
FROM
  Items,
  JSON_EACH(timings) AS  Timings;

这将返回一个表,如:

start    12.345
end      67.891
start    24.56
end      78.901

我真正需要的是:

  1. 查找特定类型的时间。 (找到匹配条件的数组中的第一个对象。)
  2. 获取此数据,并将其选择为表格其余部分的列。

换句话说,我正在寻找一个看起来像这样的表:

id        start        end
-----------------------------
0         12.345       67.891
1         24.56        78.901

我希望这样的查询:

SELECT
  id,
  JSON_EXTRACT(timings, '$.[type="start"].time'),
  JSON_EXTRACT(timings, '$.[type="end"].time')
FROM Items;

是否可以使用JSON函数中的path来选择我需要的方法?或者,采用其他方法来枢转第一个示例中应用于表的内容?

1 个答案:

答案 0 :(得分:1)

一种可能性:

WITH cte(id, json) AS
  (SELECT Items.id
        , json_group_object(json_extract(j.value, '$.type'), json_extract(j.value, '$.time'))
   FROM Items
   JOIN json_each(timings) AS j ON json_extract(j.value, '$.type') IN ('start', 'end')
   GROUP BY Items.id)
SELECT id
     , json_extract(json, '$.start') AS start
     , json_extract(json, '$.end') AS "end"
FROM cte
ORDER BY id;

给出

id          start       end
----------  ----------  ----------
1           12.345      67.891
2           24.56       78.901

另一种使用在sqlite 3.25中添加的窗口函数并避免创建中间JSON对象:

SELECT DISTINCT Items.id
              , max(json_extract(j.value, '$.time'))
                 FILTER (WHERE json_extract(j.value, '$.type') = 'start') OVER ids AS start
              , max(json_extract(j.value, '$.time'))
                 FILTER (WHERE json_extract(j.value, '$.type') = 'end') OVER ids AS "end"
FROM Items
JOIN json_each(timings) AS j ON json_extract(j.value, '$.type') IN ('start', 'end')
WINDOW ids AS (PARTITION BY Items.id)
ORDER BY Items.id;

关键是使用ON的{​​{1}}子句将结果限制为您关心的每个数组中的两个对象,然后将每个{{1 }}并用两种不同的方法。