IMO, вы можете использовать следующую простую структуру базы данных для решения вашей проблемы.
Словарь типов статистики
Очень простая таблица - просто имя и описание статистики.тип:
create table stat_types (
type text not null constraint stat_types_pkey primary key,
description text
);
(Вы можете заменить его на enum, если у вас конечное число элементов)
Таблица статистики для каждого типа объектов в проекте
Этосодержит FK для объекта, FK для стат.введите (или просто перечислите) и, что важно, поле jsonb
с произвольным значением .Данные относятся к его типу.Например, такая таблица для телефонных звонков :
create table phone_calls_statistics (
phone_call_id uuid not null references phone_calls,
stat_type text not null references stat_types,
data jsonb,
constraint phone_calls_statistics_pkey primary key (phone_call_id, stat_type)
);
Здесь я предполагаю, что таблица phone_calls
имеет тип ПК uuid
:
create table phone_calls (
id uuid not null constraint phone_calls_pkey primary key
-- ...
);
Поле data
имеет другую структуру, которая зависит от его стат.тип.Пример для продолжительности вызова :
{
"call_duration": 120.0
}
или для выпадений :
{
"dropouts": [5.23, 40.92]
}
Давайте поиграем с данными:
insert into phone_calls_statistics values
('9fc1f6c3-a9d3-4828-93ee-cf5045e93c4c', 'CALL_DURATION', '{"call_duration": 100.0}'),
('86d1a2a6-f477-4ed6-a031-b82584b1bc7e', 'CALL_DURATION', '{"call_duration": 110.0}'),
('cfd4b301-bdb9-4cfd-95db-3844e4c0625c', 'CALL_DURATION', '{"call_duration": 120.0}'),
('39465c2f-2321-499e-a156-c56a3363206a', 'CALL_DURATION', '{"call_duration": 130.0}'),
('9fc1f6c3-a9d3-4828-93ee-cf5045e93c4c', 'UNEXPECTED_HANGUP', '{"unexpected_hungup": true}'),
('86d1a2a6-f477-4ed6-a031-b82584b1bc7e', 'UNEXPECTED_HANGUP', '{"unexpected_hungup": true}'),
('cfd4b301-bdb9-4cfd-95db-3844e4c0625c', 'UNEXPECTED_HANGUP', '{"unexpected_hungup": false}'),
('39465c2f-2321-499e-a156-c56a3363206a', 'UNEXPECTED_HANGUP', '{"unexpected_hungup": false}');
Получите среднее, минимальное и максимальное время разговора:
select
avg((pcs.data ->> 'call_duration')::float) as avg,
min((pcs.data ->> 'call_duration')::float) as min,
max((pcs.data ->> 'call_duration')::float) as max
from
phone_calls_statistics pcs
where
pcs.stat_type = 'CALL_DURATION';
Получите количество неожиданных зависаний:
select
sum(case when (pcs.data ->> 'unexpected_hungup')::boolean is true then 1 else 0 end) as hungups
from
phone_calls_statistics pcs
where
pcs.stat_type = 'UNEXPECTED_HANGUP';
Я считаю, что это решение очень простое и гибкое,имеет хороший потенциал производительности и отличную масштабируемость.Основная таблица имеет простой индекс;все запросы будут выполняться внутри него.Вы всегда можете продлить номер стат.типы и их вычисления.
Живой пример: https://www.db -fiddle.com / f / auATgkRKrAuN3jHjeYzfux / 0