Vsevolod Levitan 1 month ago
parent
commit
2b96d8be49
1 changed files with 707 additions and 0 deletions
  1. 707 0
      homework/5.sql

+ 707 - 0
homework/5.sql

@@ -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;