arrays - PostgreSQL:计算特定的 JSON 元素
问题描述
我想搜索和计算 json 数组中的特定元素。数组并不总是具有相同的长度。
当前服务器版本:9.6.12
我的表如下所示:
| id | value
+----+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 1 | {"timeline":{"events":[{"date":1552289433501,"types":["START"]},{"date":1552291643428,"types":["STOP"]}]},"ongoingSLAData":null,"completeSLAData":[],"metricId":26,"definitionChangeDate":1553074745838,"definitionChangeMsEpoch":1553074745838,"goalsChangeDate":null,"goalsChangeMsEpoch":null,"goalTimeUpdatedDate":null,"goalTimeUpdatedMsEpoch":null,"metricCreatedDate":null,"updatedDate":1553074858390}
| 2 | {"timeline":{"events":[{"date":1552289433501,"types":["START"]},{"date":1552291643428,"types":["STOP"]}]},"ongoingSLAData":null,"completeSLAData":[{"succeeded":true,"goalTime":3600000,"goalTimeUnits":{"weeks":0,"remainingDaysWithinWeek":0,"remainingMillisWithinDay":3600000,"breached":false},"elapsedTime":443428,"remainingTime":3156572,"remainingTimeInDaysAndMillis":{"weeks":0,"remainingDaysWithinWeek":0,"remainingMillisWithinDay":3156572,"breached":false},"startTime":1552289433630,"stopTime":1552291643428},{"succeeded":false,"goalTime":3600000,"goalTimeUnits":{"weeks":0,"remainingDaysWithinWeek":0,"remainingMillisWithinDay":3600000,"breached":false},"elapsedTime":4069721,"remainingTime":-469721,"remainingTimeInDaysAndMillis":{"weeks":0,"remainingDaysWithinWeek":0,"remainingMillisWithinDay":469721,"breached":true},"startTime":1552986606597,"stopTime":1552990676318}],"metricId":26,"definitionChangeDate":1553074745838,"definitionChangeMsEpoch":1553074745838,"goalsChangeDate":null,"goalsChangeMsEpoch":null,"goalTimeUpdatedDate":null,"goalTimeUpdatedMsEpoch":null,"metricCreatedDate":null,"updatedDate":1553074858390}|
| 3 | {"timeline":{"events":[{"date":1546589579130,"types":["START"]},{"date":1546595500799,"types":["STOP"]}]},"ongoingSLAData":null,"completeSLAData":[{"succeeded":false,"goalTime":3600000,"goalTimeUnits":{"weeks":0,"remainingDaysWithinWeek":0,"remainingMillisWithinDay":3600000,"breached":false},"elapsedTime":5921454,"remainingTime":-2321454,"remainingTimeInDaysAndMillis":{"weeks":0,"remainingDaysWithinWeek":0,"remainingMillisWithinDay":2321454,"breached":true},"startTime":1546589579345,"stopTime":1546595500799}],"metricId":26,"definitionChangeDate":1553074745838,"definitionChangeMsEpoch":1553074745838,"goalsChangeDate":null,"goalsChangeMsEpoch":null,"goalTimeUpdatedDate":null,"goalTimeUpdatedMsEpoch":null,"metricCreatedDate":null,"updatedDate":1553074843707}|
SQL:
DROP TABLE IF EXISTS "sla_data";
DROP SEQUENCE IF EXISTS sla_data_id_seq;
CREATE SEQUENCE sla_data_id_seq
INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 3 CACHE 1;
CREATE TABLE "public"."sla_data"
(
"id" integer DEFAULT nextval('sla_data_id_seq') NOT NULL,
"sladata" text
) WITH (oids = false);
TRUNCATE "sla_data";
INSERT INTO "sla_data" ("id", "sladata")
VALUES (2, '{"timeline":{"events":[{"date":1552289433501,"types":["START"]},{"date":1552291643428,"types":["STOP"]}]},"ongoingSLAData":null,"completeSLAData":[{"succeeded":true,"goalTime":3600000,"goalTimeUnits":{"weeks":0,"remainingDaysWithinWeek":0,"remainingMillisWithinDay":3600000,"breached":false},"elapsedTime":443428,"remainingTime":3156572,"remainingTimeInDaysAndMillis":{"weeks":0,"remainingDaysWithinWeek":0,"remainingMillisWithinDay":3156572,"breached":false},"startTime":1552289433630,"stopTime":1552291643428},{"succeeded":false,"goalTime":3600000,"goalTimeUnits":{"weeks":0,"remainingDaysWithinWeek":0,"remainingMillisWithinDay":3600000,"breached":false},"elapsedTime":4069721,"remainingTime":-469721,"remainingTimeInDaysAndMillis":{"weeks":0,"remainingDaysWithinWeek":0,"remainingMillisWithinDay":469721,"breached":true},"startTime":1552986606597,"stopTime":1552990676318}],"metricId":26,"definitionChangeDate":1553074745838,"definitionChangeMsEpoch":1553074745838,"goalsChangeDate":null,"goalsChangeMsEpoch":null,"goalTimeUpdatedDate":null,"goalTimeUpdatedMsEpoch":null,"metricCreatedDate":null,"updatedDate":1553074858390}'),
(3, '{"timeline":{"events":[{"date":1546589579130,"types":["START"]},{"date":1546595500799,"types":["STOP"]}]},"ongoingSLAData":null,"completeSLAData":[{"succeeded":false,"goalTime":3600000,"goalTimeUnits":{"weeks":0,"remainingDaysWithinWeek":0,"remainingMillisWithinDay":3600000,"breached":false},"elapsedTime":5921454,"remainingTime":-2321454,"remainingTimeInDaysAndMillis":{"weeks":0,"remainingDaysWithinWeek":0,"remainingMillisWithinDay":2321454,"breached":true},"startTime":1546589579345,"stopTime":1546595500799}],"metricId":26,"definitionChangeDate":1553074745838,"definitionChangeMsEpoch":1553074745838,"goalsChangeDate":null,"goalsChangeMsEpoch":null,"goalTimeUpdatedDate":null,"goalTimeUpdatedMsEpoch":null,"metricCreatedDate":null,"updatedDate":1553074843707}'),
(1, '{"timeline":{"events":[{"date":1552289433501,"types":["START"]},{"date":1552291643428,"types":["STOP"]}]},"ongoingSLAData":null,"completeSLAData":[{"succeeded":false,"goalTime":3600000,"goalTimeUnits":{"weeks":0,"remainingDaysWithinWeek":0,"remainingMillisWithinDay":3600000,"breached":false},"elapsedTime":5921454,"remainingTime":-2321454,"remainingTimeInDaysAndMillis":{"weeks":0,"remainingDaysWithinWeek":0,"remainingMillisWithinDay":2321454,"breached":true},"startTime":1546589579345,"stopTime":1546595500799}],"metricId":26,"definitionChangeDate":1553074745838,"definitionChangeMsEpoch":1553074745838,"goalsChangeDate":null,"goalsChangeMsEpoch":null,"goalTimeUpdatedDate":null,"goalTimeUpdatedMsEpoch":null,"metricCreatedDate":null,"updatedDate":1553074858390}');
我的 SQL 查询目前看起来像这样,但我只捕获了第一个元素:
SELECT
CAST(sladata::jsonb -> 'completeSLAData' -> 0 ->> 'succeeded' AS TEXT) AS metric,
COUNT(sladata::jsonb -> 'completeSLAData' -> 0 -> 'succeeded') AS value
FROM
sla_data
GROUP BY
sladata::jsonb -> 'completeSLAData' -> 0 ->> 'succeeded'
解决方案
正如@Bergi 提到的,这样做的方法是使用横向连接。
SELECT succeeded as metric, count(succeeded) as value
FROM (
SELECT id, succeeded
FROM sla_data
CROSS JOIN LATERAL (
SELECT j->> 'succeeded' as succeeded FROM jsonb_array_elements(sladata::jsonb -> 'completeSLAData') a(j)
) AS sub
) AS sub2
GROUP BY succeeded;
metric | value
--------+-------
false | 3
true | 1
如果你自己运行内部查询,你可以看到它在做什么:
SELECT id, succeeded
FROM sla_data
CROSS JOIN LATERAL (
SELECT j->> 'succeeded' as succeeded FROM jsonb_array_elements(sladata::jsonb -> 'completeSLAData') a(j)
) AS sub;
id | succeeded
----+-----------
2 | true
2 | false
3 | false
1 | false
(4 rows)
推荐阅读
- r - 通过 rvest 登录 LinkedIn 的问题
- java - 我无法将“-fx-text-fill:white”设置为外部 css 以设置嵌套在 GridPane 中的文本,该 GridPane 嵌套在 JavaFX 的手风琴中
- java - 如何获取突出显示的节点并在卡片视图中显示它们?
- javascript - 如何遍历对象,仅显示与其所有元素相互的结果
- react-native - React Native - 状态未保存在对象中
- c++ - C++ 如何生成 10,000 个唯一随机整数以存储在 BST 中?
- css - 正确参考文件夹
- python - 无法从 html 模板访问 css 文件
- ios - 在使用 WatchConnectivity 将数据从 WatchOs 传输到 iOs 时,是否有任何代表来监控进度?
- android - 无法为 Android/IOS 应用程序 Ionic 检索 Firebase 云的 FCM 令牌