Запрос данных из пакетов JSON в поле таблицы
Для хранения пакетов используем такую таблицу:
Пакеты хранятся в поле pack_data, они одинаковой структуры для определенного типа записи (поле type_id)
Пакет имеет такую структуру:
[
{"charsetinfo":
{"name": "utf-8"}
},
{"history":
[
{"BOARDID": "TQBR", "TRADEDATE": "2026-09-21", "SHORTNAME": "РоссЮг ао", "SECID": "MRKY", "NUMTRADES": 275, "VALUE": 1541379, "OPEN": 0.07065, "LOW": 0.0695, "HIGH": 0.0716, "LEGALCLOSEPRICE": 0.07015, "WAPRICE": 0.0704, "CLOSE": 0.07055, "VOLUME": 21890000, "MARKETPRICE2": 0.0702, "MARKETPRICE3": 0.0702, "ADMITTEDQUOTE": null, "MP2VALTRD": 766668, "MARKETPRICE3TRADESVALUE": 766668, "ADMITTEDVALUE": null, "WAVAL": 0, "TRADINGSESSION": 3, "CURRENCYID": "SUR", "TRENDCLSPR": 0.21, "TRADE_SESSION_DATE": "2026-09-21"},{"BOARDID": "TQBR", "TRADEDATE": "2026-09-21", "SHORTNAME": "Мостотрест", "SECID": "MSTT", "NUMTRADES": 162, "VALUE": 1539552, "OPEN": 69.4, "LOW": 67.9, "HIGH": 69.4, "LEGALCLOSEPRICE": 67.9, "WAPRICE": 68.5, "CLOSE": 68.35, "VOLUME": 22470, "MARKETPRICE2": 68.45, "MARKETPRICE3": 68.45, "ADMITTEDQUOTE": null, "MP2VALTRD": 1292162.5, "MARKETPRICE3TRADESVALUE": 1292162.5, "ADMITTEDVALUE": null, "WAVAL": 0, "TRADINGSESSION": 3, "CURRENCYID": "SUR", "TRENDCLSPR": -1.51, "TRADE_SESSION_DATE": "2026-09-21"},
...
]
}
]
Нам нужно соединить все пакеты и получить записи из поля "history".
Чтобы развернуть массив из массива history во всех JSON-пакетах одной SQL-выборкой, в PostgreSQL используются функции для работы с JSON/JSONB:
-
Приведение типа: Так как поле
pack_dataимеет типtext, его нужно привести кjsonb(илиjson):pack_data::jsonb. -
jsonb_array_elements: Позволяет «расплющить» (распаковать) элементы JSON-массива в отдельные строки.
SQL-запрос
Поскольку yаш JSON представляет собой массив объектов, где массив history находится во втором элементе (pack_data::jsonb -> 1 -> 'history'), запрос будет выглядеть так:
SELECT u.upload_id,
u.pack_name,
u.upload_time,
-- Извлекаем поля из объектов внутри history
history_item ->> 'SECID' AS secid,
history_item ->> 'SHORTNAME' AS shortname,
history_item ->> 'TRADEDATE' AS tradedate,
(history_item ->> 'OPEN')::numeric AS open_price,
(history_item ->> 'CLOSE')::numeric AS close_price,
(history_item ->> 'VOLUME')::bigint AS volume,
(history_item ->> 'VALUE')::numeric AS value,
history_item ->> 'BOARDID' AS boardid
FROM trading.upload_data u
WHERE u.type_id = 1
-- 1. Извлекаем массив history из второго элемента корня JSON и разворачиваем его по строкам
CROSS JOIN LATERAL jsonb_array_elements(u.pack_data::jsonb -> 1 -> 'history') AS history_item;
Как это работает:
-
u.pack_data::jsonb -> 1— берет второй элемент корневого JSON-массива (индексация с 0, поэтому1указывает на объект{"history": [...]}). -
-> 'history'— переходит непосредственно к массиву цен и сделок. -
jsonb_array_elements(...)— превращает каждый элемент массиваhistoryв отдельную строку результата. -
CROSS JOIN LATERAL— связывает каждую строку из таблицыupload_dataс каждым распакованным элементами из массиваhistory. -
history_item ->> 'FIELD_NAME'— извлекает текстовое значение конкретного ключа из JSON-объекта. -
::numeric,::bigint— сразу приводит текстовые значения JSON к правильным математическим типам PostgreSQL для последующей фильтрации или агрегации.
Альтернатива: Если порядок элементов в корневом JSON может меняться
Если элемент history не всегда гарантированно идет вторым (с индексом 1), безопаснее сначала распаковать корневой массив, а затем найти элемент с ключом history:
SELECT u.upload_id,
history_item ->> 'SECID' AS secid,
history_item ->> 'SHORTNAME' AS shortname,
(history_item ->> 'CLOSE')::numeric AS close_price
FROM trading.upload_data u
WHERE u.type_id = 1
-- Распаковываем корневой массив
CROSS JOIN LATERAL jsonb_array_elements(u.pack_data::jsonb) AS root_elem
-- Распаковываем массив history (игнорируя элементы без этого ключа, например charsetinfo)
CROSS JOIN LATERAL jsonb_array_elements(root_elem -> 'history') AS history_item;
Этот вариант гибче, так как найдет массив history в любом месте структуры пакета.
Что делает оператор: ->>
->> в PostgreSQL используется для извлечения значения из JSON или JSONB в виде обычного текста (text).| Оператор | Что делает | Возвращаемый тип | Назначение |
-> |
Извлекает поле или элемент массива | json или jsonb |
Для дальнейшего навигационного продвижения вглубь структуры JSON |
->> |
Извлекает поле или элемент массива | text |
Для вывода конечных данных, фильтрации в WHERE или приведения типов |
Примеры применения
data с содержимым {"user": {"name": "Иван", "age": 25}}.1. Извлечение поля по ключу
-- Оператор -> возвращает JSON ("Иван" в кавычках)
SELECT data -> 'user' -> 'name';
-- Результат: "Иван" (тип jsonb)
-- Оператор ->> возвращает чистый текст (без кавычек)
SELECT data -> 'user' ->> 'name';
-- Результат: Иван (тип text)
2. Извлечение элемента из JSON-массива по индексу
["apple", "banana", "cherry"]:SELECT data ->> 0;
-- Результат: apple (тип text)
3. Приведение типов для расчетов и фильтрации
->> возвращает обычный text, результат можно легко привести к числу, дате или логическому типу через ::type:-- Извлекаем возраст как число для условия в WHERE
SELECT *
FROM users_table
WHERE (data ->> 'age')::int >= 18;
-- Извлекаем дату и делаем сортировку
SELECT data ->> 'TRADEDATE' AS trade_date
FROM trading.upload_data
ORDER BY (data ->> 'TRADEDATE')::date DESC;
Чек-лист для запоминания
-
Если вы хотите продолжить цепочку погружения в JSON дальше — используйте одиночную стрелку:
data -> 'a' -> 'b'. -
На самом последнем шаге, когда нужно получить конечное значение в виде текста для вывода, используйте двойную стрелку:
data -> 'a' ->> 'b'.

No comments to display
No comments to display