diff --git a/timeBasedReport.sql b/timeBasedReport.sql index d221f12..9356322 100644 --- a/timeBasedReport.sql +++ b/timeBasedReport.sql @@ -11,12 +11,12 @@ WITH -- 1. Получаем все проверки ICMP за период checks AS ( SELECT - h.host AS "Устройство", - COALESCE(h.name, h.host) AS "Видимое имя", + h.host AS host_name, + COALESCE(h.name, h.host) AS visible_name, -- Тип оборудования из инвентаризации (поле type), если пусто - берем hardware - COALESCE(hinv."name", 'не указан') AS "Тип оборудования", + COALESCE(hinv."name", 'не указан') AS equipment_type, -- Номер объекта ИТС РО (храним в поле notes инвентаризации) - COALESCE(hinv.notes, '') AS "Номер_объекта_ИТС_РО", + COALESCE(hinv.notes, '') AS object_number, -- Координаты: объединяем широту и долготу через пробел CASE WHEN hinv.location_lat IS NOT NULL AND hinv.location_lon IS NOT NULL @@ -27,11 +27,11 @@ checks AS ( WHEN hinv.location_lon IS NOT NULL AND hinv.location_lon != '' THEN hinv.location_lon ELSE '' - END AS "Координаты_расположения", + END AS coordinates, -- Время проверки с учетом часового пояса - TO_TIMESTAMP(hx.clock) AT TIME ZONE 'Europe/Moscow' AS "ts", + TO_TIMESTAMP(hx.clock) AT TIME ZONE 'Europe/Moscow' AS ts, -- Статус: 1 = доступно, 0 = недоступно - hx.value AS "status" + hx.value AS status FROM hosts h INNER JOIN items i ON i.hostid = h.hostid @@ -49,100 +49,112 @@ checks AS ( --AND UPPER(h.host) NOT LIKE 'IRZ%' -- Период: май 2026 года (измените под свои даты) --and hinv.notes = 'ОБЪЕКТ № 12' - --and hinv."name" = 'Метеостанция Кондор' + --and hinv."name" = 'Видеокамера Trassir TR-D6254IR15' and CAST(nullif(regexp_replace(hinv.notes, 'ОБЪЕКТ №\s*', '', 'g'),'') as INTEGER) - in (44,77,43,54,27,48,12,49,65,9,60,35,38,1,51,41,53,84,8) - AND hx.clock >= EXTRACT(EPOCH FROM TIMESTAMP '2026-06-01 00:00:00') - AND hx.clock < EXTRACT(EPOCH FROM TIMESTAMP '2026-07-01 00:00:00') + between 1 and 85-- (44,77,43,54,27,48,12,49,65,9,60,35,38,1,51,41,53,84,8) + --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 "Устройство" ORDER BY "ts") AS "prev_status", - Lead("ts") OVER (PARTITION BY "Устройство" ORDER BY "ts")-interval '1 sec' AS "next_ts" + 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 - 1 sec') AS next_ts FROM checks ), - +--select * from ( -- 3. Определяем моменты смены статуса (начало нового интервала) status_changes AS ( SELECT - "Устройство", - "Видимое имя", - "Тип оборудования", - "Номер_объекта_ИТС_РО", - "Координаты_расположения", - "ts", - "status", - "prev_status", + host_name, + visible_name, + equipment_type, + object_number, + coordinates, + ts, + status, + prev_status, case - when DATE("next_ts") > DATE("ts") then date_trunc('day', "ts") + interval '23:59:59' - else "next_ts" - end as "next_ts", - CASE - WHEN "prev_status" IS NULL OR "status" != "prev_status" THEN 1 + when DATE(next_ts) > DATE(ts) then date_trunc('day', ts) + interval '23:59:59' + else next_ts - interval '1 sec' + end as next_ts, + CASE WHEN status != prev_status THEN 1 ELSE 0 - END AS "is_start" + END AS is_start, + case + when DATE(next_ts) > DATE(ts) then 1 + else 0 + end as is_24hh FROM checks_with_prev union all SELECT - "Устройство", - "Видимое имя", - "Тип оборудования", - "Номер_объекта_ИТС_РО", - "Координаты_расположения", - date_trunc('day', "next_ts") + interval '00:00:00' as "ts", - "status", - "prev_status", - "next_ts", - 1 as "is_start" + 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', + 1 as is_start, + 0 as is_24hh FROM checks_with_prev - where DATE("next_ts") > DATE("ts") + where DATE(next_ts) > DATE(ts) --)f where status != prev_status and date_trunc('sec', ts) = date_trunc('sec', next_ts) ), -- 4. Нумеруем интервалы для каждого устройства intervals AS ( SELECT *, - SUM("is_start") OVER (PARTITION BY "Устройство" ORDER BY "ts") AS "interval_id" + SUM(is_start) OVER (PARTITION BY host_name ORDER BY ts) AS interval_id FROM status_changes - WHERE "status" IS NOT NULL + 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 - "Устройство", - "Видимое имя", - "Тип оборудования", - "Номер_объекта_ИТС_РО", - "Координаты_расположения", - MIN("ts") AS "time_start", - MAX("next_ts") AS "time_end", - MAX("status") AS "status" + 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, + MAX(is_24hh) AS is_24hh FROM intervals GROUP BY - "Устройство", - "Видимое имя", - "Тип оборудования", - "Номер_объекта_ИТС_РО", - "Координаты_расположения", - "interval_id" + host_name, + visible_name, + equipment_type, + object_number, + coordinates, + interval_id ) -- 6. Финальный вывод отчета SELECT - ROW_NUMBER() OVER (order by "Номер_объекта_ИТС_РО","Тип оборудования","time_start") AS "№ п/п", - TO_CHAR(DATE("time_start"), 'DD.MM.YYYY') AS "Дата", - "Тип оборудования", - "Номер_объекта_ИТС_РО", - "Координаты_расположения", - TO_CHAR("time_start", 'HH24:MI:SS') AS "Время начала статуса", - TO_CHAR("time_end", 'HH24:MI:SS') AS "Время окончания статуса", + 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, 'yyyy-mm-dd HH24:MI:SS')::varchar AS "Время начала статуса", + case when is_24hh = 1 then TO_CHAR(DATE(time_end), 'yyyy-mm-dd')::varchar || ' 24:00:00' + else time_end::varchar end as "Время окончания статуса", CASE - WHEN "status" = 1 THEN 'доступно' + WHEN status = 1 THEN 'доступно' ELSE 'недоступно' END AS "Статус" FROM grouped_intervals -ORDER BY 4,3,2; \ No newline at end of file +ORDER BY 1 +; \ No newline at end of file