sfx-tg-bot/database.sql

383 строки
13 KiB
PL/PgSQL

create table categories (
id smallserial not null,
name character varying (64) not null,
description text not null,
primary key (id),
unique (name)
);
insert into categories (name, description) values
('Прикладное программное обеспечение', '[Описание категории]'),
('Системное программное обеспечение', '[Описание категории]'),
('Системы обеспечения IT-безопасности', '[Описание категории]'),
('Специализированное программное обеспечение', '[Описание категории]');
create table subcategories (
category_id smallint not null,
id smallint not null,
name character varying (64) not null,
description text not null,
foreign key (category_id) references categories on delete cascade,
primary key (category_id, id),
unique (category_id, name)
);
create function sfx_subcategories_id_seq() returns trigger as $$
begin
if new.id is null then
new.id := (select
coalesce(max(subcategories.id) + 1, 1)
from
subcategories
where
subcategories.category_id = new.category_id);
end if;
return new;
end;
$$ language plpgsql;
create trigger subcategories_id_seq before insert on subcategories
for each row execute procedure sfx_subcategories_id_seq();
insert into subcategories (category_id, name, description) values
(1, 'Программы 1С', '[Описание подкатегории]'),
(1, 'Программы ЭОС', '[Описание подкатегории]'),
(1, 'Собственные разработки на платформе 1С', '[Описание подкатегории]'),
(2, 'Продукция Astra Linux', '[Описание подкатегории]'),
(2, 'Продукция Alt Linux (Базальт-СПО)', '[Описание подкатегории]'),
(2, 'ПО для работы с текстом', '[Описание подкатегории]'),
(2, 'МойОфис', '[Описание подкатегории]'),
(3, 'Системы обеспечения сохранности данных', '[Описание подкатегории]'),
(3, 'Антивирусное ПО', '[Описание подкатегории]'),
(3, 'Системы защиты корпоративной информации', '[Описание подкатегории]'),
(3, 'Программный комплекс «Стахановец»', '[Описание подкатегории]'),
(3, 'Решение StaffCop Enterprise', '[Описание подкатегории]'),
(4, 'Графические редакторы Movavi', '[Описание подкатегории]'),
(4, 'Сметные программы', '[Описание подкатегории]'),
(4, 'Библиотеки нормативов и стандартов', '[Описание подкатегории]'),
(4, 'САПР', '[Описание подкатегории]'),
(4, 'Решения для совместной работы TrueConf', '[Описание подкатегории]'),
(4, 'Polys - система безопасных онлайн-голосований', '[Описание подкатегории]'),
(4, 'VISOCALL IP Телекоммуникация в медицине', '[Описание подкатегории]');
create table executors (
id bigserial not null,
name character varying (64) not null,
primary key (id),
unique (name)
);
insert into executors (name) values
('Богатырёва Ю. И.'),
('Ванькова В. С.'),
('Даниленко С. В.'),
('Екатериничев А. Л.'),
('Клепиков А. К.'),
('Мартынюк Ю. М.'),
('Надеждин Е. Н.'),
('Привалов А. Н.'),
('Родионова О. В.');
create table executor_specialties (
executor_id bigint not null,
category_id smallint not null,
subcategory_id smallint not null,
foreign key (executor_id) references executors on delete cascade,
foreign key (category_id, subcategory_id) references subcategories on delete cascade,
primary key (executor_id, category_id, subcategory_id)
);
insert into executor_specialties (executor_id, category_id, subcategory_id) values
(1, 1, 1),
(2, 1, 1),
(4, 1, 1),
(5, 1, 1),
(6, 1, 1),
(7, 1, 1),
(8, 1, 1),
(9, 1, 1),
(4, 1, 2),
(5, 1, 2),
(7, 1, 2),
(8, 1, 2),
(1, 1, 3),
(2, 1, 3),
(3, 1, 3),
(5, 1, 3),
(6, 1, 3),
(7, 1, 3),
(8, 1, 3),
(4, 2, 1),
(5, 2, 1),
(6, 2, 1),
(7, 2, 1),
(8, 2, 1),
(9, 2, 1),
(2, 2, 2),
(5, 2, 2),
(6, 2, 2),
(7, 2, 2),
(8, 2, 2),
(9, 2, 2),
(2, 2, 3),
(4, 2, 3),
(8, 2, 3),
(4, 2, 4),
(5, 2, 4),
(8, 2, 4),
(9, 2, 4),
(2, 3, 1),
(3, 3, 1),
(6, 3, 1),
(7, 3, 1),
(1, 3, 2),
(4, 3, 2),
(5, 3, 2),
(6, 3, 2),
(9, 3, 2),
(1, 3, 3),
(6, 3, 3),
(9, 3, 3),
(3, 3, 4),
(8, 3, 4),
(1, 3, 5),
(3, 3, 5),
(5, 3, 5),
(6, 3, 5),
(7, 3, 5),
(9, 3, 5),
(5, 4, 1),
(6, 4, 1),
(7, 4, 2),
(9, 4, 4),
(3, 4, 6),
(4, 4, 6);
create table time_ranges (
id smallserial not null,
start_time time not null,
end_time time not null,
primary key (id)
);
insert into time_ranges (start_time, end_time) values
('9:00'::time, '12:00'::time),
('12:00'::time, '15:00'::time),
('15:00'::time, '18:00'::time);
create table orders (
id bigserial not null,
category_id smallint not null,
subcategory_id smallint not null,
date date not null,
time_range_id smallint not null,
executor_id bigint not null,
telegram_id bigint not null,
email_address character varying (256) not null,
phone_number character varying (16) not null,
comment character varying (1024) not null,
start_time timestamp,
end_time timestamp,
foreign key (category_id, subcategory_id) references subcategories on delete cascade,
foreign key (time_range_id) references time_ranges on delete cascade,
foreign key (executor_id) references executors on delete cascade,
primary key (id)
);
create table issues (
id bigint not null,
key character varying (16) not null,
status character varying (16) not null,
telegram_id bigint not null,
primary key (id),
unique (key)
);
create table statistics (
category_id smallint not null,
subcategory_id smallint not null,
execution_time interval not null,
foreign key (category_id, subcategory_id) references subcategories on delete cascade,
primary key (category_id, subcategory_id)
);
insert into statistics (category_id, subcategory_id, execution_time) values
(1, 1, interval '15 minutes'),
(1, 2, interval '30 minutes'),
(1, 3, interval '15 minutes'),
(2, 1, interval '1 hour'),
(2, 2, interval '2 hours'),
(2, 3, interval '1 hour'),
(2, 4, interval '2 hours'),
(3, 1, interval '15 minutes'),
(3, 2, interval '30 minutes'),
(3, 3, interval '15 minutes'),
(3, 4, interval '30 minutes'),
(3, 5, interval '15 minutes'),
(4, 1, interval '1 hour'),
(4, 2, interval '2 hours'),
(4, 3, interval '1 hour'),
(4, 4, interval '2 hours'),
(4, 5, interval '1 hour'),
(4, 6, interval '2 hours'),
(4, 7, interval '1 hour');
create or replace function sfx_update_statistics(
k integer
) returns void as $$
declare subcategory subcategories;
declare _order record;
begin
for subcategory in (
select
subcategories.category_id,
subcategories.id
from
subcategories
) loop
for _order in (
select
count(t1) as count,
avg(t1.end_time - t1.start_time) as avg
from
(
select
orders.start_time,
orders.end_time
from
orders
where
orders.category_id = subcategory.category_id and
orders.subcategory_id = subcategory.id and
orders.start_time is not null and
orders.end_time is not null
order by
orders.start_time desc
limit
k
) t1
) loop
if _order.count <> k then
continue;
end if;
update
statistics
set
execution_time = _order.avg
where
statistics.category_id = subcategory.category_id and
statistics.subcategory_id = subcategory.id;
end loop;
end loop;
end;
$$ language plpgsql;
create or replace function sfx_read_free_to_order(
_category_id smallint,
_subcategory_id smallint
) returns table (
date date,
time_range_id smallint,
executor_id bigint,
busy_interval interval
) as $$
declare avg_interval interval := (
select
statistics.execution_time
from
statistics
where
statistics.category_id = _category_id and
statistics.subcategory_id = _subcategory_id
);
declare max_interval interval := (
select
max(time_ranges.end_time - time_ranges.start_time)
from
time_ranges
);
declare executor executors;
declare time_range time_ranges;
declare _date date := now()::date;
declare _busy_interval interval;
begin
if avg_interval > max_interval then
raise '0x00000005';
end if;
create temporary table tmp (
date date not null,
time_range_id smallint not null,
executor_id bigint not null,
busy_interval interval not null
) on commit drop;
while (
select
coalesce(count(t1.*), 0) < 6
from
(select distinct
tmp.date
from
tmp) t1
) loop
for executor in (
select
executors.id
from
executor_specialties
left join executors on
executor_specialties.executor_id = executors.id
where
executor_specialties.category_id = _category_id and
executor_specialties.subcategory_id = _subcategory_id
) loop
for time_range in (
select
time_ranges.id,
time_ranges.start_time,
time_ranges.end_time
from
time_ranges
) loop
if _date = now()::date and time_range.start_time < now()::time then
continue;
end if;
_busy_interval := (
select
coalesce(sum(statistics.execution_time), '0s'::interval)
from
orders
left join statistics on
orders.category_id = statistics.category_id and
orders.subcategory_id = statistics.subcategory_id
where
orders.date = _date and
orders.time_range_id = time_range.id and
orders.executor_id = executor.id
);
if time_range.end_time - time_range.start_time - _busy_interval > avg_interval then
insert into tmp (
date,
time_range_id,
executor_id,
busy_interval
)
values (
_date,
time_range.id,
executor.id,
_busy_interval
);
end if;
end loop;
end loop;
_date = _date + '1 day'::interval;
end loop;
return query (
select
tmp.*
from
tmp
);
end;
$$ language plpgsql;