Компонент Alpha.RMap отображает архив Alpha.Historian в виде таблиц PostgreSQL, поэтому историю сигналов можно забирать обычными SQL-запросами: в отчёты, в Excel, в стороннюю аналитику. Здесь есть одна тонкость. Nodes_history — таблица виртуальная. За каждым обращением к ней стоит запрос к серверу истории, и результат зависит от того, как компонент подключён и как записаны условия.
Если из материала «Использование компонента Alpha.RMap» вы узнали, как установить компонент, настроить его и выполнить первые SQL-запросы, то эта статья о том, что осталось за кадром знакомства. Разберём подключение Alpha.RMap к истории, работу со столбцами time и actualtime, выборку за период, последнее значение на момент времени и запрос по нескольким сигналам сразу.
Подключение к истории
Есть два способа получения истории: напрямую с TCP-порта Alpha.Historian (по умолчанию 4949) и через порт доступа к истории модуля TCP Server, работающего в составе Alpha.Server. Использовать нужно второй способ.
При прямом подключении метка времени из условия запроса передаётся в Alpha.Historian в другом бинарном формате, и сервер истории воспринимает верхнюю границу периода не как конец диапазона, а как управляющий параметр чтения архива. В этом случае запрос с условием BETWEEN возвращает одну строку вместо тысяч, выполняется за десятки миллисекунд и не выдаёт ни одной ошибки. Как распознать такое поведение — в конце статьи.
Порт доступа к истории задаётся в Alpha.DevStudio в свойствах модуля TCP Server, группа Настройки доступа к истории, свойство Номер TCP порта:
Через этот же модуль Alpha.RMap обычно уже читает оперативные значения (атрибут SourceTcpPort). Для истории в настройках сервера Alpha.RMap укажите адрес Alpha.Server и порт доступа к истории.
Куда подключён уже настроенный Alpha.RMap, видно прямо из PostgreSQL:
Если в srvoptions значится historiantcpport=4949, то есть порт самого Alpha.Historian, подключение идёт в обход модуля TCP Server. Перенастроить его можно без пересоздания сервера:
Соединение с сервером истории живёт в рамках сессии PostgreSQL. После изменения настроек закройте текущую сессию (в pgAdmin — окно Query Tool) и откройте новую, иначе запросы продолжат уходить по старому адресу.
Таблицы и время
История значений находится в таблице nodes_history, справочник сигналов — в таблице nodes. Типовой запрос соединяет их по паре идентификаторов NodeId и AppId, а сигнал выбирается по имени:
В nodes_history два столбца со временем. Time — метка времени записи в том виде, в каком её запрашивали. ActualTime — действительная метка времени значения. У записей внутри запрошенного периода они совпадают. Различаются они у граничных точек — записей с RecordType со значениями lbound и ubound, которые сервер истории добавляет к выборке за период. У такой записи Time равен границе периода, а ActualTime показывает, когда значение записано на самом деле.
Время в таблицах Alpha.RMap хранится по UTC. Если сервер работает в московском часовом поясе, событие 16:00 по местному времени попадёт в архив с меткой 13:00. Указывайте границы периодов в UTC, а текущее время получайте выражением now() AT TIME ZONE 'UTC'.
Выборка за период
Диапазон по столбцу time задаётся конструкцией BETWEEN:
В выборку попадают все записи периода плюс две граничные точки. В примере ниже период содержит 840 записей, а count возвращает 842: первая строка — lbound с временем ровно 13:16:00, последняя — ubound с временем 13:30:00.
Граничные точки удобны для трендов. Они дают значение сигнала на краях периода, даже если точно в эти секунды записей не было. Когда они не нужны, их можно отфильтровать:
Тот же результат даёт пара строгих неравенств. Она возвращает только записи внутри периода, без граничных точек:
Границы необязательно задавать парой. Условие только с верхней границей вернёт всю историю с начала архива до указанного момента, условие только с нижней — всё от момента до текущего времени:
Если верхняя граница периода оказалась в будущем, выборка ограничится текущим моментом. Архив отдаст всё, что успел накопить.
Последнее значение на момент времени
Частая задача в отчётах — значение сигнала на конец суток или смены. Достаточно верхней границы, обратной сортировки и LIMIT:
Несколько сигналов в одном запросе
Список тегов задаётся обычным IN:
Работает и вариант с массивом: n.TagName = ANY (ARRAY['Parameter', 'Parameter1']::text[]). А когда по каждому сигналу нужны свои условия, например разные периоды, выборки объединяются через UNION ALL.
Если запрос вернул одну строку вместо диапазона
Так проявляет себя подключение в обход модуля TCP Server. Запросы выполняются без ошибок, но результат не совпадает с ожидаемым:
BETWEEN и пара неравенств по time возвращают одну запись или ноль;
условие только с верхней границей отдаёт самую старую запись архива;
ORDER BY h.time DESC LIMIT 1 приносит не последнее значение перед границей, а первое в архиве;
на большом диапазоне ответ приходит за десятки миллисекунд — архив в действительности не читается.
К примеру, вместо 842 записей за период запрос вернул одну граничную точку, у которой actualtime указывает на самую старую запись архива:
Первым делом проверьте подключение через pg_foreign_server и переведите его на порт доступа к истории модуля TCP Server, как описано в начале статьи. Если сделать это прямо сейчас нельзя, помогут обходные приёмы. К примеру, работают условия, в которых верхняя граница не является константой при столбце time:
Надёжное решение при этом одно — правильное подключение: обходные приёмы лишь маскируют проблему, которая продолжит проявляться в других запросах.
Заключение
Работа с историей через Alpha.RMap сводится к нескольким правилам. Подключайте компонент к истории через порт доступа модуля TCP Server, а не напрямую к Alpha.Historian. Задавая границы периодов, помните, что время в таблицах хранится по UTC, а BETWEEN добавляет к выборке граничные точки lbound и ubound. Для выборки по нескольким сигналам используйте IN или ANY, OR либо UNION ALL. И если запрос вернул одну строку вместо диапазона или самую старую запись вместо последней, не ищите проблему в данных, проверьте подключение через pg_foreign_server.
Подробнее в документации: Alpha.RMap 1.7 (ред. 2) > Приложения > Описание таблиц и Alpha.RMap 1.7 (ред. 2) > Приложения > Установка и настройка.