
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;
