|
@@ -0,0 +1,707 @@
|
|
|
+
|
|
|
+CREATE OR REPLACE VIEW user_error_stats AS
|
|
|
+WITH measurement_counts AS (
|
|
|
+ -- CTE для подсчета общего количества измерений
|
|
|
+ SELECT
|
|
|
+ COUNT(*) AS count,
|
|
|
+ user_id
|
|
|
+ FROM public.measurement_params AS t1
|
|
|
+ INNER JOIN public.measurement_batch AS t2 ON t2.measurement_param_id = t1.id
|
|
|
+ GROUP BY user_id
|
|
|
+),
|
|
|
+error_counts AS (
|
|
|
+ -- CTE для подсчета количества ошибочных данных
|
|
|
+ SELECT
|
|
|
+ COUNT(*) AS error_count,
|
|
|
+ user_id
|
|
|
+ FROM public.measurement_params AS t1
|
|
|
+ INNER JOIN public.measurement_batch AS t2 ON t2.measurement_param_id = t1.id
|
|
|
+ WHERE (public.fn_check_params(height, temperature, pressure, wind_direction, wind_speed, bullet_speed)::public.check_result).is_check = False
|
|
|
+ GROUP BY user_id
|
|
|
+)
|
|
|
+-- Основной запрос, использующий CTE
|
|
|
+SELECT
|
|
|
+ t1.name AS user_name,
|
|
|
+ t2.name AS position,
|
|
|
+ COALESCE(mc.count, 0) AS count,
|
|
|
+ COALESCE(fc.error_count, 0) AS error_count
|
|
|
+FROM public.employees AS t1
|
|
|
+INNER JOIN public.ranks AS t2 ON t1.rank_id = t2.id
|
|
|
+LEFT JOIN measurement_counts AS mc ON mc.user_id = t1.id
|
|
|
+LEFT JOIN error_counts AS fc ON fc.user_id = t1.id
|
|
|
+ORDER BY fc.error_count DESC;
|
|
|
+
|
|
|
+
|
|
|
+--Таблица 3
|
|
|
+-- Создаем таблицу speed_of_average_wind с внешним ключом на calc_height_correction.id
|
|
|
+CREATE TABLE speed_of_average_wind
|
|
|
+(
|
|
|
+ height_id INTEGER PRIMARY KEY REFERENCES calc_height_correction(id), -- Внешний ключ на calc_height_correction
|
|
|
+ distance NUMERIC[], -- Массив для отрицательных значений
|
|
|
+ degree INTEGER
|
|
|
+);
|
|
|
+
|
|
|
+-- Вставляем данные в таблицу speed_of_average_wind, используя id из calc_height_correction
|
|
|
+INSERT INTO CREATE OR REPLACE VIEW employee_measurement_stats AS
|
|
|
+WITH measurement_counts AS (
|
|
|
+ -- CTE для подсчета общего количества измерений
|
|
|
+ SELECT
|
|
|
+ COUNT(*) AS count,
|
|
|
+ user_id
|
|
|
+ FROM public.measurment_input_params AS t1
|
|
|
+ INNER JOIN public.measurment_baths AS t2 ON t2.measurment_input_param_id = t1.id
|
|
|
+ GROUP BY user_id
|
|
|
+),
|
|
|
+error_counts AS (
|
|
|
+ -- CTE для подсчета количества ошибочных данных
|
|
|
+ SELECT
|
|
|
+ COUNT(*) AS fail_count,
|
|
|
+ user_id
|
|
|
+ FROM public.measurment_input_params AS t1
|
|
|
+ INNER JOIN public.measurment_baths AS t2 ON t2.measurment_input_param_id = t1.id
|
|
|
+ WHERE (public.fn_check_input_params(height, temperature, pressure, wind_direction, wind_speed, bullet_demolition_range)::public.check_result).is_check = False
|
|
|
+ GROUP BY user_id
|
|
|
+)
|
|
|
+-- Основной запрос, использующий CTE
|
|
|
+SELECT
|
|
|
+ t1.name AS user_name,
|
|
|
+ t2.description AS position,
|
|
|
+ COALESCE(mc.count, 0) AS count,
|
|
|
+ COALESCE(fc.fail_count, 0) AS fail_count
|
|
|
+FROM public.employees AS t1
|
|
|
+INNER JOIN public.ranks AS t2 ON t1.rank_id = t2.id
|
|
|
+LEFT JOIN measurement_counts AS mc ON mc.user_id = t1.id
|
|
|
+LEFT JOIN error_counts AS fc ON fc.user_id = t1.id
|
|
|
+ORDER BY fc.fail_count DESC;
|
|
|
+
|
|
|
+CREATE TABLE calculation_logs (
|
|
|
+ id SERIAL PRIMARY KEY,
|
|
|
+ input_params JSONB NOT NULL, -- Входные параметры расчета
|
|
|
+ input_params_hash VARCHAR(32) NOT NULL, -- Хэш входных параметров
|
|
|
+ used_table_values JSONB, -- Использованные значения из таблиц с корректировкой
|
|
|
+ intermediate_results JSONB, -- Промежуточные результаты
|
|
|
+ calculation_result JSONB, -- Итоговый результат расчета
|
|
|
+ calculation_timestamp TIMESTAMP DEFAULT NOW() -- Время выполнения расчета
|
|
|
+);
|
|
|
+
|
|
|
+CREATE UNIQUE INDEX idx_calculation_logs_input_params_hash ON calculation_logs (input_params_hash);
|
|
|
+
|
|
|
+CREATE OR REPLACE FUNCTION log_calculation(input_params JSONB, used_table_values JSONB, intermediate_results JSONB, calculation_result JSONB) RETURNS VOID AS $$
|
|
|
+DECLARE
|
|
|
+ input_params_hash TEXT;
|
|
|
+BEGIN
|
|
|
+ -- Генерация хэша входных параметров
|
|
|
+ input_params_hash := md5(input_params::text);
|
|
|
+
|
|
|
+ -- Проверка, был ли уже выполнен расчет с такими параметрами
|
|
|
+ IF EXISTS (SELECT 1 FROM calculation_logs WHERE input_params_hash = input_params_hash) THEN
|
|
|
+ RAISE NOTICE 'Расчет с такими входными параметрами уже был выполнен';
|
|
|
+ ELSE
|
|
|
+ -- Логирование нового расчета
|
|
|
+ INSERT INTO calculation_logs (input_params, input_params_hash, used_table_values, intermediate_results, calculation_result)
|
|
|
+ VALUES (input_params, input_params_hash, used_table_values, intermediate_results, calculation_result);
|
|
|
+
|
|
|
+ RAISE NOTICE 'Расчет успешно залогирован';
|
|
|
+ END IF;
|
|
|
+END;
|
|
|
+$$ LANGUAGE plpgsql;
|
|
|
+
|
|
|
+--Таблица 3
|
|
|
+-- Создаем таблицу speed_of_average_wind с внешним ключом на calc_height_correction.id
|
|
|
+CREATE TABLE speed_of_average_wind
|
|
|
+(
|
|
|
+ height_id INTEGER PRIMARY KEY REFERENCES calc_height_correction(id), -- Внешний ключ на calc_height_correction
|
|
|
+ distance NUMERIC[], -- Массив для отрицательных значений
|
|
|
+ degree INTEGER
|
|
|
+);
|
|
|
+
|
|
|
+-- Вставляем данные в таблицу speed_of_average_wind, используя id из calc_height_correction
|
|
|
+INSERT INTO speed_of_average_wind (height_id, distance, degree)
|
|
|
+VALUES
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 200), ARRAY[3,4,5,6,7,7,8,9,10,11,12,12], 0),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 400), ARRAY[4,5,6,7,8,9,10,11,12,13,14,15], 1),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 800), ARRAY[4,5,6,7,8,9,10,11,13,14,15,16], 2),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 1200), ARRAY[4,5,6,7,8,9,10,11,12,13,14,15,16], 2),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 1600), ARRAY[4,6,7,8,9,10,11,13,14,15,17,17], 3),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 2000), ARRAY[4,6,7,8,9,10,11,13,14,16,17,18], 3),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 2400), ARRAY[4,6,8,9,9,10,12,14,15,16,18,19], 3),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 3000), ARRAY[5,6,8,9,10,11,12,14,15,17,18,19], 4),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 4000), ARRAY[5,6,8,9,10,11,12,14,16,18,19,20], 4);
|
|
|
+
|
|
|
+
|
|
|
+CREATE OR REPLACE FUNCTION calculate_average_wind_speed(
|
|
|
+ par_height NUMERIC,
|
|
|
+ par_bullet_demolition_range NUMERIC
|
|
|
+) RETURNS NUMERIC AS $$
|
|
|
+DECLARE
|
|
|
+ var_speed NUMERIC := 0;
|
|
|
+ var_distance_index INT;
|
|
|
+ var_distance_values NUMERIC[];
|
|
|
+BEGIN
|
|
|
+ -- Если дальность сноса меньше 40 метров, скорость ветра равна 0
|
|
|
+ IF par_bullet_demolition_range < 40 THEN
|
|
|
+ RETURN 0;
|
|
|
+ END IF;
|
|
|
+
|
|
|
+ -- Получаем данные из таблицы для заданной высоты
|
|
|
+ SELECT distance
|
|
|
+ INTO var_distance_values
|
|
|
+ FROM speed_of_average_wind
|
|
|
+ WHERE height = par_height;
|
|
|
+
|
|
|
+ -- Если данные для высоты не найдены, возвращаем 0
|
|
|
+ IF var_distance_values IS NULL THEN
|
|
|
+ RETURN 0;
|
|
|
+ END IF;
|
|
|
+
|
|
|
+ -- Вычисляем индекс на основе дальности сноса
|
|
|
+ var_distance_index := LEAST(GREATEST((par_bullet_demolition_range - 40) / 10, 0), array_length(var_distance_values, 1) - 1);
|
|
|
+
|
|
|
+ -- Получаем скорость ветра по индексу
|
|
|
+ var_speed := var_distance_values[var_distance_index + 1]; -- Индексы в массиве начинаются с 1
|
|
|
+
|
|
|
+ RETURN var_speed;
|
|
|
+END;
|
|
|
+$$ LANGUAGE plpgsql;
|
|
|
+
|
|
|
+CREATE OR REPLACE FUNCTION calculate_average_wind_direction(
|
|
|
+ par_height NUMERIC,
|
|
|
+ par_ground_wind_direction NUMERIC
|
|
|
+) RETURNS NUMERIC AS $$
|
|
|
+DECLARE
|
|
|
+ var_direction_increment NUMERIC;
|
|
|
+BEGIN
|
|
|
+ -- Получаем приращение направления ветра из таблицы
|
|
|
+ SELECT degree
|
|
|
+ INTO var_direction_increment
|
|
|
+ FROM speed_of_average_wind
|
|
|
+ WHERE height = par_height;
|
|
|
+
|
|
|
+ -- Если данные для высоты не найдены, возвращаем направление приземного ветра
|
|
|
+ IF var_direction_increment IS NULL THEN
|
|
|
+ RETURN par_ground_wind_direction;
|
|
|
+ END IF;
|
|
|
+
|
|
|
+ -- Рассчитываем среднее направление ветра
|
|
|
+ RETURN par_ground_wind_direction + var_direction_increment;
|
|
|
+END;
|
|
|
+$$ LANGUAGE plpgsql;
|
|
|
+
|
|
|
+CREATE OR REPLACE FUNCTION calculate_wind_gun_corrections(
|
|
|
+ IN par_height NUMERIC,
|
|
|
+ IN par_temperature NUMERIC,
|
|
|
+ IN par_pressure NUMERIC,
|
|
|
+ IN par_wind_direction NUMERIC,
|
|
|
+ IN par_wind_speed NUMERIC,
|
|
|
+ IN par_bullet_demolition_range NUMERIC,
|
|
|
+ OUT deviation_pressure NUMERIC,
|
|
|
+ OUT deviation_temperature NUMERIC,
|
|
|
+ OUT average_wind_speed NUMERIC,
|
|
|
+ OUT average_wind_direction NUMERIC
|
|
|
+) AS $$
|
|
|
+BEGIN
|
|
|
+ -- Отклонение наземного давления
|
|
|
+ deviation_pressure := public.fn_calc_header_pressure(par_pressure);
|
|
|
+
|
|
|
+ -- Отклонение приземной виртуальной температуры
|
|
|
+ deviation_temperature := public.fn_calc_header_temperature(par_temperature);
|
|
|
+
|
|
|
+ -- Средняя скорость ветра
|
|
|
+ average_wind_speed := calculate_average_wind_speed(par_height, par_bullet_demolition_range);
|
|
|
+
|
|
|
+ -- Среднее направление ветра
|
|
|
+ average_wind_direction := calculate_average_wind_direction(par_height, par_wind_direction);
|
|
|
+END;
|
|
|
+$$ LANGUAGE plpgsql;
|
|
|
+
|
|
|
+
|
|
|
+DO $$
|
|
|
+DECLARE
|
|
|
+ -- Входные параметры
|
|
|
+ var_height NUMERIC := 200; -- Высота (в метрах)
|
|
|
+ var_temperature NUMERIC := 10; -- Температура (в градусах Цельсия)
|
|
|
+ var_pressure NUMERIC := 740; -- Давление (в мм рт. ст.)
|
|
|
+ var_wind_direction NUMERIC := 30; -- Направление приземного ветра (в градусах)
|
|
|
+ var_wind_speed NUMERIC := 5; -- Скорость приземного ветра (в м/с)
|
|
|
+ var_bullet_demolition_range NUMERIC := 80; -- Дальность сноса ветровых пуль (в метрах)
|
|
|
+
|
|
|
+ -- Выходные параметры
|
|
|
+ var_deviation_pressure NUMERIC; -- Отклонение наземного давления
|
|
|
+ var_deviation_temperature NUMERIC; -- Отклонение приземной виртуальной температуры
|
|
|
+ var_average_wind_speed NUMERIC; -- Средняя скорость ветра
|
|
|
+ var_average_wind_direction NUMERIC; -- Среднее направление ветра
|
|
|
+BEGIN
|
|
|
+ -- Вызов основной функции расчета
|
|
|
+ SELECT * INTO var_deviation_pressure, var_deviation_temperature, var_average_wind_speed, var_average_wind_direction
|
|
|
+ FROM calculate_wind_gun_corrections(
|
|
|
+ var_height,
|
|
|
+ var_temperature,
|
|
|
+ var_pressure,
|
|
|
+ var_wind_direction,
|
|
|
+ var_wind_speed,
|
|
|
+ var_bullet_demolition_range
|
|
|
+ );
|
|
|
+
|
|
|
+ -- Вывод результатов
|
|
|
+ RAISE NOTICE '==============================';
|
|
|
+ RAISE NOTICE 'Результаты расчета:';
|
|
|
+ RAISE NOTICE 'Отклонение наземного давления: % мм рт. ст.', var_deviation_pressure;
|
|
|
+ RAISE NOTICE 'Отклонение приземной виртуальной температуры: % °C', var_deviation_temperature;
|
|
|
+ RAISE NOTICE 'Средняя скорость ветра: % м/с', var_average_wind_speed;
|
|
|
+ RAISE NOTICE 'Среднее направление ветра: % градусов', var_average_wind_direction;
|
|
|
+ RAISE NOTICE '==============================';
|
|
|
+END $$;
|
|
|
+
|
|
|
+
|
|
|
+-- Индексы для таблицы ranks
|
|
|
+CREATE INDEX idx_ranks_id ON public.ranks (id);
|
|
|
+
|
|
|
+-- Индексы для таблицы employees
|
|
|
+CREATE INDEX idx_employees_id ON public.employees (id);
|
|
|
+CREATE INDEX idx_employees_rank_id ON public.employees (rank_id);
|
|
|
+
|
|
|
+-- Индексы для таблицы measurment_types
|
|
|
+CREATE INDEX idx_measurment_types_id ON public.measurment_types (id);
|
|
|
+
|
|
|
+-- Индексы для таблицы measurment_input_params
|
|
|
+CREATE INDEX idx_measurment_input_params_id ON public.measurment_input_params (id);
|
|
|
+CREATE INDEX idx_measurment_input_params_measurment_type_id ON public.measurment_input_params (measurment_type_id);
|
|
|
+
|
|
|
+-- Индексы для таблицы measurment_baths
|
|
|
+CREATE INDEX idx_measurment_baths_id ON public.measurment_baths (id);
|
|
|
+CREATE INDEX idx_measurment_baths_user_id ON public.measurment_baths (user_id);
|
|
|
+CREATE INDEX idx_measurment_baths_measurment_input_param_id ON public.measurment_baths (measurment_input_param_id);
|
|
|
+
|
|
|
+-- Индексы для таблицы measurment_settings
|
|
|
+CREATE INDEX idx_measurment_settings_key ON public.measurment_settings (key);
|
|
|
+
|
|
|
+-- Индексы для таблицы calc_height_correction
|
|
|
+CREATE INDEX idx_calc_height_correction_id ON public.calc_height_correction (id);
|
|
|
+CREATE INDEX idx_calc_height_correction_measurment_type_id ON public.calc_height_correction (measurment_type_id);
|
|
|
+
|
|
|
+-- Индексы для таблицы calc_temperature_height_correction
|
|
|
+CREATE INDEX idx_calc_temperature_height_correction_id ON public.calc_temperature_height_correction (id);
|
|
|
+CREATE INDEX idx_calc_temperature_height_correction_calc_height_id ON public.calc_temperature_height_correction (calc_height_id);
|
|
|
+CREATE INDEX idx_calc_temperature_height_correction_calc_temperature_header_id ON public.calc_temperature_height_correction (calc_temperature_header_id);
|
|
|
+
|
|
|
+-- Индексы для таблицы calc_header_correction
|
|
|
+CREATE INDEX idx_calc_header_correction_id ON public.calc_header_correction (id);
|
|
|
+CREATE INDEX idx_calc_header_correction_measurment_type_id ON public.calc_header_correction (measurment_type_id);
|
|
|
+
|
|
|
+-- Индексы для таблицы speed_of_average_wind
|
|
|
+CREATE INDEX idx_speed_of_average_wind_height ON public.speed_of_average_wind (height);
|
|
|
+
|
|
|
+
|
|
|
+CREATE OR REPLACE VIEW effective_measurement_height AS
|
|
|
+WITH measurement_stats AS (
|
|
|
+ -- CTE для подсчета общего количества измерений и количества ошибочных измерений
|
|
|
+ SELECT
|
|
|
+ e.id AS employee_id,
|
|
|
+ e.name AS user_name,
|
|
|
+ mr.description AS rank,
|
|
|
+ COUNT(mb.id) AS total_measurements,
|
|
|
+ SUM(CASE WHEN (public.fn_check_input_params(mip.height, mip.temperature, mip.pressure, mip.wind_direction, mip.wind_speed, mip.bullet_demolition_range)).is_check = False THEN 1 ELSE 0 END) AS error_count
|
|
|
+ FROM
|
|
|
+ public.employees e
|
|
|
+ INNER JOIN
|
|
|
+ public.ranks mr ON e.rank_id = mr.id
|
|
|
+ INNER JOIN
|
|
|
+ public.measurment_baths mb ON e.id = mb.user_id
|
|
|
+ INNER JOIN
|
|
|
+ public.measurment_input_params mip ON mb.measurment_input_param_id = mip.id
|
|
|
+ GROUP BY
|
|
|
+ e.id, e.name, mr.description
|
|
|
+)
|
|
|
+-- Основной запрос, использующий CTE
|
|
|
+SELECT
|
|
|
+ ms.user_name AS "ФИО пользователя",
|
|
|
+ ms.rank AS "Звание",
|
|
|
+ MIN(mip.height) AS "Мин. высота метеопоста",
|
|
|
+ MAX(mip.height) AS "Макс. высота метеопоста",
|
|
|
+ ms.total_measurements AS "Всего измерений",
|
|
|
+ ms.error_count AS "Из них ошибочны"
|
|
|
+FROM
|
|
|
+ measurement_stats ms
|
|
|
+INNER JOIN
|
|
|
+ public.measurment_baths mb ON ms.employee_id = mb.user_id
|
|
|
+INNER JOIN
|
|
|
+ public.measurment_input_params mip ON mb.measurment_input_param_id = mip.id
|
|
|
+WHERE
|
|
|
+ ms.total_measurements >= 5 AND ms.error_count < 10
|
|
|
+GROUP BY
|
|
|
+ ms.user_name, ms.rank, ms.total_measurements, ms.error_count
|
|
|
+ORDER BY
|
|
|
+ ms.error_count;
|
|
|
+
|
|
|
+
|
|
|
+CREATE OR REPLACE VIEW most_common_measurement_errors AS
|
|
|
+WITH log_data_text AS (
|
|
|
+ -- Извлекаем данные из JSON-логов как текст
|
|
|
+ SELECT
|
|
|
+ cl.id AS log_id,
|
|
|
+ cl.input_params->>'height' AS height_text,
|
|
|
+ cl.input_params->>'temperature' AS temperature_text,
|
|
|
+ cl.input_params->>'pressure' AS pressure_text,
|
|
|
+ cl.input_params->>'wind_direction' AS wind_direction_text,
|
|
|
+ cl.input_params->>'wind_speed' AS wind_speed_text,
|
|
|
+ cl.input_params->>'bullet_demolition_range' AS bullet_demolition_range_text,
|
|
|
+ cl.calculation_timestamp AS log_time
|
|
|
+ FROM
|
|
|
+ calculation_logs cl
|
|
|
+),
|
|
|
+log_data AS (
|
|
|
+ -- Конвертируем текстовые данные в numeric с обработкой null
|
|
|
+ SELECT
|
|
|
+ log_id,
|
|
|
+ coalesce(height_text, '0')::numeric AS height,
|
|
|
+ coalesce(temperature_text, '0')::numeric AS temperature,
|
|
|
+ coalesce(pressure_text, '0')::numeric AS pressure,
|
|
|
+ coalesce(wind_direction_text, '0')::numeric AS wind_direction,
|
|
|
+ coalesce(wind_speed_text, '0')::numeric AS wind_speed,
|
|
|
+ coalesce(bullet_demolition_range_text, '0')::numeric AS bullet_demolition_range,
|
|
|
+ log_time
|
|
|
+ FROM
|
|
|
+ log_data_text
|
|
|
+),
|
|
|
+error_data AS (
|
|
|
+ -- Проверяем данные на ошибки
|
|
|
+ SELECT
|
|
|
+ ld.*,
|
|
|
+ (public.fn_check_input_params(
|
|
|
+ ld.height,
|
|
|
+ ld.temperature,
|
|
|
+ ld.pressure,
|
|
|
+ ld.wind_direction,
|
|
|
+ ld.wind_speed,
|
|
|
+ ld.bullet_demolition_range
|
|
|
+ )).error_message AS error_message
|
|
|
+ FROM
|
|
|
+ log_data ld
|
|
|
+ WHERE
|
|
|
+ (public.fn_check_input_params(
|
|
|
+ ld.height,
|
|
|
+ ld.temperature,
|
|
|
+ ld.pressure,
|
|
|
+ ld.wind_direction,
|
|
|
+ ld.wind_speed,
|
|
|
+ ld.bullet_demolition_range
|
|
|
+ )).is_check = False
|
|
|
+),
|
|
|
+error_counts AS (
|
|
|
+ -- Группируем ошибки по типу и собираем пользователей
|
|
|
+ SELECT
|
|
|
+ ed.error_message,
|
|
|
+ COUNT(*) AS error_count,
|
|
|
+ STRING_AGG(DISTINCT e.name, ', ') AS users_list
|
|
|
+ FROM
|
|
|
+ error_data ed
|
|
|
+ INNER JOIN
|
|
|
+ measurment_baths mb ON ed.log_id = mb.measurment_input_param_id
|
|
|
+ INNER JOIN
|
|
|
+ employees e ON mb.user_id = e.id
|
|
|
+ GROUP BY
|
|
|
+ ed.error_message
|
|
|
+)
|
|
|
+-- Основной запрос, формирующий отчет
|
|
|
+SELECT
|
|
|
+ error_message AS "Наименование ошибки",
|
|
|
+ error_count AS "Количество ошибок",
|
|
|
+ users_list AS "Список пользователей, которые допустили ошибку"
|
|
|
+FROM
|
|
|
+ error_counts
|
|
|
+ORDER BY
|
|
|
+ error_count DESC; (height_id, distance, degree)
|
|
|
+VALUES
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 200), ARRAY[3,4,5,6,7,7,8,9,10,11,12,12], 0),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 400), ARRAY[4,5,6,7,8,9,10,11,12,13,14,15], 1),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 800), ARRAY[4,5,6,7,8,9,10,11,13,14,15,16], 2),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 1200), ARRAY[4,5,6,7,8,9,10,11,12,13,14,15,16], 2),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 1600), ARRAY[4,6,7,8,9,10,11,13,14,15,17,17], 3),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 2000), ARRAY[4,6,7,8,9,10,11,13,14,16,17,18], 3),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 2400), ARRAY[4,6,8,9,9,10,12,14,15,16,18,19], 3),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 3000), ARRAY[5,6,8,9,10,11,12,14,15,17,18,19], 4),
|
|
|
+ ((SELECT id FROM calc_height_correction WHERE height = 4000), ARRAY[5,6,8,9,10,11,12,14,16,18,19,20], 4);
|
|
|
+
|
|
|
+
|
|
|
+CREATE OR REPLACE FUNCTION calc_avg_wind_speed(
|
|
|
+ par_height NUMERIC,
|
|
|
+ par_bullet_speed NUMERIC
|
|
|
+) RETURNS NUMERIC AS $$
|
|
|
+DECLARE
|
|
|
+ var_speed NUMERIC := 0;
|
|
|
+ var_distance_index INT;
|
|
|
+ var_distance_values NUMERIC[];
|
|
|
+BEGIN
|
|
|
+ -- Если дальность сноса меньше 40 метров, скорость ветра равна 0
|
|
|
+ IF par_bullet_speed < 40 THEN
|
|
|
+ RETURN 0;
|
|
|
+ END IF;
|
|
|
+
|
|
|
+ -- Получаем данные из таблицы для заданной высоты
|
|
|
+ SELECT distance
|
|
|
+ INTO var_distance_values
|
|
|
+ FROM speed_of_average_wind
|
|
|
+ WHERE height = par_height;
|
|
|
+
|
|
|
+ -- Если данные для высоты не найдены, возвращаем 0
|
|
|
+ IF var_distance_values IS NULL THEN
|
|
|
+ RETURN 0;
|
|
|
+ END IF;
|
|
|
+
|
|
|
+ -- Вычисляем индекс на основе дальности сноса
|
|
|
+ var_distance_index := LEAST(GREATEST((par_bullet_speed - 40) / 10, 0), array_length(var_distance_values, 1) - 1);
|
|
|
+
|
|
|
+ -- Получаем скорость ветра по индексу
|
|
|
+ var_speed := var_distance_values[var_distance_index + 1]; -- Индексы в массиве начинаются с 1
|
|
|
+
|
|
|
+ RETURN var_speed;
|
|
|
+END;
|
|
|
+$$ LANGUAGE plpgsql;
|
|
|
+
|
|
|
+CREATE OR REPLACE FUNCTION calc_avg_wind_dir(
|
|
|
+ par_height NUMERIC,
|
|
|
+ par_ground_wind_direction NUMERIC
|
|
|
+) RETURNS NUMERIC AS $$
|
|
|
+DECLARE
|
|
|
+ var_direction_increment NUMERIC;
|
|
|
+BEGIN
|
|
|
+ -- Получаем приращение направления ветра из таблицы
|
|
|
+ SELECT degree
|
|
|
+ INTO var_direction_increment
|
|
|
+ FROM speed_of_average_wind
|
|
|
+ WHERE height = par_height;
|
|
|
+
|
|
|
+ -- Если данные для высоты не найдены, возвращаем направление приземного ветра
|
|
|
+ IF var_direction_increment IS NULL THEN
|
|
|
+ RETURN par_ground_wind_direction;
|
|
|
+ END IF;
|
|
|
+
|
|
|
+ -- Рассчитываем среднее направление ветра
|
|
|
+ RETURN par_ground_wind_direction + var_direction_increment;
|
|
|
+END;
|
|
|
+$$ LANGUAGE plpgsql;
|
|
|
+
|
|
|
+CREATE OR REPLACE FUNCTION calculate_wind_gun_corrections(
|
|
|
+ IN par_height NUMERIC,
|
|
|
+ IN par_temperature NUMERIC,
|
|
|
+ IN par_pressure NUMERIC,
|
|
|
+ IN par_wind_direction NUMERIC,
|
|
|
+ IN par_wind_speed NUMERIC,
|
|
|
+ IN par_bullet_speed NUMERIC,
|
|
|
+ OUT deviation_pressure NUMERIC,
|
|
|
+ OUT deviation_temperature NUMERIC,
|
|
|
+ OUT average_wind_speed NUMERIC,
|
|
|
+ OUT average_wind_direction NUMERIC
|
|
|
+) AS $$
|
|
|
+BEGIN
|
|
|
+ -- Отклонение наземного давления
|
|
|
+ deviation_pressure := public.fn_calc_header_pressure(par_pressure);
|
|
|
+
|
|
|
+ -- Отклонение приземной виртуальной температуры
|
|
|
+ deviation_temperature := public.fn_calc_header_temperature(par_temperature);
|
|
|
+
|
|
|
+ -- Средняя скорость ветра
|
|
|
+ average_wind_speed := calc_avg_wind_speed(par_height, par_bullet_speed);
|
|
|
+
|
|
|
+ -- Среднее направление ветра
|
|
|
+ average_wind_direction := calc_avg_wind_dir(par_height, par_wind_direction);
|
|
|
+END;
|
|
|
+$$ LANGUAGE plpgsql;
|
|
|
+
|
|
|
+
|
|
|
+DO $$
|
|
|
+DECLARE
|
|
|
+ -- Входные параметры
|
|
|
+ var_height NUMERIC := 200; -- Высота (в метрах)
|
|
|
+ var_temperature NUMERIC := 10; -- Температура (в градусах Цельсия)
|
|
|
+ var_pressure NUMERIC := 740; -- Давление (в мм рт. ст.)
|
|
|
+ var_wind_direction NUMERIC := 30; -- Направление приземного ветра (в градусах)
|
|
|
+ var_wind_speed NUMERIC := 5; -- Скорость приземного ветра (в м/с)
|
|
|
+ var_bullet_speed NUMERIC := 80; -- Дальность сноса ветровых пуль (в метрах)
|
|
|
+
|
|
|
+ -- Выходные параметры
|
|
|
+ var_deviation_pressure NUMERIC; -- Отклонение наземного давления
|
|
|
+ var_deviation_temperature NUMERIC; -- Отклонение приземной виртуальной температуры
|
|
|
+ var_average_wind_speed NUMERIC; -- Средняя скорость ветра
|
|
|
+ var_average_wind_direction NUMERIC; -- Среднее направление ветра
|
|
|
+BEGIN
|
|
|
+ -- Вызов основной функции расчета
|
|
|
+ SELECT * INTO var_deviation_pressure, var_deviation_temperature, var_average_wind_speed, var_average_wind_direction
|
|
|
+ FROM calculate_wind_gun_corrections(
|
|
|
+ var_height,
|
|
|
+ var_temperature,
|
|
|
+ var_pressure,
|
|
|
+ var_wind_direction,
|
|
|
+ var_wind_speed,
|
|
|
+ var_bullet_speed
|
|
|
+ );
|
|
|
+
|
|
|
+ -- Вывод результатов
|
|
|
+ RAISE NOTICE '==============================';
|
|
|
+ RAISE NOTICE 'Результаты расчета:';
|
|
|
+ RAISE NOTICE 'Отклонение наземного давления: % мм рт. ст.', var_deviation_pressure;
|
|
|
+ RAISE NOTICE 'Отклонение приземной виртуальной температуры: % °C', var_deviation_temperature;
|
|
|
+ RAISE NOTICE 'Средняя скорость ветра: % м/с', var_average_wind_speed;
|
|
|
+ RAISE NOTICE 'Среднее направление ветра: % градусов', var_average_wind_direction;
|
|
|
+ RAISE NOTICE '==============================';
|
|
|
+END $$;
|
|
|
+
|
|
|
+
|
|
|
+-- Индексы для таблицы ranks
|
|
|
+CREATE INDEX idx_ranks_id ON public.ranks (id);
|
|
|
+
|
|
|
+-- Индексы для таблицы employees
|
|
|
+CREATE INDEX idx_employees_id ON public.employees (id);
|
|
|
+CREATE INDEX idx_employees_rank_id ON public.employees (rank_id);
|
|
|
+
|
|
|
+-- Индексы для таблицы measurment_types
|
|
|
+CREATE INDEX idx_measurment_types_id ON public.measurment_types (id);
|
|
|
+
|
|
|
+-- Индексы для таблицы measurement_params
|
|
|
+CREATE INDEX idx_measurement_params_id ON public.measurement_params (id);
|
|
|
+CREATE INDEX idx_measurement_params_measurment_type_id ON public.measurement_params (measurment_type_id);
|
|
|
+
|
|
|
+-- Индексы для таблицы measurement_batch
|
|
|
+CREATE INDEX idx_measurement_batch_id ON public.measurement_batch (id);
|
|
|
+CREATE INDEX idx_measurement_batch_user_id ON public.measurement_batch (user_id);
|
|
|
+CREATE INDEX idx_measurement_batch_measurement_param_id ON public.measurement_batch (measurement_param_id);
|
|
|
+
|
|
|
+-- Индексы для таблицы measurment_settings
|
|
|
+CREATE INDEX idx_measurment_settings_key ON public.measurment_settings (key);
|
|
|
+
|
|
|
+-- Индексы для таблицы calc_height_correction
|
|
|
+CREATE INDEX idx_calc_height_correction_id ON public.calc_height_correction (id);
|
|
|
+CREATE INDEX idx_calc_height_correction_measurment_type_id ON public.calc_height_correction (measurment_type_id);
|
|
|
+
|
|
|
+-- Индексы для таблицы calc_temperature_height_correction
|
|
|
+CREATE INDEX idx_calc_temperature_height_correction_id ON public.calc_temperature_height_correction (id);
|
|
|
+CREATE INDEX idx_calc_temperature_height_correction_calc_height_id ON public.calc_temperature_height_correction (calc_height_id);
|
|
|
+CREATE INDEX idx_calc_temperature_height_correction_calc_temperature_header_id ON public.calc_temperature_height_correction (calc_temperature_header_id);
|
|
|
+
|
|
|
+-- Индексы для таблицы calc_header_correction
|
|
|
+CREATE INDEX idx_calc_header_correction_id ON public.calc_header_correction (id);
|
|
|
+CREATE INDEX idx_calc_header_correction_measurment_type_id ON public.calc_header_correction (measurment_type_id);
|
|
|
+
|
|
|
+-- Индексы для таблицы speed_of_average_wind
|
|
|
+CREATE INDEX idx_speed_of_average_wind_height ON public.speed_of_average_wind (height);
|
|
|
+
|
|
|
+
|
|
|
+CREATE OR REPLACE VIEW effective_measurement_height AS
|
|
|
+WITH measurement_stats AS (
|
|
|
+ -- CTE для подсчета общего количества измерений и количества ошибочных измерений
|
|
|
+ SELECT
|
|
|
+ e.id AS employee_id,
|
|
|
+ e.name AS user_name,
|
|
|
+ mr.description AS rank,
|
|
|
+ COUNT(mb.id) AS total_measurements,
|
|
|
+ SUM(CASE WHEN (public.fn_check_params(mip.height, mip.temperature, mip.pressure, mip.wind_direction, mip.wind_speed, mip.bullet_speed)).is_check = False THEN 1 ELSE 0 END) AS error_count
|
|
|
+ FROM
|
|
|
+ public.employees e
|
|
|
+ INNER JOIN
|
|
|
+ public.ranks mr ON e.rank_id = mr.id
|
|
|
+ INNER JOIN
|
|
|
+ public.measurement_batch mb ON e.id = mb.user_id
|
|
|
+ INNER JOIN
|
|
|
+ public.measurement_params mip ON mb.measurement_param_id = mip.id
|
|
|
+ GROUP BY
|
|
|
+ e.id, e.name, mr.description
|
|
|
+)
|
|
|
+-- Основной запрос, использующий CTE
|
|
|
+SELECT
|
|
|
+ ms.user_name AS "ФИО пользователя",
|
|
|
+ ms.rank AS "Звание",
|
|
|
+ MIN(mip.height) AS "Мин. высота метеопоста",
|
|
|
+ MAX(mip.height) AS "Макс. высота метеопоста",
|
|
|
+ ms.total_measurements AS "Всего измерений",
|
|
|
+ ms.error_count AS "Из них ошибочны"
|
|
|
+FROM
|
|
|
+ measurement_stats ms
|
|
|
+INNER JOIN
|
|
|
+ public.measurement_batch mb ON ms.employee_id = mb.user_id
|
|
|
+INNER JOIN
|
|
|
+ public.measurement_params mip ON mb.measurement_param_id = mip.id
|
|
|
+WHERE
|
|
|
+ ms.total_measurements >= 5 AND ms.error_count < 10
|
|
|
+GROUP BY
|
|
|
+ ms.user_name, ms.rank, ms.total_measurements, ms.error_count
|
|
|
+ORDER BY
|
|
|
+ ms.error_count;
|
|
|
+
|
|
|
+
|
|
|
+CREATE OR REPLACE VIEW most_common_measurement_errors AS
|
|
|
+WITH log_data_text AS (
|
|
|
+ -- Извлекаем данные из JSON-логов как текст
|
|
|
+ SELECT
|
|
|
+ cl.id AS log_id,
|
|
|
+ cl.params->>'height' AS height_text,
|
|
|
+ cl.params->>'temperature' AS temperature_text,
|
|
|
+ cl.params->>'pressure' AS pressure_text,
|
|
|
+ cl.params->>'wind_direction' AS wind_direction_text,
|
|
|
+ cl.params->>'wind_speed' AS wind_speed_text,
|
|
|
+ cl.params->>'bullet_speed' AS bullet_speed_text,
|
|
|
+ cl.calculation_timestamp AS log_time
|
|
|
+ FROM
|
|
|
+ calculation_logs cl
|
|
|
+),
|
|
|
+log_data AS (
|
|
|
+ -- Конвертируем текстовые данные в numeric с обработкой null
|
|
|
+ SELECT
|
|
|
+ log_id,
|
|
|
+ coalesce(height_text, '0')::numeric AS height,
|
|
|
+ coalesce(temperature_text, '0')::numeric AS temperature,
|
|
|
+ coalesce(pressure_text, '0')::numeric AS pressure,
|
|
|
+ coalesce(wind_direction_text, '0')::numeric AS wind_direction,
|
|
|
+ coalesce(wind_speed_text, '0')::numeric AS wind_speed,
|
|
|
+ coalesce(bullet_speed_text, '0')::numeric AS bullet_speed,
|
|
|
+ log_time
|
|
|
+ FROM
|
|
|
+ log_data_text
|
|
|
+),
|
|
|
+error_data AS (
|
|
|
+ -- Проверяем данные на ошибки
|
|
|
+ SELECT
|
|
|
+ ld.*,
|
|
|
+ (public.fn_check_params(
|
|
|
+ ld.height,
|
|
|
+ ld.temperature,
|
|
|
+ ld.pressure,
|
|
|
+ ld.wind_direction,
|
|
|
+ ld.wind_speed,
|
|
|
+ ld.bullet_speed
|
|
|
+ )).error_message AS error_message
|
|
|
+ FROM
|
|
|
+ log_data ld
|
|
|
+ WHERE
|
|
|
+ (public.fn_check_params(
|
|
|
+ ld.height,
|
|
|
+ ld.temperature,
|
|
|
+ ld.pressure,
|
|
|
+ ld.wind_direction,
|
|
|
+ ld.wind_speed,
|
|
|
+ ld.bullet_speed
|
|
|
+ )).is_check = False
|
|
|
+),
|
|
|
+error_counts AS (
|
|
|
+ -- Группируем ошибки по типу и собираем пользователей
|
|
|
+ SELECT
|
|
|
+ ed.error_message,
|
|
|
+ COUNT(*) AS error_count,
|
|
|
+ STRING_AGG(DISTINCT e.name, ', ') AS users_list
|
|
|
+ FROM
|
|
|
+ error_data ed
|
|
|
+ INNER JOIN
|
|
|
+ measurement_batch mb ON ed.log_id = mb.measurement_param_id
|
|
|
+ INNER JOIN
|
|
|
+ employees e ON mb.user_id = e.id
|
|
|
+ GROUP BY
|
|
|
+ ed.error_message
|
|
|
+)
|
|
|
+-- Основной запрос, формирующий отчет
|
|
|
+SELECT
|
|
|
+ error_message AS "Наименование ошибки",
|
|
|
+ error_count AS "Количество ошибок",
|
|
|
+ users_list AS "Список пользователей, которые допустили ошибку"
|
|
|
+FROM
|
|
|
+ error_counts
|
|
|
+ORDER BY
|
|
|
+ error_count DESC;
|