5.sql 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. CREATE OR REPLACE VIEW user_error_stats AS
  2. WITH measurement_counts AS (
  3. -- CTE для подсчета общего количества измерений
  4. SELECT
  5. COUNT(*) AS count,
  6. user_id
  7. FROM public.measurement_params AS t1
  8. INNER JOIN public.measurement_batch AS t2 ON t2.measurement_param_id = t1.id
  9. GROUP BY user_id
  10. ),
  11. error_counts AS (
  12. -- CTE для подсчета количества ошибочных данных
  13. SELECT
  14. COUNT(*) AS error_count,
  15. user_id
  16. FROM public.measurement_params AS t1
  17. INNER JOIN public.measurement_batch AS t2 ON t2.measurement_param_id = t1.id
  18. WHERE (public.fn_check_params(height, temperature, pressure, wind_direction, wind_speed, bullet_speed)::public.check_result).is_check = False
  19. GROUP BY user_id
  20. )
  21. -- Основной запрос, использующий CTE
  22. SELECT
  23. t1.name AS user_name,
  24. t2.name AS position,
  25. COALESCE(mc.count, 0) AS count,
  26. COALESCE(fc.error_count, 0) AS error_count
  27. FROM public.employees AS t1
  28. INNER JOIN public.ranks AS t2 ON t1.rank_id = t2.id
  29. LEFT JOIN measurement_counts AS mc ON mc.user_id = t1.id
  30. LEFT JOIN error_counts AS fc ON fc.user_id = t1.id
  31. ORDER BY fc.error_count DESC;
  32. --Таблица 3
  33. -- Создаем таблицу speed_of_average_wind с внешним ключом на calc_height_correction.id
  34. CREATE TABLE speed_of_average_wind
  35. (
  36. height_id INTEGER PRIMARY KEY REFERENCES calc_height_correction(id), -- Внешний ключ на calc_height_correction
  37. distance NUMERIC[], -- Массив для отрицательных значений
  38. degree INTEGER
  39. );
  40. -- Вставляем данные в таблицу speed_of_average_wind, используя id из calc_height_correction
  41. INSERT INTO CREATE OR REPLACE VIEW employee_measurement_stats AS
  42. WITH measurement_counts AS (
  43. -- CTE для подсчета общего количества измерений
  44. SELECT
  45. COUNT(*) AS count,
  46. user_id
  47. FROM public.measurment_input_params AS t1
  48. INNER JOIN public.measurment_baths AS t2 ON t2.measurment_input_param_id = t1.id
  49. GROUP BY user_id
  50. ),
  51. error_counts AS (
  52. -- CTE для подсчета количества ошибочных данных
  53. SELECT
  54. COUNT(*) AS fail_count,
  55. user_id
  56. FROM public.measurment_input_params AS t1
  57. INNER JOIN public.measurment_baths AS t2 ON t2.measurment_input_param_id = t1.id
  58. WHERE (public.fn_check_input_params(height, temperature, pressure, wind_direction, wind_speed, bullet_demolition_range)::public.check_result).is_check = False
  59. GROUP BY user_id
  60. )
  61. -- Основной запрос, использующий CTE
  62. SELECT
  63. t1.name AS user_name,
  64. t2.description AS position,
  65. COALESCE(mc.count, 0) AS count,
  66. COALESCE(fc.fail_count, 0) AS fail_count
  67. FROM public.employees AS t1
  68. INNER JOIN public.ranks AS t2 ON t1.rank_id = t2.id
  69. LEFT JOIN measurement_counts AS mc ON mc.user_id = t1.id
  70. LEFT JOIN error_counts AS fc ON fc.user_id = t1.id
  71. ORDER BY fc.fail_count DESC;
  72. CREATE TABLE calculation_logs (
  73. id SERIAL PRIMARY KEY,
  74. input_params JSONB NOT NULL, -- Входные параметры расчета
  75. input_params_hash VARCHAR(32) NOT NULL, -- Хэш входных параметров
  76. used_table_values JSONB, -- Использованные значения из таблиц с корректировкой
  77. intermediate_results JSONB, -- Промежуточные результаты
  78. calculation_result JSONB, -- Итоговый результат расчета
  79. calculation_timestamp TIMESTAMP DEFAULT NOW() -- Время выполнения расчета
  80. );
  81. CREATE UNIQUE INDEX idx_calculation_logs_input_params_hash ON calculation_logs (input_params_hash);
  82. CREATE OR REPLACE FUNCTION log_calculation(input_params JSONB, used_table_values JSONB, intermediate_results JSONB, calculation_result JSONB) RETURNS VOID AS $$
  83. DECLARE
  84. input_params_hash TEXT;
  85. BEGIN
  86. -- Генерация хэша входных параметров
  87. input_params_hash := md5(input_params::text);
  88. -- Проверка, был ли уже выполнен расчет с такими параметрами
  89. IF EXISTS (SELECT 1 FROM calculation_logs WHERE input_params_hash = input_params_hash) THEN
  90. RAISE NOTICE 'Расчет с такими входными параметрами уже был выполнен';
  91. ELSE
  92. -- Логирование нового расчета
  93. INSERT INTO calculation_logs (input_params, input_params_hash, used_table_values, intermediate_results, calculation_result)
  94. VALUES (input_params, input_params_hash, used_table_values, intermediate_results, calculation_result);
  95. RAISE NOTICE 'Расчет успешно залогирован';
  96. END IF;
  97. END;
  98. $$ LANGUAGE plpgsql;
  99. --Таблица 3
  100. -- Создаем таблицу speed_of_average_wind с внешним ключом на calc_height_correction.id
  101. CREATE TABLE speed_of_average_wind
  102. (
  103. height_id INTEGER PRIMARY KEY REFERENCES calc_height_correction(id), -- Внешний ключ на calc_height_correction
  104. distance NUMERIC[], -- Массив для отрицательных значений
  105. degree INTEGER
  106. );
  107. -- Вставляем данные в таблицу speed_of_average_wind, используя id из calc_height_correction
  108. INSERT INTO speed_of_average_wind (height_id, distance, degree)
  109. VALUES
  110. ((SELECT id FROM calc_height_correction WHERE height = 200), ARRAY[3,4,5,6,7,7,8,9,10,11,12,12], 0),
  111. ((SELECT id FROM calc_height_correction WHERE height = 400), ARRAY[4,5,6,7,8,9,10,11,12,13,14,15], 1),
  112. ((SELECT id FROM calc_height_correction WHERE height = 800), ARRAY[4,5,6,7,8,9,10,11,13,14,15,16], 2),
  113. ((SELECT id FROM calc_height_correction WHERE height = 1200), ARRAY[4,5,6,7,8,9,10,11,12,13,14,15,16], 2),
  114. ((SELECT id FROM calc_height_correction WHERE height = 1600), ARRAY[4,6,7,8,9,10,11,13,14,15,17,17], 3),
  115. ((SELECT id FROM calc_height_correction WHERE height = 2000), ARRAY[4,6,7,8,9,10,11,13,14,16,17,18], 3),
  116. ((SELECT id FROM calc_height_correction WHERE height = 2400), ARRAY[4,6,8,9,9,10,12,14,15,16,18,19], 3),
  117. ((SELECT id FROM calc_height_correction WHERE height = 3000), ARRAY[5,6,8,9,10,11,12,14,15,17,18,19], 4),
  118. ((SELECT id FROM calc_height_correction WHERE height = 4000), ARRAY[5,6,8,9,10,11,12,14,16,18,19,20], 4);
  119. CREATE OR REPLACE FUNCTION calculate_average_wind_speed(
  120. par_height NUMERIC,
  121. par_bullet_demolition_range NUMERIC
  122. ) RETURNS NUMERIC AS $$
  123. DECLARE
  124. var_speed NUMERIC := 0;
  125. var_distance_index INT;
  126. var_distance_values NUMERIC[];
  127. BEGIN
  128. -- Если дальность сноса меньше 40 метров, скорость ветра равна 0
  129. IF par_bullet_demolition_range < 40 THEN
  130. RETURN 0;
  131. END IF;
  132. -- Получаем данные из таблицы для заданной высоты
  133. SELECT distance
  134. INTO var_distance_values
  135. FROM speed_of_average_wind
  136. WHERE height = par_height;
  137. -- Если данные для высоты не найдены, возвращаем 0
  138. IF var_distance_values IS NULL THEN
  139. RETURN 0;
  140. END IF;
  141. -- Вычисляем индекс на основе дальности сноса
  142. var_distance_index := LEAST(GREATEST((par_bullet_demolition_range - 40) / 10, 0), array_length(var_distance_values, 1) - 1);
  143. -- Получаем скорость ветра по индексу
  144. var_speed := var_distance_values[var_distance_index + 1]; -- Индексы в массиве начинаются с 1
  145. RETURN var_speed;
  146. END;
  147. $$ LANGUAGE plpgsql;
  148. CREATE OR REPLACE FUNCTION calculate_average_wind_direction(
  149. par_height NUMERIC,
  150. par_ground_wind_direction NUMERIC
  151. ) RETURNS NUMERIC AS $$
  152. DECLARE
  153. var_direction_increment NUMERIC;
  154. BEGIN
  155. -- Получаем приращение направления ветра из таблицы
  156. SELECT degree
  157. INTO var_direction_increment
  158. FROM speed_of_average_wind
  159. WHERE height = par_height;
  160. -- Если данные для высоты не найдены, возвращаем направление приземного ветра
  161. IF var_direction_increment IS NULL THEN
  162. RETURN par_ground_wind_direction;
  163. END IF;
  164. -- Рассчитываем среднее направление ветра
  165. RETURN par_ground_wind_direction + var_direction_increment;
  166. END;
  167. $$ LANGUAGE plpgsql;
  168. CREATE OR REPLACE FUNCTION calculate_wind_gun_corrections(
  169. IN par_height NUMERIC,
  170. IN par_temperature NUMERIC,
  171. IN par_pressure NUMERIC,
  172. IN par_wind_direction NUMERIC,
  173. IN par_wind_speed NUMERIC,
  174. IN par_bullet_demolition_range NUMERIC,
  175. OUT deviation_pressure NUMERIC,
  176. OUT deviation_temperature NUMERIC,
  177. OUT average_wind_speed NUMERIC,
  178. OUT average_wind_direction NUMERIC
  179. ) AS $$
  180. BEGIN
  181. -- Отклонение наземного давления
  182. deviation_pressure := public.fn_calc_header_pressure(par_pressure);
  183. -- Отклонение приземной виртуальной температуры
  184. deviation_temperature := public.fn_calc_header_temperature(par_temperature);
  185. -- Средняя скорость ветра
  186. average_wind_speed := calculate_average_wind_speed(par_height, par_bullet_demolition_range);
  187. -- Среднее направление ветра
  188. average_wind_direction := calculate_average_wind_direction(par_height, par_wind_direction);
  189. END;
  190. $$ LANGUAGE plpgsql;
  191. DO $$
  192. DECLARE
  193. -- Входные параметры
  194. var_height NUMERIC := 200; -- Высота (в метрах)
  195. var_temperature NUMERIC := 10; -- Температура (в градусах Цельсия)
  196. var_pressure NUMERIC := 740; -- Давление (в мм рт. ст.)
  197. var_wind_direction NUMERIC := 30; -- Направление приземного ветра (в градусах)
  198. var_wind_speed NUMERIC := 5; -- Скорость приземного ветра (в м/с)
  199. var_bullet_demolition_range NUMERIC := 80; -- Дальность сноса ветровых пуль (в метрах)
  200. -- Выходные параметры
  201. var_deviation_pressure NUMERIC; -- Отклонение наземного давления
  202. var_deviation_temperature NUMERIC; -- Отклонение приземной виртуальной температуры
  203. var_average_wind_speed NUMERIC; -- Средняя скорость ветра
  204. var_average_wind_direction NUMERIC; -- Среднее направление ветра
  205. BEGIN
  206. -- Вызов основной функции расчета
  207. SELECT * INTO var_deviation_pressure, var_deviation_temperature, var_average_wind_speed, var_average_wind_direction
  208. FROM calculate_wind_gun_corrections(
  209. var_height,
  210. var_temperature,
  211. var_pressure,
  212. var_wind_direction,
  213. var_wind_speed,
  214. var_bullet_demolition_range
  215. );
  216. -- Вывод результатов
  217. RAISE NOTICE '==============================';
  218. RAISE NOTICE 'Результаты расчета:';
  219. RAISE NOTICE 'Отклонение наземного давления: % мм рт. ст.', var_deviation_pressure;
  220. RAISE NOTICE 'Отклонение приземной виртуальной температуры: % °C', var_deviation_temperature;
  221. RAISE NOTICE 'Средняя скорость ветра: % м/с', var_average_wind_speed;
  222. RAISE NOTICE 'Среднее направление ветра: % градусов', var_average_wind_direction;
  223. RAISE NOTICE '==============================';
  224. END $$;
  225. -- Индексы для таблицы ranks
  226. CREATE INDEX idx_ranks_id ON public.ranks (id);
  227. -- Индексы для таблицы employees
  228. CREATE INDEX idx_employees_id ON public.employees (id);
  229. CREATE INDEX idx_employees_rank_id ON public.employees (rank_id);
  230. -- Индексы для таблицы measurment_types
  231. CREATE INDEX idx_measurment_types_id ON public.measurment_types (id);
  232. -- Индексы для таблицы measurment_input_params
  233. CREATE INDEX idx_measurment_input_params_id ON public.measurment_input_params (id);
  234. CREATE INDEX idx_measurment_input_params_measurment_type_id ON public.measurment_input_params (measurment_type_id);
  235. -- Индексы для таблицы measurment_baths
  236. CREATE INDEX idx_measurment_baths_id ON public.measurment_baths (id);
  237. CREATE INDEX idx_measurment_baths_user_id ON public.measurment_baths (user_id);
  238. CREATE INDEX idx_measurment_baths_measurment_input_param_id ON public.measurment_baths (measurment_input_param_id);
  239. -- Индексы для таблицы measurment_settings
  240. CREATE INDEX idx_measurment_settings_key ON public.measurment_settings (key);
  241. -- Индексы для таблицы calc_height_correction
  242. CREATE INDEX idx_calc_height_correction_id ON public.calc_height_correction (id);
  243. CREATE INDEX idx_calc_height_correction_measurment_type_id ON public.calc_height_correction (measurment_type_id);
  244. -- Индексы для таблицы calc_temperature_height_correction
  245. CREATE INDEX idx_calc_temperature_height_correction_id ON public.calc_temperature_height_correction (id);
  246. CREATE INDEX idx_calc_temperature_height_correction_calc_height_id ON public.calc_temperature_height_correction (calc_height_id);
  247. CREATE INDEX idx_calc_temperature_height_correction_calc_temperature_header_id ON public.calc_temperature_height_correction (calc_temperature_header_id);
  248. -- Индексы для таблицы calc_header_correction
  249. CREATE INDEX idx_calc_header_correction_id ON public.calc_header_correction (id);
  250. CREATE INDEX idx_calc_header_correction_measurment_type_id ON public.calc_header_correction (measurment_type_id);
  251. -- Индексы для таблицы speed_of_average_wind
  252. CREATE INDEX idx_speed_of_average_wind_height ON public.speed_of_average_wind (height);
  253. CREATE OR REPLACE VIEW effective_measurement_height AS
  254. WITH measurement_stats AS (
  255. -- CTE для подсчета общего количества измерений и количества ошибочных измерений
  256. SELECT
  257. e.id AS employee_id,
  258. e.name AS user_name,
  259. mr.description AS rank,
  260. COUNT(mb.id) AS total_measurements,
  261. 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
  262. FROM
  263. public.employees e
  264. INNER JOIN
  265. public.ranks mr ON e.rank_id = mr.id
  266. INNER JOIN
  267. public.measurment_baths mb ON e.id = mb.user_id
  268. INNER JOIN
  269. public.measurment_input_params mip ON mb.measurment_input_param_id = mip.id
  270. GROUP BY
  271. e.id, e.name, mr.description
  272. )
  273. -- Основной запрос, использующий CTE
  274. SELECT
  275. ms.user_name AS "ФИО пользователя",
  276. ms.rank AS "Звание",
  277. MIN(mip.height) AS "Мин. высота метеопоста",
  278. MAX(mip.height) AS "Макс. высота метеопоста",
  279. ms.total_measurements AS "Всего измерений",
  280. ms.error_count AS "Из них ошибочны"
  281. FROM
  282. measurement_stats ms
  283. INNER JOIN
  284. public.measurment_baths mb ON ms.employee_id = mb.user_id
  285. INNER JOIN
  286. public.measurment_input_params mip ON mb.measurment_input_param_id = mip.id
  287. WHERE
  288. ms.total_measurements >= 5 AND ms.error_count < 10
  289. GROUP BY
  290. ms.user_name, ms.rank, ms.total_measurements, ms.error_count
  291. ORDER BY
  292. ms.error_count;
  293. CREATE OR REPLACE VIEW most_common_measurement_errors AS
  294. WITH log_data_text AS (
  295. -- Извлекаем данные из JSON-логов как текст
  296. SELECT
  297. cl.id AS log_id,
  298. cl.input_params->>'height' AS height_text,
  299. cl.input_params->>'temperature' AS temperature_text,
  300. cl.input_params->>'pressure' AS pressure_text,
  301. cl.input_params->>'wind_direction' AS wind_direction_text,
  302. cl.input_params->>'wind_speed' AS wind_speed_text,
  303. cl.input_params->>'bullet_demolition_range' AS bullet_demolition_range_text,
  304. cl.calculation_timestamp AS log_time
  305. FROM
  306. calculation_logs cl
  307. ),
  308. log_data AS (
  309. -- Конвертируем текстовые данные в numeric с обработкой null
  310. SELECT
  311. log_id,
  312. coalesce(height_text, '0')::numeric AS height,
  313. coalesce(temperature_text, '0')::numeric AS temperature,
  314. coalesce(pressure_text, '0')::numeric AS pressure,
  315. coalesce(wind_direction_text, '0')::numeric AS wind_direction,
  316. coalesce(wind_speed_text, '0')::numeric AS wind_speed,
  317. coalesce(bullet_demolition_range_text, '0')::numeric AS bullet_demolition_range,
  318. log_time
  319. FROM
  320. log_data_text
  321. ),
  322. error_data AS (
  323. -- Проверяем данные на ошибки
  324. SELECT
  325. ld.*,
  326. (public.fn_check_input_params(
  327. ld.height,
  328. ld.temperature,
  329. ld.pressure,
  330. ld.wind_direction,
  331. ld.wind_speed,
  332. ld.bullet_demolition_range
  333. )).error_message AS error_message
  334. FROM
  335. log_data ld
  336. WHERE
  337. (public.fn_check_input_params(
  338. ld.height,
  339. ld.temperature,
  340. ld.pressure,
  341. ld.wind_direction,
  342. ld.wind_speed,
  343. ld.bullet_demolition_range
  344. )).is_check = False
  345. ),
  346. error_counts AS (
  347. -- Группируем ошибки по типу и собираем пользователей
  348. SELECT
  349. ed.error_message,
  350. COUNT(*) AS error_count,
  351. STRING_AGG(DISTINCT e.name, ', ') AS users_list
  352. FROM
  353. error_data ed
  354. INNER JOIN
  355. measurment_baths mb ON ed.log_id = mb.measurment_input_param_id
  356. INNER JOIN
  357. employees e ON mb.user_id = e.id
  358. GROUP BY
  359. ed.error_message
  360. )
  361. -- Основной запрос, формирующий отчет
  362. SELECT
  363. error_message AS "Наименование ошибки",
  364. error_count AS "Количество ошибок",
  365. users_list AS "Список пользователей, которые допустили ошибку"
  366. FROM
  367. error_counts
  368. ORDER BY
  369. error_count DESC; (height_id, distance, degree)
  370. VALUES
  371. ((SELECT id FROM calc_height_correction WHERE height = 200), ARRAY[3,4,5,6,7,7,8,9,10,11,12,12], 0),
  372. ((SELECT id FROM calc_height_correction WHERE height = 400), ARRAY[4,5,6,7,8,9,10,11,12,13,14,15], 1),
  373. ((SELECT id FROM calc_height_correction WHERE height = 800), ARRAY[4,5,6,7,8,9,10,11,13,14,15,16], 2),
  374. ((SELECT id FROM calc_height_correction WHERE height = 1200), ARRAY[4,5,6,7,8,9,10,11,12,13,14,15,16], 2),
  375. ((SELECT id FROM calc_height_correction WHERE height = 1600), ARRAY[4,6,7,8,9,10,11,13,14,15,17,17], 3),
  376. ((SELECT id FROM calc_height_correction WHERE height = 2000), ARRAY[4,6,7,8,9,10,11,13,14,16,17,18], 3),
  377. ((SELECT id FROM calc_height_correction WHERE height = 2400), ARRAY[4,6,8,9,9,10,12,14,15,16,18,19], 3),
  378. ((SELECT id FROM calc_height_correction WHERE height = 3000), ARRAY[5,6,8,9,10,11,12,14,15,17,18,19], 4),
  379. ((SELECT id FROM calc_height_correction WHERE height = 4000), ARRAY[5,6,8,9,10,11,12,14,16,18,19,20], 4);
  380. CREATE OR REPLACE FUNCTION calc_avg_wind_speed(
  381. par_height NUMERIC,
  382. par_bullet_speed NUMERIC
  383. ) RETURNS NUMERIC AS $$
  384. DECLARE
  385. var_speed NUMERIC := 0;
  386. var_distance_index INT;
  387. var_distance_values NUMERIC[];
  388. BEGIN
  389. -- Если дальность сноса меньше 40 метров, скорость ветра равна 0
  390. IF par_bullet_speed < 40 THEN
  391. RETURN 0;
  392. END IF;
  393. -- Получаем данные из таблицы для заданной высоты
  394. SELECT distance
  395. INTO var_distance_values
  396. FROM speed_of_average_wind
  397. WHERE height = par_height;
  398. -- Если данные для высоты не найдены, возвращаем 0
  399. IF var_distance_values IS NULL THEN
  400. RETURN 0;
  401. END IF;
  402. -- Вычисляем индекс на основе дальности сноса
  403. var_distance_index := LEAST(GREATEST((par_bullet_speed - 40) / 10, 0), array_length(var_distance_values, 1) - 1);
  404. -- Получаем скорость ветра по индексу
  405. var_speed := var_distance_values[var_distance_index + 1]; -- Индексы в массиве начинаются с 1
  406. RETURN var_speed;
  407. END;
  408. $$ LANGUAGE plpgsql;
  409. CREATE OR REPLACE FUNCTION calc_avg_wind_dir(
  410. par_height NUMERIC,
  411. par_ground_wind_direction NUMERIC
  412. ) RETURNS NUMERIC AS $$
  413. DECLARE
  414. var_direction_increment NUMERIC;
  415. BEGIN
  416. -- Получаем приращение направления ветра из таблицы
  417. SELECT degree
  418. INTO var_direction_increment
  419. FROM speed_of_average_wind
  420. WHERE height = par_height;
  421. -- Если данные для высоты не найдены, возвращаем направление приземного ветра
  422. IF var_direction_increment IS NULL THEN
  423. RETURN par_ground_wind_direction;
  424. END IF;
  425. -- Рассчитываем среднее направление ветра
  426. RETURN par_ground_wind_direction + var_direction_increment;
  427. END;
  428. $$ LANGUAGE plpgsql;
  429. CREATE OR REPLACE FUNCTION calculate_wind_gun_corrections(
  430. IN par_height NUMERIC,
  431. IN par_temperature NUMERIC,
  432. IN par_pressure NUMERIC,
  433. IN par_wind_direction NUMERIC,
  434. IN par_wind_speed NUMERIC,
  435. IN par_bullet_speed NUMERIC,
  436. OUT deviation_pressure NUMERIC,
  437. OUT deviation_temperature NUMERIC,
  438. OUT average_wind_speed NUMERIC,
  439. OUT average_wind_direction NUMERIC
  440. ) AS $$
  441. BEGIN
  442. -- Отклонение наземного давления
  443. deviation_pressure := public.fn_calc_header_pressure(par_pressure);
  444. -- Отклонение приземной виртуальной температуры
  445. deviation_temperature := public.fn_calc_header_temperature(par_temperature);
  446. -- Средняя скорость ветра
  447. average_wind_speed := calc_avg_wind_speed(par_height, par_bullet_speed);
  448. -- Среднее направление ветра
  449. average_wind_direction := calc_avg_wind_dir(par_height, par_wind_direction);
  450. END;
  451. $$ LANGUAGE plpgsql;
  452. DO $$
  453. DECLARE
  454. -- Входные параметры
  455. var_height NUMERIC := 200; -- Высота (в метрах)
  456. var_temperature NUMERIC := 10; -- Температура (в градусах Цельсия)
  457. var_pressure NUMERIC := 740; -- Давление (в мм рт. ст.)
  458. var_wind_direction NUMERIC := 30; -- Направление приземного ветра (в градусах)
  459. var_wind_speed NUMERIC := 5; -- Скорость приземного ветра (в м/с)
  460. var_bullet_speed NUMERIC := 80; -- Дальность сноса ветровых пуль (в метрах)
  461. -- Выходные параметры
  462. var_deviation_pressure NUMERIC; -- Отклонение наземного давления
  463. var_deviation_temperature NUMERIC; -- Отклонение приземной виртуальной температуры
  464. var_average_wind_speed NUMERIC; -- Средняя скорость ветра
  465. var_average_wind_direction NUMERIC; -- Среднее направление ветра
  466. BEGIN
  467. -- Вызов основной функции расчета
  468. SELECT * INTO var_deviation_pressure, var_deviation_temperature, var_average_wind_speed, var_average_wind_direction
  469. FROM calculate_wind_gun_corrections(
  470. var_height,
  471. var_temperature,
  472. var_pressure,
  473. var_wind_direction,
  474. var_wind_speed,
  475. var_bullet_speed
  476. );
  477. -- Вывод результатов
  478. RAISE NOTICE '==============================';
  479. RAISE NOTICE 'Результаты расчета:';
  480. RAISE NOTICE 'Отклонение наземного давления: % мм рт. ст.', var_deviation_pressure;
  481. RAISE NOTICE 'Отклонение приземной виртуальной температуры: % °C', var_deviation_temperature;
  482. RAISE NOTICE 'Средняя скорость ветра: % м/с', var_average_wind_speed;
  483. RAISE NOTICE 'Среднее направление ветра: % градусов', var_average_wind_direction;
  484. RAISE NOTICE '==============================';
  485. END $$;
  486. -- Индексы для таблицы ranks
  487. CREATE INDEX idx_ranks_id ON public.ranks (id);
  488. -- Индексы для таблицы employees
  489. CREATE INDEX idx_employees_id ON public.employees (id);
  490. CREATE INDEX idx_employees_rank_id ON public.employees (rank_id);
  491. -- Индексы для таблицы measurment_types
  492. CREATE INDEX idx_measurment_types_id ON public.measurment_types (id);
  493. -- Индексы для таблицы measurement_params
  494. CREATE INDEX idx_measurement_params_id ON public.measurement_params (id);
  495. CREATE INDEX idx_measurement_params_measurment_type_id ON public.measurement_params (measurment_type_id);
  496. -- Индексы для таблицы measurement_batch
  497. CREATE INDEX idx_measurement_batch_id ON public.measurement_batch (id);
  498. CREATE INDEX idx_measurement_batch_user_id ON public.measurement_batch (user_id);
  499. CREATE INDEX idx_measurement_batch_measurement_param_id ON public.measurement_batch (measurement_param_id);
  500. -- Индексы для таблицы measurment_settings
  501. CREATE INDEX idx_measurment_settings_key ON public.measurment_settings (key);
  502. -- Индексы для таблицы calc_height_correction
  503. CREATE INDEX idx_calc_height_correction_id ON public.calc_height_correction (id);
  504. CREATE INDEX idx_calc_height_correction_measurment_type_id ON public.calc_height_correction (measurment_type_id);
  505. -- Индексы для таблицы calc_temperature_height_correction
  506. CREATE INDEX idx_calc_temperature_height_correction_id ON public.calc_temperature_height_correction (id);
  507. CREATE INDEX idx_calc_temperature_height_correction_calc_height_id ON public.calc_temperature_height_correction (calc_height_id);
  508. CREATE INDEX idx_calc_temperature_height_correction_calc_temperature_header_id ON public.calc_temperature_height_correction (calc_temperature_header_id);
  509. -- Индексы для таблицы calc_header_correction
  510. CREATE INDEX idx_calc_header_correction_id ON public.calc_header_correction (id);
  511. CREATE INDEX idx_calc_header_correction_measurment_type_id ON public.calc_header_correction (measurment_type_id);
  512. -- Индексы для таблицы speed_of_average_wind
  513. CREATE INDEX idx_speed_of_average_wind_height ON public.speed_of_average_wind (height);
  514. CREATE OR REPLACE VIEW effective_measurement_height AS
  515. WITH measurement_stats AS (
  516. -- CTE для подсчета общего количества измерений и количества ошибочных измерений
  517. SELECT
  518. e.id AS employee_id,
  519. e.name AS user_name,
  520. mr.description AS rank,
  521. COUNT(mb.id) AS total_measurements,
  522. 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
  523. FROM
  524. public.employees e
  525. INNER JOIN
  526. public.ranks mr ON e.rank_id = mr.id
  527. INNER JOIN
  528. public.measurement_batch mb ON e.id = mb.user_id
  529. INNER JOIN
  530. public.measurement_params mip ON mb.measurement_param_id = mip.id
  531. GROUP BY
  532. e.id, e.name, mr.description
  533. )
  534. -- Основной запрос, использующий CTE
  535. SELECT
  536. ms.user_name AS "ФИО пользователя",
  537. ms.rank AS "Звание",
  538. MIN(mip.height) AS "Мин. высота метеопоста",
  539. MAX(mip.height) AS "Макс. высота метеопоста",
  540. ms.total_measurements AS "Всего измерений",
  541. ms.error_count AS "Из них ошибочны"
  542. FROM
  543. measurement_stats ms
  544. INNER JOIN
  545. public.measurement_batch mb ON ms.employee_id = mb.user_id
  546. INNER JOIN
  547. public.measurement_params mip ON mb.measurement_param_id = mip.id
  548. WHERE
  549. ms.total_measurements >= 5 AND ms.error_count < 10
  550. GROUP BY
  551. ms.user_name, ms.rank, ms.total_measurements, ms.error_count
  552. ORDER BY
  553. ms.error_count;
  554. CREATE OR REPLACE VIEW most_common_measurement_errors AS
  555. WITH log_data_text AS (
  556. -- Извлекаем данные из JSON-логов как текст
  557. SELECT
  558. cl.id AS log_id,
  559. cl.params->>'height' AS height_text,
  560. cl.params->>'temperature' AS temperature_text,
  561. cl.params->>'pressure' AS pressure_text,
  562. cl.params->>'wind_direction' AS wind_direction_text,
  563. cl.params->>'wind_speed' AS wind_speed_text,
  564. cl.params->>'bullet_speed' AS bullet_speed_text,
  565. cl.calculation_timestamp AS log_time
  566. FROM
  567. calculation_logs cl
  568. ),
  569. log_data AS (
  570. -- Конвертируем текстовые данные в numeric с обработкой null
  571. SELECT
  572. log_id,
  573. coalesce(height_text, '0')::numeric AS height,
  574. coalesce(temperature_text, '0')::numeric AS temperature,
  575. coalesce(pressure_text, '0')::numeric AS pressure,
  576. coalesce(wind_direction_text, '0')::numeric AS wind_direction,
  577. coalesce(wind_speed_text, '0')::numeric AS wind_speed,
  578. coalesce(bullet_speed_text, '0')::numeric AS bullet_speed,
  579. log_time
  580. FROM
  581. log_data_text
  582. ),
  583. error_data AS (
  584. -- Проверяем данные на ошибки
  585. SELECT
  586. ld.*,
  587. (public.fn_check_params(
  588. ld.height,
  589. ld.temperature,
  590. ld.pressure,
  591. ld.wind_direction,
  592. ld.wind_speed,
  593. ld.bullet_speed
  594. )).error_message AS error_message
  595. FROM
  596. log_data ld
  597. WHERE
  598. (public.fn_check_params(
  599. ld.height,
  600. ld.temperature,
  601. ld.pressure,
  602. ld.wind_direction,
  603. ld.wind_speed,
  604. ld.bullet_speed
  605. )).is_check = False
  606. ),
  607. error_counts AS (
  608. -- Группируем ошибки по типу и собираем пользователей
  609. SELECT
  610. ed.error_message,
  611. COUNT(*) AS error_count,
  612. STRING_AGG(DISTINCT e.name, ', ') AS users_list
  613. FROM
  614. error_data ed
  615. INNER JOIN
  616. measurement_batch mb ON ed.log_id = mb.measurement_param_id
  617. INNER JOIN
  618. employees e ON mb.user_id = e.id
  619. GROUP BY
  620. ed.error_message
  621. )
  622. -- Основной запрос, формирующий отчет
  623. SELECT
  624. error_message AS "Наименование ошибки",
  625. error_count AS "Количество ошибок",
  626. users_list AS "Список пользователей, которые допустили ошибку"
  627. FROM
  628. error_counts
  629. ORDER BY
  630. error_count DESC;