0

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

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

我知道我可以用JSON_EACH()and提取这些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 函数中使用路径来选择我需要的东西?或者,以其他方式将我在第一个示例中的内容应用于表格?

4

1 回答 1

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子句JOIN将结果限制为您关心的每个数组中的两个对象,然后Items.id使用几种不同的方法将每个最多两行合并为一个。

于 2019-05-11T22:50:44.507 回答