Ошибка с вложенным набором результатов JSON с самоссылкой "вызовы агрегатных функций не могут быть вложены"
У меня есть следующая схема данных
-- table
master
- id (int)
- meta (jsonb)
- key (string)
-- table
details
- master_id (int)
- timestamp (timestamp)
- value (float)
(Упрощенный)
следующий запрос завершен со следующей ошибкой:
select json_build_object(
'name',m.meta->>'name',
'keys',json_agg(
json_build_object(
'key',m.key,
'checkpoints',json_agg(
json_build_object(
'time',d.timestamp,
'value',d.value)
)
)
)
)
from master m, details d
GROUP by m.meta->>'name',m.key,d.timestamp,d.value
ERROR: aggregate function calls cannot be nested
LINE 6: 'checkpoints',json_agg(
Я хотел бы получить следующую структуру.
[
{"name":"name",
"keys":[
{"key":"mykey",
"checkpoints":[
{"time":"timestamp","value":"1.2"},...]
},...]
}...
]
Я знаю, что ошибка вполне понятна, что я не могу использовать json_agg
вложенный. Но я не знаю, как это решить.
В этом ответе рекомендуется использовать встроенные запросы: вызовы агрегатных функций PostgreSQL не могут быть вложены с помощью функции jsonb_agg.
но у меня это тоже не работает или я что-то упускаю.
Помощь с запросом будет оценена,
РЕДАКТИРОВАТЬ // Обеспечил дБ скрипку с примерами данных и результатов работы, которые еще не включают контрольную точку для каждого датчика.
1 ответ
Прежде чем перейти к запросам, обратите внимание, что я изменил условия соединения. Я полагаю, это правильно присоединиться details
в id / master_id, потому что ваш исходный запрос в dbfiddle, похоже, не дал правильных результатов; ты действительно хочешь {"name":"x32Z72","keys":[{"key":"sensor1"},{"key":"sensor1"},{"key":"sensor1"},{"key":"sensor1"},{"key":"sensor1"},{"key":"sensor1"}]}
когда у вас есть только две записи в details
с идентификатором 1?
Вот два варианта:
1: Не включайтесь в основной запрос, вместо этого выполните подзапрос details
чтобы получить контрольные точки для каждого ключа. Подзапрос стоит сам по себе, поэтому не имеет проблемы вложенного вызова agg.
SELECT json_build_object(
'name', meta->>'name',
'keys', json_agg(
json_build_object(
'key', key,
'checkpoints', (
SELECT json_agg(
json_build_object(
'time', d.timestamp,
'value', d.value
)
)
FROM details d
WHERE master_id = m.id
GROUP BY master_id
)
)
)
)
FROM masters m
GROUP by m.meta->>'name', m.key
https://www.db-fiddle.com/f/2XaUFeTcTfFFUrPYsVnYkt/1
2: Сделайте соединение, но сделайте агги на разных уровнях. Поэтому сначала сделайте агг на самом нижнем / самом внутреннем уровне (контрольные точки), затем у вас есть внешний выбор, чтобы сделать агг более высокого уровня (ключи):
SELECT json_build_object(
'name', name,
'keys', json_agg(
json_build_object(
'key', key,
'checkpoints', checkpoints
)
)
)
FROM (
SELECT
m.meta->>'name' AS name,
m.key,
json_agg(
json_build_object(
'time', d.timestamp,
'value', d.value
)
) AS checkpoints
FROM masters m
INNER JOIN details d ON m.id = d.master_id
GROUP by m.meta->>'name', m.key, d.master_id
) s
GROUP BY name, key
https://www.db-fiddle.com/f/2XaUFeTcTfFFUrPYsVnYkt/2
В любом случае результаты одинаковы:
{"name":"x32Z72","keys":[{"key":"sensor1","checkpoints":[{"time":"2018-10-03T00:00:00+00:00","value":1},{"time":"2018-10-03T01:01:12+00:00","value":1.5},{"time":"2018-10-03T00:10:00+00:00","value":2.1}]}]}
{"name":"x32Z72","keys":[{"key":"sensor2","checkpoints":[{"time":"2018-10-03T02:12:01+00:00","value":0.8},{"time":"2018-10-03T06:10:00+00:00","value":1.8}]}]}
{"name":"x32Z72","keys":[{"key":"sensor3","checkpoints":[{"time":"2018-10-03T01:01:12+00:00","value":0.95}]}]}