Для разработчиков

Запросы

Запрос в Интеграме — сохранённое декларативное определение: какие колонки, из каких таблиц, с какими условиями, функциями и итогами. Ядро компилирует его в SQL при каждом вызове, а путь между таблицами находит само по метаданным — писать JOIN вручную не нужно.

Один и тот же запрос отдаёт человеку HTML-отчёт, коду — JSON по тому же адресу, ИИ-агенту — данные через MCP; фильтры, сортировка и состав колонок управляются параметрами адреса. Создание запросов командами API разобрано в справочнике API (/api.html#reports), запись данных запросом — на странице «Хранимые процедуры».

Примеры даны для https://ideav.ru и базы mydb; токен в примерах передаётся как в справочнике API — заголовком X-Authorization вместе с параметром JSON.

Что такое запрос

Запрос и его колонки

Запрос — запись таблицы 22, его колонки — записи таблицы 28 с up={id запроса}. У колонки есть источник (таблица или колонка), «Имя в отчёте», функция, фильтр и сортировка; полный разбор полей — в справочнике API (/api.html#report-model).

  • Первая колонка задаёт главную таблицу: строки отчёта — её записи.
  • Колонки связанных таблиц добавляются просто id их колонок — путь по ссылкам ядро находит само (см. «Соединения по метаданным»).
  • GROUP BY строится по всем видимым колонкам без функции.
  • Определение запроса — записи той же базы: запрос создаётся и правится тем же API, что и данные, без выкладки кода, и переносится между базами JSON-файлом.

Адрес вызова

Запрос вызывается командой report — по id или по названию, в адресе регистр не важен: report/intReports и report/intreports — один запрос.

curl -s -H "X-Authorization: $TOKEN" "https://ideav.ru/mydb/report/950?JSON_KV"
curl -s -H "X-Authorization: $TOKEN" "https://ideav.ru/mydb/report/Клиенты%20по%20категориям?JSON_KV&FR_Категория=Клиент"

Без параметра JSON (или JSON_KV, JSON_DATA…) запрос считается переходом браузера и уходит на страницу входа — токен в заголовке тогда не читается.

Форматы ответа

Четыре формата — один адрес

ФорматЧто отдаётКому
— (по умолчанию)HTML-страницу отчётачеловеку в браузере
JSON_KVМассив объектов; ключи — «Имя в отчёте» (t100)интерфейсам и скриптам
JSON_DATAДанные первой строкискалярные выборки «одна запись»
JSONСтроки плюс метаданные: тип, формат и права каждой колонкивнешним клиентам, которые форматируют сами

Даты приходят unix-секундами — метаданные формата из JSON подсказывают, как их показать. Пример ответа JSON_KV — в справочнике API (/api.html#report-run).

Заголовки X-Query-Id и X-Query-Name

Каждый ответ помечается заголовками X-Query-Id и X-Query-Name. Потребитель — дашборд, скрипт, внешняя система — записывает, на каком именно запросе построены его данные: когда определение поменяют, расхождение находится по источнику, а не по симптомам.

Параметры адреса

Фильтры FR_ и TO_

Внешние фильтры передаются по «Имени в отчёте» (t100): FR_{имя} — от, TO_{имя} — до; пробелы в имени заменяются на _. Они перекрывают постоянные фильтры колонок (t102/t103) и работают только на колонках с заполненным именем — колонка без имени снаружи не фильтруется (см. «Права и ограничители»).

# срез за октябрь, первые 50 строк
curl -s -H "X-Authorization: $TOKEN" "https://ideav.ru/mydb/report/951?JSON_KV&FR_Дата=01.10.2026&TO_Дата=31.10.2026&LIMIT=50"
# то же в ссылке для человека: страница отчёта откроется уже отфильтрованной
# https://ideav.ru/mydb/report/951?FR_Дата=01.10.2026&TO_Дата=31.10.2026

Сортировка, пагинация, итоги и состав колонок

ПараметрЧто делает
ORDER={id колонки}Сортировка; минус перед id — по убыванию
LIMIT=NОграничение числа строк (пагинация)
RECORD_COUNTВернуть только число строк
SELECT=имя:ФУНКЦИЯСостав колонок поверх сохранённого
TOTALS=имя:SUMИтог по колонке в ответе

Определение при этом не меняется: один сохранённый запрос обслуживает и полный отчёт, и узкий срез под конкретного потребителя.

Встроенные переменные и _request_

В фильтрах определения (t102/t103) и в формулах работают встроенные переменные; их значения подставляются при каждом вызове.

ПеременнаяЗначение
[TODAY], [NOW], [YESTERDAY], [WEEK_AGO], [MONTH_AGO]Относительные даты
[USER], [USER_ID]Текущий пользователь, его id
[ROLE], [ROLE_ID]Роль вызывающего
_request_.ИмяПараметр адреса: report/950?ProjID=12 читается как _request_.ProjID
[Имя запроса]Значение другого запроса (подзапрос)

Например, скрытая колонка «Ответственный» с фильтром t102=[USER_ID] делает запрос «только свои строки» для каждого вызывающего — и её нельзя перекрыть из адреса, если у неё нет имени в отчёте.

Язык фильтров

Что можно писать в фильтре

Фильтр — не только значение: язык условий один и тот же в t102/t103, в FR_/TO_ и в условии колонки.

ЗначениеОтбирает
ОдобренаРавно значению; у справочной колонки — по названию записи
660 при t104=abn_IDСсылка на запись справочника 660
%…%Маска: подстрока в любом месте
% / !%Непусто / пусто
!1Не равно
IS NULLНет значения
IN(1;2;3)Вхождение в список
~шаблонРегулярное выражение
1.1 и TO_=31.12Диапазон: от и до
[Имя запроса]Подзапрос в условии

Индекс по значению префиксный: маска с % в начале строки (%Иванов) его не использует — на больших таблицах такой фильтр перебирает строки.

Соединения по метаданным

Как ядро находит путь

Пользователь выбирает колонки, ядро само находит путь между таблицами и строит LEFT JOIN без единого условия, написанного рукой. Пути, по которым идёт автосоединение:

  • ссылка «на нас» — колонка главной таблицы указывает на другую таблицу;
  • ссылка «от нас» — другая таблица ссылается на главную;
  • подчинённая таблица — записи с up на запись главной;
  • родитель — переход к таблице владельца.

Несколько ссылок и явный JOIN

Если на одну таблицу ведут несколько ссылок, соединение выбирается по тому, какая ссылочная колонка стоит в отчёте. Подключить таблицу дважды или соединить по произвольному условию можно явным JOIN с псевдонимом.

Производные таблицы: агрегаты не размножаются

Каждая присоединённая таблица, внутри которой агрегат, оформляется производной таблицей со своей группировкой. Поэтому «сумма заявок по компании» не размножается её договорами: соединение считает агрегат отдельно и подставляет готовое значение.

Цепочки одного уровня (Компания ← Заявка ← Договор) так не спасаются — суммы с разных уровней удваиваются. Их считают подзапросами, см. «Подзапросы и рекурсия».

Подзапросы и рекурсия

Сохранённый запрос как подзапрос

Любой сохранённый запрос вкладывается в другой конструкцией [Имя запроса] — в формуле колонки, фильтре, ORDER BY, GROUP BY или HAVING — без ограничения глубины.

Подзапрос без строк возвращает пусто — оберните его в IFNULL(…, 0) или задайте запросу «Если пусто, вернуть» (t113=0). Развёрнутый пример с суммами по цепочке Компания ← Заявка ← Договор — в справочнике API (/api.html#report-subquery).

RECURSIVE: оба вида иерархий

Функция RECURSIVE у первой колонки превращает запрос в рекурсивный CTE. Она умеет оба вида иерархий:

  • дерево по ссылке таблицы на саму себя: «все подразделения ниже данного», категории, BOM;
  • дерево подчинённых записей: «все пункты меню, доступные роли».

Результат возвращается множеством id и вкладывается в другие запросы подзапросом — рекурсивная часть пишется один раз, а используется везде.

Права и ограничители

Чьи права действуют

Запрос работает как хранимая процедура: с правами того, кто его настроил, а не того, кто вызывает. Роли вызывающего нужен только доступ READ к самому запросу — он открывает все колонки и строки, которые отбирает запрос; доступы роли к таблицам и её маски при этом не применяются.

Это не обход прав, а назначение запроса: отдать ровно то, что решил аналитик, в том числе из таблиц, которые роль руками не видит. Внешняя система, которой выдан доступ к одному запросу, видит только его результат и не открывает таблицы.

Фильтруемость — только по имени

  • Снаружи фильтруются только колонки с заполненным «Именем в отчёте»: FR_/TO_ перекрывают их постоянные фильтры.
  • У колонки без имени фильтр параметрами адреса не переопределяется — защита от подмены фильтра вызывающим.
  • Фильтруемость включается явно: всё, чему аналитик не дал имени, закрыто. Это строже правила «фильтровать можно всё, кроме запрещённого».

Не давайте колонке-ограничителю «Имя в отчёте»: с именем её фильтр становится параметром, и вызывающий подставит в FR_ чужой id вместо [USER_ID]. Запись данных запросом и полный разбор прав — на странице Хранимые процедуры →

Кто вызывает запрос

Кнопки в таблицах

Кнопка-колонка вызывает запрос с подстановками из строки — [ID], значения колонок, — поэтому «открыть срез по этой записи» настраивается одной кнопкой. Триггеры и подстановки — на странице Триггеры кнопок →

Дашборды и ИИ-агенты

  • Панели дашбордов и сводные таблицы питаются теми же запросами — без отдельного коннектора с кэшем.
  • MCP-сервер integram-mcp отдаёт агенту инструменты отчётов: выполнение, чтение структуры, создание, колонки, клонирование, умный и естественный поиск нужного запроса.
  • ИИ-чат строит ответ на своём запросе в той же базе.

Агент работает с данными с правами пользователя, от имени которого вызван, — отдельных «агентских» доступов выдавать не нужно.

Лимиты и производительность

Время и объём

  • Запрос ограничен по времени: 30 секунд по умолчанию, до 600; зависшее выполнение снимается принудительно.
  • Списки пагинированы; потолок строк можно задать в самом определении.
  • Выборочный запрос — по ключу, родителю, ссылке — по размеру ответа, а не базы, и не зависит от числа соединений: каждое идёт по индексу.
  • Тяжёлая агрегация по миллионам строк растёт с объёмом: на замере 1 млн транзакций по 45 реквизитам сумма за 90 дней — 28 с на EAV «как есть» и 4,7 с с разрезом и накопителями; карточка по ключу — 3 мс.

Для чистой аналитики больших объёмов штатный путь — накопители или выгрузка в DWH тем же запросом в JSON. Обзор «что умеет движок» с примерами из проектов — в статье Запросы Интеграма (база знаний №28) →