Files
zabbixSql/timeBasedReport.sql
T

188 lines
7.5 KiB
SQL

-- =============================================================================
-- Отчет повременного учета работоспособности периферийного оборудования
-- Период: май 2026
-- Исключены устройства, начинающиеся на IRZ
-- Тип оборудования берется из инвентаризации Zabbix (поле type)
-- Координаты: широта + долгота из полей location_lat и location_lon
-- =============================================================================
WITH
-- 1. Получаем все проверки ICMP за период
checks AS (
SELECT
h.host AS host_name,
COALESCE(h.name, h.host) AS visible_name,
-- Тип оборудования из инвентаризации (поле type), если пусто - берем hardware
COALESCE(hinv."name", 'не указан') AS equipment_type,
-- Номер объекта ИТС РО (храним в поле notes инвентаризации)
COALESCE(hinv.notes, '') AS object_number,
-- Координаты: объединяем широту и долготу через пробел
CASE
WHEN hinv.location_lat IS NOT NULL AND hinv.location_lon IS NOT NULL
AND hinv.location_lat != '' AND hinv.location_lon != ''
THEN hinv.location_lat || ' ' || hinv.location_lon
WHEN hinv.location_lat IS NOT NULL AND hinv.location_lat != ''
THEN hinv.location_lat
WHEN hinv.location_lon IS NOT NULL AND hinv.location_lon != ''
THEN hinv.location_lon
ELSE ''
END AS coordinates,
-- Время проверки с учетом часового пояса
TO_TIMESTAMP(hx.clock) AT TIME ZONE 'Europe/Moscow' AS ts,
-- Статус: 1 = доступно, 0 = недоступно
hx.value AS status
FROM hosts h
INNER JOIN items i
ON i.hostid = h.hostid
AND i.key_ = 'icmpping'
AND i.status = 0
AND i.value_type = 3 -- unsigned numeric
INNER JOIN history_uint hx
ON hx.itemid = i.itemid
LEFT JOIN host_inventory hinv
ON hinv.hostid = h.hostid
WHERE
-- Только мониторимые хосты
h.status = 0
and h.host not like '%WiMAX'
and h.host not like '%DP%'
and h.host not like '%CO%'
--and CAST(nullif(regexp_replace(hinv.notes, 'ОБЪЕКТ №\s*', '', 'g'),'') as INTEGER) = 6
and ((CAST(nullif(regexp_replace(hinv.notes, 'ОБЪЕКТ №\s*', '', 'g'),'') as INTEGER)
in (1,2,4,5,8,9,11,12,14,23,24,25,27,28,29,30,31,32,34,35,36,38,39,40,41,42,43,44,45,46,48,49,50,51,53,54,55,57,58,60,62,63,64,65,66,67,68,69,70,75,76,77,81,82,84,85)
AND TO_TIMESTAMP(hx.clock) >= to_date(${start_dt}, 'yyyymmdd') - interval '1 day'
AND TO_TIMESTAMP(hx.clock) <= to_date(${end_dt}, 'yyyymmdd') + interval '1 day' )
or (CAST(nullif(regexp_replace(hinv.notes, 'ОБЪЕКТ №\s*', '', 'g'),'') as INTEGER)
in (6,10,16,74,78)
AND TO_TIMESTAMP(hx.clock) >= to_date('20260709', 'yyyymmdd') - interval '1 day'
AND TO_TIMESTAMP(hx.clock) <= to_date(${end_dt}, 'yyyymmdd') + interval '1 day' ))
),
-- 2. Добавляем предыдущий статус для определения моментов смены
checks_with_prev AS (
SELECT
*,
LAG(status) OVER (PARTITION BY host_name ORDER BY ts) AS prev_status,
coalesce(lead(ts) OVER (PARTITION BY host_name ORDER BY ts), date_trunc('day', ts) + interval '1 day') AS next_ts
FROM checks
),
--3. Определяем моменты смены статуса (начало нового интервала)
status_changes AS (
SELECT
host_name,
visible_name,
equipment_type,
object_number,
coordinates,
ts,
status,
prev_status,
case
when DATE(next_ts) > DATE(ts) then date_trunc('day', next_ts) + interval '00:00:00'
else next_ts - interval '1 sec'
end as next_ts,
CASE WHEN status != prev_status THEN 1
ELSE 0
END AS is_start
FROM checks_with_prev
union all
SELECT
host_name,
visible_name,
equipment_type,
object_number,
coordinates,
date_trunc('day', next_ts) + interval '00:00:00' as ts,
status,
prev_status,
next_ts - interval '1 sec' as next_ts,
1 as is_start
FROM checks_with_prev
where DATE(next_ts) > DATE(ts)
),
-- 4. Нумеруем интервалы для каждого устройства
intervals AS (
SELECT
*,
SUM(is_start) OVER (PARTITION BY host_name ORDER BY ts) AS interval_id
FROM status_changes
WHERE status IS NOT null
and ((regexp_replace(object_number, 'ОБЪЕКТ №\s*', '', 'g')::INT in (6,10,16,74,78)
AND date_trunc('day', ts) >= to_date('20260709', 'yyyymmdd')
AND date_trunc('day', ts) <= to_date(${end_dt}, 'yyyymmdd'))
or (regexp_replace(object_number, 'ОБЪЕКТ №\s*', '', 'g')::INT not in (6,10,16,74,78) and date_trunc('day', ts) >= to_date(${start_dt}, 'yyyymmdd') and date_trunc('day', ts) <= to_date(${end_dt}, 'yyyymmdd')))
and ts <= now()
),
-- 5. Агрегируем каждый непрерывный интервал
grouped_intervals AS (
SELECT
host_name,
visible_name,
equipment_type,
object_number,
coordinates,
max(case when object_number similar to '%№%' then regexp_replace(object_number, 'ОБЪЕКТ №\s*', '', 'g')::int else null end) as object_num,
MIN(ts) AS time_start,
MAX(next_ts) AS time_end,
MAX(status) AS status
FROM intervals
GROUP BY
host_name,
visible_name,
equipment_type,
object_number,
coordinates,
interval_id
),
-- 5_1. Определение маршрутизатора (заглушка)
router as
(
select
m.host_name,
m.visible_name,
m.equipment_type,
v.object_number,
v.coordinates,
v.object_num,
v.time_start,
v.time_end,
v.status
from grouped_intervals v
join
(
select host_name, visible_name, object_number, equipment_type, date_trunc('day', time_start) as time_start_dt
from grouped_intervals
where equipment_type like 'Маршрутизатор%'
group by 1,2,3,4,5
) m on m.object_number = v.object_number
where v.equipment_type like 'Видеокамера%'
and time_start_dt = date_trunc('day', v.time_start)
)
-- 6. Финальный вывод отчета
SELECT
ROW_NUMBER() OVER (order by object_num nulls last, equipment_type,time_start) AS "№ п/п",
TO_CHAR(DATE(time_start), 'DD.MM.YYYY') AS "Дата",
equipment_type as "Тип оборудования",
case when object_num is null then 'на инвентаризации' else object_number end as "Номер_объекта_ИТС_РО",
coordinates as "Координаты_расположения",
TO_CHAR(time_start, 'HH24:MI:SS') AS "Время начала статуса",
TO_CHAR(time_end, 'HH24:MI:SS') as "Время окончания статуса",
CASE
WHEN status = 1 THEN 'доступно'
ELSE 'недоступно'
END AS "Статус"
FROM
(
select * from grouped_intervals where equipment_type not like 'Маршрутизатор%'
union all
select * from router
) g
ORDER BY 1
;