Добавить balalaika.sql

This commit is contained in:
2026-07-27 12:02:31 +00:00
parent d63e8739cb
commit 6e46265b09
+407
View File
@@ -0,0 +1,407 @@
-- =============================================================================
-- Отчет повременного учета работоспособности периферийного оборудования
-- Период: май 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 COALESCE(h.name, h.host) not like '%WIMAX'
-- Исключаем оборудование, начинающееся на IRZ (любой регистр)
-- AND UPPER(h.host) NOT LIKE 'IRZ%'
-- Период: май 2026 года (измените под свои даты)
and hinv.notes is not null and hinv.notes <> ''
--and hinv.notes = 'ОБЪЕКТ № 67' --and hinv.name like '%Маршрутизатор%'
and CAST(nullif(regexp_replace(hinv.notes, 'ОБЪЕКТ №\s*', '', 'g'),'') as INTEGER)
--between 1 and 85
in (1,2,4,5,8,9,11,12,14,24,25,27,28,29,30,31,32,34,35,36,38,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,76,77,81,82,84,85)
--AND hx.clock >= EXTRACT(EPOCH FROM TIMESTAMP '2026-06-01 00:00:00')
--AND hx.clock < EXTRACT(EPOCH FROM TIMESTAMP '2026-06-05 00:00:00')
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'
), -- 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('month', to_date(${start_dt}, 'yyyymmdd')) + interval '1 month') 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 DATE(next_ts) > DATE(ts) then date_trunc('day', next_ts) + interval '00:00:00'
else next_ts
end as next_check_time,
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,
next_ts as next_check_time,
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 date_trunc('day', ts) >= to_date(${start_dt}, 'yyyymmdd') and date_trunc('day', ts) <= to_date(${end_dt}, 'yyyymmdd')
), -- 5. Агрегируем каждый непрерывный интервал
grouped_intervals AS (
SELECT
host_name,
visible_name,
equipment_type,
object_number,
coordinates,
max(regexp_replace(object_number, 'ОБЪЕКТ №\s*', '', 'g'))::int as object_num,
MIN(ts) AS time_start,
MAX(next_ts) AS time_end,
MAX(next_check_time) AS time_end_all,
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.time_end_all,
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, object_num
from grouped_intervals
where equipment_type like 'Маршрутизатор%'
group by 1,2,3,4,5,6
) m on m.object_num = v.object_num
where v.equipment_type like 'Видеокамера%'
and time_start_dt = date_trunc('day', v.time_start)
), union_zab as
(
select *
, case
when equipment_type like 'Метеостанция%' then '1'
when equipment_type like 'Видеокамера%' then '2'
when equipment_type like 'Маршрутизатор%' then '3'
when object_num = 38 and equipment_type like 'Детектор транспортных потоков CTfind DTM 1' then 'Детектор транспортных потоков №1'
when object_num = 38 and equipment_type like 'Детектор транспортных потоков CTfind DTM 2' then 'Детектор транспортных потоков №2'
else equipment_type
end as equipment_id
, DATE(time_start) AS date_check
, row_number() over(partition by DATE(time_start), object_num, equipment_type order by time_start desc) as rn
from
(
select * from grouped_intervals where equipment_type not like 'Маршрутизатор%'
union all
select * from router
) u
), sum_interval as
(
select
equipment_id,
object_num,
date_check,
case
when available_hours = '1 day' then '24:00:00'::interval
else available_hours::interval
end as available_hours
from
(
SELECT
equipment_id,
object_num,
date_check,
sum(time_end_all - time_start) AS available_hours
FROM union_zab u
where status = 1
GROUP BY equipment_id, object_num, date_check
) s
), gant as
(
select DATE(date_check) as date_check, object_name, equipment_type, coordinates
, regexp_replace(object_name, 'ОБЪЕКТ №\s*', '', 'g')::int as object_num
, case
when equipment_type like 'Метеостанция%' then '1'
when equipment_type like 'Видеокамера%' then '2'
when equipment_type like 'Роутер%' then '3'
else equipment_type
end as equipment_id
, time_start as sum_hours
, coalesce(LPAD(FLOOR(time_start)::INT::TEXT, 2, '0') || ':' ||
LPAD(FLOOR((time_start- FLOOR(time_start)::INT) * 60)::INT::TEXT, 2, '0') || ':' ||
LPAD(ROUND(((time_start - FLOOR(time_start)::INT) * 60 - FLOOR((time_start- FLOOR(time_start)::INT) * 60)::INT) * 60)::INT::TEXT, 2, '0'), '00:00:00')::interval as aval
from
(
select object_name, equipment_type, d01 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) as date_check from gantt_contractor
union all
select object_name, equipment_type, d02 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '1 day'from gantt_contractor
union all
select object_name, equipment_type, d03 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '2 day'from gantt_contractor
union all
select object_name, equipment_type, d04 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '3 day'from gantt_contractor
union all
select object_name, equipment_type, d05 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '4 day'from gantt_contractor
union all
select object_name, equipment_type, d06 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '5 day'from gantt_contractor
union all
select object_name, equipment_type, d07 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '6 day'from gantt_contractor
union all
select object_name, equipment_type, d08 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '7 day'from gantt_contractor
union all
select object_name, equipment_type, d09 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '8 day'from gantt_contractor
union all
select object_name, equipment_type, d10 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '9 day'from gantt_contractor
union all
select object_name, equipment_type, d11 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '10 day'from gantt_contractor
union all
select object_name, equipment_type, d12 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '11 day'from gantt_contractor
union all
select object_name, equipment_type, d13 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '12 day'from gantt_contractor
union all
select object_name, equipment_type, d14 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '13 day'from gantt_contractor
union all
select object_name, equipment_type, d15 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '14 day'from gantt_contractor
union all
select object_name, equipment_type, d16 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '15 day'from gantt_contractor
union all
select object_name, equipment_type, d17 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '16 day'from gantt_contractor
union all
select object_name, equipment_type, d18 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '17 day'from gantt_contractor
union all
select object_name, equipment_type, d19 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '18 day'from gantt_contractor
union all
select object_name, equipment_type, d20 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '19 day'from gantt_contractor
union all
select object_name, equipment_type, d21 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '20 day'from gantt_contractor
union all
select object_name, equipment_type, d22 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '21 day'from gantt_contractor
union all
select object_name, equipment_type, d23 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '22 day'from gantt_contractor
union all
select object_name, equipment_type, d24 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '23 day'from gantt_contractor
union all
select object_name, equipment_type, d25 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '24 day'from gantt_contractor
union all
select object_name, equipment_type, d26 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '25 day'from gantt_contractor
union all
select object_name, equipment_type, d27 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '26 day'from gantt_contractor
union all
select object_name, equipment_type, d28 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '27 day'from gantt_contractor
union all
select object_name, equipment_type, d29 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '28 day'from gantt_contractor
union all
select object_name, equipment_type, d30 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '29 day'from gantt_contractor
) g
where date_check >= to_date(${start_dt}, 'yyyymmdd') and date_check <= to_date(${end_dt}, 'yyyymmdd')
), gant_interval as
(
select date_check, object_name, equipment_type, object_num, equipment_id, coordinates
, 1 as status, INTERVAL '00:00:00' as time_start_tm, INTERVAL '24:00:00' as time_end_tm
from gant
where sum_hours = 24
union all
select date_check, object_name, equipment_type, object_num, equipment_id, coordinates
, 1 as status, INTERVAL '00:00:00' as time_start_tm, aval::interval as time_end_tm
from gant
where sum_hours > 0 and sum_hours < 24
union all
select date_check, object_name, equipment_type, object_num, equipment_id, coordinates
, 0 as status, aval::interval + INTERVAL '1 second' as time_start_tm, INTERVAL '00:00:00' as time_end_tm
from gant
where sum_hours > 0 and sum_hours < 24
union all
select date_check, object_name, equipment_type, object_num, equipment_id, coordinates
, 0 as status, INTERVAL '00:00:00' as time_start_tm, INTERVAL '24:00:00' as time_end_tm
from gant
where sum_hours = 0
union all
select date_check, object_name, equipment_type, object_num, equipment_id, coordinates
, 0 as status, aval::interval, aval::interval
from gant
where sum_hours is null
), gener as
(
select g.*, i.available_hours, g.time_end_tm - i.available_hours as diff_tm
, case when g.time_end_tm > i.available_hours then 1 else 0 end as diff_fl
from gant_interval g
left join sum_interval i on g.object_num = i.object_num
and g.equipment_id = i.equipment_id
and g.date_check = i.date_check
where abs(extract('minute' from g.time_end_tm - i.available_hours)::int) > 5
and g.status = 1
union all
select g.*, i.available_hours, INTERVAL '00:00:00' as diff_tm, null as diff_fl
from gant_interval g
left join sum_interval i on g.object_num = i.object_num
and g.equipment_id = i.equipment_id
and g.date_check = i.date_check
where i.available_hours is null
), gener_gant_interval as
(
select gi.date_check, g.equipment_id, g.object_num, z.status
, case
when z.status = 1 and z.rn = 1 then z.time_start - DATE_trunc('day', z.time_start) - diff_tm
when z.status = 0 and z.rn = 2 then z.time_start - DATE_trunc('day', z.time_start)
when z.status = 0 and z.rn = 1 then z.time_start - DATE_trunc('day', z.time_start) - diff_tm
when z.status = 1 and z.rn = 2 then z.time_start - DATE_trunc('day', z.time_start)
else z.time_start - DATE_trunc('day', z.time_start)
end as time_start_tm
, case
when z.status = 1 and z.rn = 1 then z.time_end - DATE_trunc('day', z.time_end)
when z.status = 0 and z.rn = 2 then z.time_end - DATE_trunc('day', z.time_end) - diff_tm
when z.status = 0 and z.rn = 1 then z.time_end - DATE_trunc('day', z.time_end)
when z.status = 1 and z.rn = 2 then z.time_end - DATE_trunc('day', z.time_end) - diff_tm
else z.time_end - DATE_trunc('day', z.time_end)
end as time_end_tm
from gener g
join gant_interval gi on g.object_num = gi.object_num and g.equipment_id = gi.equipment_id and g.date_check = gi.date_check
join union_zab z on g.object_num = z.object_num and g.equipment_id = z.equipment_id and g.date_check = z.date_check
where g.diff_fl = 1 --в zabbix <
union
select gi.date_check, g.equipment_id, g.object_num, z.status
, case
when z.status = 1 and z.rn = 1 then z.time_start - DATE_trunc('day', z.time_start) + diff_tm
when z.status = 0 and z.rn = 2 then z.time_start - DATE_trunc('day', z.time_start)
when z.status = 0 and z.rn = 1 then z.time_start - DATE_trunc('day', z.time_start) + diff_tm
when z.status = 1 and z.rn = 2 then z.time_start - DATE_trunc('day', z.time_start)
else z.time_start - DATE_trunc('day', z.time_start)
end as time_start_tm
, case
when z.status = 1 and z.rn = 1 then z.time_end - DATE_trunc('day', z.time_end)
when z.status = 0 and z.rn = 2 then z.time_end - DATE_trunc('day', z.time_end) + diff_tm
when z.status = 0 and z.rn = 1 then z.time_end - DATE_trunc('day', z.time_end)
when z.status = 1 and z.rn = 2 then z.time_end - DATE_trunc('day', z.time_end) + diff_tm
else z.time_end - DATE_trunc('day', z.time_end)
end as time_end_tm
from gener g
join gant_interval gi on g.object_num = gi.object_num and g.equipment_id = gi.equipment_id and g.date_check = gi.date_check
join union_zab z on g.object_num = z.object_num and g.equipment_id = z.equipment_id and g.date_check = z.date_check
where g.diff_fl = 0 --в zabbix >
), main as
(
select g.date_check as date_check
, coalesce(u.object_num, g.object_num) as object_num
, coalesce(u.equipment_id, g.equipment_id) as equipment_id
, coalesce(u.equipment_type, g.equipment_type) as equipment_type
, coalesce(u.object_number, g.object_name) as object_name
, greatest(u.coordinates::varchar, g.coordinates::varchar) as coordinates
from gant g
left join union_zab u on u.object_num = g.object_num
and g.equipment_id = u.equipment_id
group by 1,2,3,4,5,6
)
-- 6. Финальный вывод отчета
SELECT
ROW_NUMBER() OVER (order by m.date_check, m.object_num nulls last, m.equipment_type, u.time_start) AS "№ п/п",
TO_CHAR(DATE(m.date_check), 'DD.MM.YYYY') AS "Дата",
m.equipment_type as "Тип оборудования",
m.object_name as "Номер_объекта_ИТС_РО",
m.coordinates as "Координаты_расположения",
TO_CHAR(u.time_start, 'HH24:MI:SS') AS "Время начала статуса",
TO_CHAR(u.time_end, 'HH24:MI:SS') as "Время окончания статуса",
CASE
WHEN u.status = 1 THEN 'доступно'
ELSE 'недоступно'
END AS "Статус"
FROM main m
join
(
select *
from
(
select gi.date_check, gi.equipment_id, gi.object_num, gi.status, gi.time_start_tm as time_start, gi.time_end_tm as time_end
from gener g
join gant_interval gi on g.object_num = gi.object_num and g.equipment_id = gi.equipment_id and g.date_check = gi.date_check
where g.diff_fl is null
union all
select date_check, equipment_id, object_num, status, time_start_tm, time_end_tm
from gener_gant_interval
union all
select uz.date_check, uz.equipment_id, uz.object_num, uz.status, uz.time_start - DATE_trunc('day', uz.time_start), uz.time_end - DATE_trunc('day', uz.time_start)
from union_zab uz
left join gener_gant_interval ggi on uz.object_num = ggi.object_num and uz.equipment_id = ggi.equipment_id and uz.date_check = ggi.date_check
where ggi.date_check is null
) r
) u on m.object_num = u.object_num and m.equipment_id = u.equipment_id and m.date_check = u.date_check
ORDER BY 1
;