Обновить hardwareAvailabilityReport.sql
Исправления в расчетах Исправления в отображении посуточной статистики
This commit is contained in:
+130
-22
@@ -1,10 +1,14 @@
|
|||||||
WITH
|
WITH
|
||||||
|
-- 1. Получаем все проверки ICMP за период
|
||||||
checks AS (
|
checks AS (
|
||||||
SELECT
|
SELECT
|
||||||
h.host AS host_name,
|
h.host AS host_name,
|
||||||
COALESCE(h.name, h.host) AS visible_name,
|
COALESCE(h.name, h.host) AS visible_name,
|
||||||
COALESCE(hinv.name, 'unknown') AS equipment_type,
|
-- Тип оборудования из инвентаризации (поле type), если пусто - берем hardware
|
||||||
|
COALESCE(hinv."name", 'не указан') AS equipment_type,
|
||||||
|
-- Номер объекта ИТС РО (храним в поле notes инвентаризации)
|
||||||
COALESCE(hinv.notes, '') AS object_number,
|
COALESCE(hinv.notes, '') AS object_number,
|
||||||
|
-- Координаты: объединяем широту и долготу через пробел
|
||||||
CASE
|
CASE
|
||||||
WHEN hinv.location_lat IS NOT NULL AND hinv.location_lon IS NOT NULL
|
WHEN hinv.location_lat IS NOT NULL AND hinv.location_lon IS NOT NULL
|
||||||
AND hinv.location_lat != '' AND hinv.location_lon != ''
|
AND hinv.location_lat != '' AND hinv.location_lon != ''
|
||||||
@@ -15,44 +19,145 @@ checks AS (
|
|||||||
THEN hinv.location_lon
|
THEN hinv.location_lon
|
||||||
ELSE ''
|
ELSE ''
|
||||||
END AS coordinates,
|
END AS coordinates,
|
||||||
|
-- Время проверки с учетом часового пояса
|
||||||
TO_TIMESTAMP(hx.clock) AT TIME ZONE 'Europe/Moscow' AS check_time,
|
TO_TIMESTAMP(hx.clock) AT TIME ZONE 'Europe/Moscow' AS check_time,
|
||||||
|
-- Статус: 1 = доступно, 0 = недоступно
|
||||||
hx.value AS status
|
hx.value AS status
|
||||||
FROM hosts h
|
FROM hosts h
|
||||||
INNER JOIN items i
|
INNER JOIN items i
|
||||||
ON i.hostid = h.hostid
|
ON i.hostid = h.hostid
|
||||||
AND i.key_ = 'icmpping'
|
AND i.key_ = 'icmpping'
|
||||||
AND i.status = 0
|
AND i.status = 0
|
||||||
AND i.value_type = 3
|
AND i.value_type = 3 -- unsigned numeric
|
||||||
INNER JOIN history_uint hx
|
INNER JOIN history_uint hx
|
||||||
ON hx.itemid = i.itemid
|
ON hx.itemid = i.itemid
|
||||||
LEFT JOIN host_inventory hinv
|
LEFT JOIN host_inventory hinv
|
||||||
ON hinv.hostid = h.hostid
|
ON hinv.hostid = h.hostid
|
||||||
WHERE
|
WHERE
|
||||||
|
-- Только мониторимые хосты
|
||||||
h.status = 0
|
h.status = 0
|
||||||
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)
|
-- Исключаем оборудование, начинающееся на IRZ (любой регистр)
|
||||||
--AND UPPER(h.host) NOT LIKE 'IRZ%'
|
--AND UPPER(h.host) NOT LIKE 'IRZ%'
|
||||||
AND hx.clock >= EXTRACT(EPOCH FROM TIMESTAMP '2026-05-25 00:00:00')
|
-- Период: май 2026 года (измените под свои даты)
|
||||||
AND hx.clock < EXTRACT(EPOCH FROM TIMESTAMP '2026-06-01 00:00:00')
|
--and hinv.notes = 'ОБЪЕКТ № 12'
|
||||||
|
--and hinv."name" = 'Видеокамера Trassir TR-D6254IR15'
|
||||||
|
and CAST(nullif(regexp_replace(hinv.notes, 'ОБЪЕКТ №\s*', '', 'g'),'') as INTEGER)
|
||||||
|
between 1 and 85 --in (44,77,43,54,27,48,12,49,65,9,60,35,38,1,51,41,53,84,8)
|
||||||
|
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'
|
||||||
|
--and hinv.notes is null
|
||||||
|
|
||||||
),
|
),
|
||||||
|
|
||||||
daily_stats AS (
|
-- 2. Добавляем предыдущий статус для определения моментов смены
|
||||||
|
checks_with_prev AS (
|
||||||
|
SELECT
|
||||||
|
*,
|
||||||
|
LAG(status) OVER (PARTITION BY host_name ORDER BY check_time) AS prev_status,
|
||||||
|
coalesce(lead(check_time) OVER (PARTITION BY host_name ORDER BY check_time), date_trunc('day', check_time) + interval '1 day - 1 sec') AS next_check_time
|
||||||
|
FROM checks
|
||||||
|
),
|
||||||
|
--select * from (
|
||||||
|
-- 3. Определяем моменты смены статуса (начало нового интервала)
|
||||||
|
status_changes AS (
|
||||||
|
SELECT
|
||||||
|
host_name,
|
||||||
|
visible_name,
|
||||||
|
equipment_type,
|
||||||
|
object_number,
|
||||||
|
coordinates,
|
||||||
|
check_time,
|
||||||
|
status,
|
||||||
|
prev_status,
|
||||||
|
case
|
||||||
|
when DATE(next_check_time) > DATE(check_time) then date_trunc('day', check_time) + interval '23:59:59'
|
||||||
|
else next_check_time - interval '1 sec'
|
||||||
|
end as next_check_time,
|
||||||
|
CASE WHEN status != prev_status THEN 1
|
||||||
|
ELSE 0
|
||||||
|
END AS is_start,
|
||||||
|
case
|
||||||
|
when DATE(next_check_time) > DATE(check_time) then 1
|
||||||
|
else 0
|
||||||
|
end as is_24hh
|
||||||
|
FROM checks_with_prev
|
||||||
|
union all
|
||||||
|
SELECT
|
||||||
|
host_name,
|
||||||
|
visible_name,
|
||||||
|
equipment_type,
|
||||||
|
object_number,
|
||||||
|
coordinates,
|
||||||
|
date_trunc('day', next_check_time) + interval '00:00:00' as check_time,
|
||||||
|
status,
|
||||||
|
prev_status,
|
||||||
|
next_check_time - interval '1 sec',
|
||||||
|
1 as is_start,
|
||||||
|
0 as is_24hh
|
||||||
|
FROM checks_with_prev
|
||||||
|
where DATE(next_check_time) > DATE(check_time) --)f where status != prev_status and date_trunc('sec', ts) = date_trunc('sec', next_check_time)
|
||||||
|
),
|
||||||
|
|
||||||
|
-- 4. Нумеруем интервалы для каждого устройства
|
||||||
|
intervals AS (
|
||||||
|
SELECT
|
||||||
|
*,
|
||||||
|
SUM(is_start) OVER (PARTITION BY host_name ORDER BY check_time) AS interval_id
|
||||||
|
FROM status_changes
|
||||||
|
WHERE status IS NOT null
|
||||||
|
and date_trunc('day', check_time) >= to_date(${start_dt}, 'yyyymmdd') and date_trunc('day', check_time) <= to_date(${end_dt}, 'yyyymmdd')
|
||||||
|
),
|
||||||
|
|
||||||
|
-- 5. Агрегируем каждый непрерывный интервал
|
||||||
|
grouped_intervals AS (
|
||||||
SELECT
|
SELECT
|
||||||
host_name,
|
host_name,
|
||||||
visible_name,
|
visible_name,
|
||||||
equipment_type,
|
equipment_type,
|
||||||
object_number,
|
object_number,
|
||||||
coordinates,
|
coordinates,
|
||||||
DATE(check_time) AS check_date,
|
MIN(date_trunc('second', check_time)) AS check_time,
|
||||||
ROUND((SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) * 60.0) / 3600.0, 2) AS available_hours,
|
MAX(date_trunc('second', next_check_time)) AS next_check_time,
|
||||||
ROUND((SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) * 60.0) / 3600.0, 2) AS unavailable_hours
|
MAX(status) AS status,
|
||||||
FROM checks
|
MAX(is_24hh) AS is_24hh
|
||||||
|
FROM intervals
|
||||||
GROUP BY
|
GROUP BY
|
||||||
host_name,
|
host_name,
|
||||||
visible_name,
|
visible_name,
|
||||||
equipment_type,
|
equipment_type,
|
||||||
object_number,
|
object_number,
|
||||||
coordinates,
|
coordinates,
|
||||||
DATE(check_time)
|
interval_id
|
||||||
|
),
|
||||||
|
|
||||||
|
daily_stats AS (
|
||||||
|
select *,
|
||||||
|
extract('hour' from available_hours)::int AS a_h,
|
||||||
|
extract('minute' from available_hours)::int AS a_m,
|
||||||
|
extract('second' from available_hours)::int AS a_s,
|
||||||
|
extract('hour' from unavailable_hours)::int AS u_h,
|
||||||
|
extract('minute' from unavailable_hours)::int AS u_m,
|
||||||
|
extract('second' from unavailable_hours)::int AS u_s
|
||||||
|
from
|
||||||
|
(
|
||||||
|
SELECT
|
||||||
|
host_name,
|
||||||
|
visible_name,
|
||||||
|
equipment_type,
|
||||||
|
object_number,
|
||||||
|
coordinates,
|
||||||
|
DATE(check_time) AS check_date,
|
||||||
|
sum(case when status = 1 then next_check_time - check_time else null end) AS available_hours,
|
||||||
|
sum(case when status = 0 then next_check_time - check_time else null end) AS unavailable_hours
|
||||||
|
FROM grouped_intervals
|
||||||
|
GROUP BY
|
||||||
|
host_name,
|
||||||
|
visible_name,
|
||||||
|
equipment_type,
|
||||||
|
object_number,
|
||||||
|
coordinates,
|
||||||
|
DATE(check_time)
|
||||||
|
) f
|
||||||
),
|
),
|
||||||
|
|
||||||
daily_graph AS (
|
daily_graph AS (
|
||||||
@@ -61,8 +166,11 @@ daily_graph AS (
|
|||||||
equipment_type,
|
equipment_type,
|
||||||
object_number,
|
object_number,
|
||||||
coordinates,
|
coordinates,
|
||||||
|
max(case when object_number similar to '%№%' then regexp_replace(object_number, 'ОБЪЕКТ №\s*', '', 'g')::int else null end) as object_num,
|
||||||
STRING_AGG(
|
STRING_AGG(
|
||||||
TO_CHAR(check_date, 'DD.MM') || ': Доступно ' || available_hours || 'h, Недоступно ' || unavailable_hours || 'h',
|
TO_CHAR(check_date, 'DD.MM')
|
||||||
|
|| ': Доступно ' || a_h || 'ч.' || a_m || 'м.' || a_s|| 'с.'
|
||||||
|
|| ', Недоступно ' || u_h || 'ч.' || u_m || 'м.' || u_s ||'с.',
|
||||||
'; ' ORDER BY check_date
|
'; ' ORDER BY check_date
|
||||||
) AS daily_schedule
|
) AS daily_schedule
|
||||||
FROM daily_stats
|
FROM daily_stats
|
||||||
@@ -79,8 +187,8 @@ device_summary AS (
|
|||||||
equipment_type,
|
equipment_type,
|
||||||
object_number,
|
object_number,
|
||||||
coordinates,
|
coordinates,
|
||||||
SUM(CASE WHEN available_hours > 12 THEN 1 ELSE 0 END) AS days_available_gt_12h,
|
SUM(CASE WHEN (a_h + a_m/60 + a_s/360) > 12 THEN 1 ELSE 0 END) AS days_available_gt_12h,
|
||||||
SUM(CASE WHEN available_hours <= 12 THEN 1 ELSE 0 END) AS days_unavailable_ge_12h
|
SUM(CASE WHEN (a_h + a_m/60 + a_s/360) <= 12 THEN 1 ELSE 0 END) AS days_unavailable_ge_12h
|
||||||
FROM daily_stats
|
FROM daily_stats
|
||||||
GROUP BY
|
GROUP BY
|
||||||
visible_name,
|
visible_name,
|
||||||
@@ -90,14 +198,14 @@ device_summary AS (
|
|||||||
)
|
)
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
ROW_NUMBER() OVER (ORDER BY dg.equipment_type) AS row_number,
|
ROW_NUMBER() OVER (ORDER BY dg.object_num nulls last, dg.equipment_type) AS "№ п/п",
|
||||||
dg.equipment_type AS equipment_type,
|
dg.equipment_type AS "Тип оборудования",
|
||||||
dg.object_number AS object_number,
|
case when dg.object_num is null then 'на инвентаризации' else dg.object_number end AS "Номер_объекта_ИТС_РО",
|
||||||
dg.coordinates AS coordinates,
|
dg.coordinates AS "Координаты_расположения",
|
||||||
dg.daily_schedule AS daily_schedule,
|
dg.daily_schedule AS "Посуточный график функц оборуд",
|
||||||
ds.days_available_gt_12h AS days_available_more_than_12h,
|
ds.days_available_gt_12h AS "Количество суток доступности",
|
||||||
ds.days_unavailable_ge_12h AS days_unavailable_12h_or_more
|
ds.days_unavailable_ge_12h AS "Количество суток недоступности"
|
||||||
FROM daily_graph dg
|
FROM daily_graph dg
|
||||||
INNER JOIN device_summary ds
|
INNER JOIN device_summary ds
|
||||||
ON ds.visible_name = dg.visible_name
|
ON ds.visible_name = dg.visible_name
|
||||||
ORDER BY dg.object_number;
|
ORDER BY 1;
|
||||||
Reference in New Issue
Block a user