Vsevolod Levitan 1 місяць тому
батько
коміт
669f14e8de
4 змінених файлів з 158 додано та 0 видалено
  1. 0 0
      homework/0.sql
  2. 67 0
      homework/3.class.sql
  3. 35 0
      homework/3.data.sql
  4. 56 0
      homework/3.sql

+ 0 - 0
homework/init.sql → homework/0.sql


+ 67 - 0
homework/3.class.sql

@@ -0,0 +1,67 @@
+create table if not exists numeric_constants(key varchar primary key, value numeric);
+
+-- Функция формата даты
+create or replace function approx_report_date(t_date timestamptz)
+	returns varchar(5)
+	language plpgsql
+	as
+$$
+begin
+	return lpad(extract(day from t_date)::text, 2, '0') || lpad(extract(hour from t_date)::text, 2, '0') || floor((extract(minute from t_date) / 10))::varchar;
+end;
+$$;
+
+-- Функция формата высоты
+create or replace function approx_report_height(height numeric)
+	returns varchar(4)
+	language plpgsql
+	as
+$$
+begin
+	return lpad(height::text, 4, '0');
+end;
+$$;
+
+-- Функция формата отклонения по давлению и температуре
+create or replace function approx_report_deviation(pressure numeric, temperature numeric)
+	returns varchar(5)
+	language plpgsql
+	as
+$$
+declare 
+	pressure_dev numeric;
+	temperature_dev numeric;
+	res varchar(5);
+begin
+	pressure_dev = (pressure - (select value from numeric_constants where key = 'rel_pressure'));
+	temperature_dev = (temperature - (select value from numeric_constants where key = 'rel_temperature'));
+	temperature_dev := round(temperature_dev + calc_adjustment(calc_interpolation(temperature)));
+	
+	res = case when pressure_dev >= 0 then pressure_dev::text else ('5' || lpad((pressure_dev*-1)::text, 2, '0')) end;
+	res = concat(res, lpad(temperature_dev::text, 2, '0'));
+	
+	return res;
+end;
+$$;
+
+-- Тип приблизительного отчета
+CREATE TYPE approx_report AS
+(
+	date character varying(5),
+	height character varying(4),
+	deviation character varying(5)
+);
+
+-- Функция получения приблизительного отчета
+create or replace function approx_report(date timestamptz, height numeric, pressure numeric, temperature numeric)
+	returns approx_report
+	language plpgsql
+	as
+$$
+begin
+	return (approx_report_date(date)::varchar(5), approx_report_height(height)::varchar(4), approx_report_deviation(pressure, temperature)::varchar(5)) as approx_report;
+end;
+$$;
+
+insert into numeric_constants(key, value) values ('rel_pressure', 750);
+insert into numeric_constants(key, value) values ('rel_temperature', 15.9);

+ 35 - 0
homework/3.data.sql

@@ -0,0 +1,35 @@
+DO $$
+DECLARE
+    user_count INT := 5; -- Количество пользователей
+    measurements_per_user INT := 100; -- Количество измерений на пользователя
+    user_id INT;
+    batch_id INT;
+BEGIN
+    -- Добавление пользователей
+    FOR i IN 1..user_count LOOP
+        INSERT INTO users (name, rank_id) VALUES ('User' || i, i);
+        user_id := currval(pg_get_serial_sequence('users', 'id'));
+
+        -- Добавление пакетов измерений для каждого пользователя
+        FOR j IN 1..(measurements_per_user / 10) LOOP
+            INSERT INTO measurement_batch (start_period, user_id, pos_x, pos_y)
+            VALUES (NOW() - (j || ' days')::interval, user_id, random() * 100, random() * 100);
+            batch_id := currval(pg_get_serial_sequence('measurement_batch', 'id'));
+
+            -- Добавление измерений в пакет
+            FOR k IN 1..10 LOOP
+                INSERT INTO measurement_params (measurement_type_id, measurement_batch_id, height, temperature, pressure, wind_speed, wind_direction, bullet_speed)
+                VALUES (
+                    1, -- Тип измерения
+                    batch_id,
+                    random() * 1000, -- Высота
+                    (random() * 116 - 58)::NUMERIC, -- Температура (-58..58)
+                    (random() * 400 + 500)::NUMERIC, -- Давление (500..900)
+                    random() * 20, -- Скорость ветра
+                    (random() * 60)::INT, -- Направление ветра (0..59)
+                    random() * 1000 -- Скорость пули
+                );
+            END LOOP;
+        END LOOP;
+    END LOOP;
+END $$;

+ 56 - 0
homework/3.sql

@@ -0,0 +1,56 @@
+CREATE TABLE IF NOT EXISTS measure_settings (
+    id SERIAL PRIMARY KEY,
+    parameter_name VARCHAR(50) NOT NULL UNIQUE,
+    min_value NUMERIC NOT NULL,
+    max_value NUMERIC NOT NULL,
+    unit VARCHAR(20)
+);
+
+INSERT INTO measure_settings (parameter_name, min_value, max_value, unit)
+VALUES 
+('temperature', -58, 58, '°C'),
+('pressure', 500, 900, 'mmHg'),
+('wind_direction', 0, 59, 'degrees');
+
+CREATE TYPE measurement_data AS (
+    temperature NUMERIC,
+    pressure NUMERIC,
+    wind_direction NUMERIC
+);
+
+CREATE OR REPLACE FUNCTION validate_measurement(
+    input_temperature NUMERIC,
+    input_pressure NUMERIC,
+    input_wind_direction NUMERIC
+) RETURNS measurement_data AS $$
+DECLARE
+    validated_data measurement_data;
+BEGIN
+    IF input_temperature < (SELECT min_value FROM measure_settings WHERE parameter_name = 'temperature') OR
+       input_temperature > (SELECT max_value FROM measure_settings WHERE parameter_name = 'temperature') THEN
+        RAISE EXCEPTION 'Temperature out of range. Allowed range: % to % °C',
+            (SELECT min_value FROM measure_settings WHERE parameter_name = 'temperature'),
+            (SELECT max_value FROM measure_settings WHERE parameter_name = 'temperature');
+    END IF;
+
+    IF input_pressure < (SELECT min_value FROM measure_settings WHERE parameter_name = 'pressure') OR
+       input_pressure > (SELECT max_value FROM measure_settings WHERE parameter_name = 'pressure') THEN
+        RAISE EXCEPTION 'Pressure out of range. Allowed range: % to % mmHg',
+            (SELECT min_value FROM measure_settings WHERE parameter_name = 'pressure'),
+            (SELECT max_value FROM measure_settings WHERE parameter_name = 'pressure');
+    END IF;
+
+    IF input_wind_direction < (SELECT min_value FROM measure_settings WHERE parameter_name = 'wind_direction') OR
+       input_wind_direction > (SELECT max_value FROM measure_settings WHERE parameter_name = 'wind_direction') THEN
+        RAISE EXCEPTION 'Wind direction out of range. Allowed range: % to % degrees',
+            (SELECT min_value FROM measure_settings WHERE parameter_name = 'wind_direction'),
+            (SELECT max_value FROM measure_settings WHERE parameter_name = 'wind_direction');
+    END IF;
+
+    validated_data.temperature := input_temperature;
+    validated_data.pressure := input_pressure;
+    validated_data.wind_direction := input_wind_direction;
+
+    RETURN validated_data;
+END;
+$$ LANGUAGE plpgsql;