powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Получение динамики изменений определенного поля
2 сообщений из 2, страница 1 из 1
Получение динамики изменений определенного поля
    #39400488
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хочу спросить совета.

Если таблица клиентов CUSTOMERS(CUSTOMER_ID,...).
Есть таблица услуг SERVICES(SERVICE_ID,CUSTOMER_ID,LOGIN,...,STATUS_ID), которые подключены клиентам.
Есть версионная таблица статусов услуг, по которой можно получить статус на любой момент SERVICE_STATUS(SERVICE_ID,STATUS_ID,DATE_BEG,DATE_END).
Мне нужно за 6 лет получить посуточный отчет с полями: дата, кол-во клиентов на начало периода, приток, отток, кол-во клиентов на конец периода. Клиентом считается клиент, у которого есть хотя бы одна услуга с положительным статусом (STATUS_ID>0).

У каждого клиента в среднем по две услуги, общее количество клиентов можно принять за 5000, поэтому если просто построить таблицу на каждый день за 6 лет, то получится порядка 20кк записей и такое «лобовое» решение неразумно.
Сравнивать я думаю не наборы услуг, а их количества:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
select C.CUSTOMER_ID
, sum(case when SS.STATUS_ID > 0 then 1 end) as CNT_ON
, sum(case when SS.STATUS_ID < 0 then 1 end) as CNT_OFF
from CUSTOMERS C
join SERVICES S on (S.CUSTOMER_ID = C.CUSTOMER_ID)
join SERVICE_STATUS SS on (SS.SERVICE_ID = S.SERVICE_ID and SS.DATE_BEG <= :moment and (SS.DATE_END is null or SS.DATE_END > :moment))
group by C.CUSTOMER_ID


В результате я получаю по каждому клиенту количество подключенных услуг и приток/отток могу определять по полю CNT_ON.
Фактически мне нужно посчитать дельту между текущим и следующим днем по полю CNT_ON, положительную разницу записать в отток, отрицательную разницу записать в приток, и просуммировать по дням.

Теперь я не могу решить, что делать дальше.
Я вижу три варианта.

1. Формирую сводную таблицу на каждый день. Клиенты с CNT_ON>0 будут не все (оценочно около 4000), поэтому в этой таблице окажется около 8кк записей. Тоже не очень разумно, но уже более реально.

2. Считать дельту прямо в запросе, с помощью аналитической функции — что-то типа lead(sum(case when SS.STATUS_ID>0 then 1 end)) - sum(case when SS.STATUS_ID>0 then 1 end).

3. В цикле формировать посуточную сводную таблицу, но не за весь период, а за месяц, после чего посчитать дельту за месяц и начать следующую итерацию цикла.

Какой вариант правильнее?

________________________
Мы смотрим с оптимизмом...
...в оптический прицел.
...
Рейтинг: 0 / 0
Получение динамики изменений определенного поля
    #39400495
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
По второму варианту составил такой запрос (потроха внутреннего запроса убрал).
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
select D
, CNT as QTY_START
, case
    when lead(CNT) over(order by D) > CNT
    then lead(CNT) over(order by D) - CNT
  end as QTY_PLUS
, case
    when lead(CNT) over(order by D) < CNT
    then CNT - lead(CNT) over(order by D)
  end as QTY_MINUS
, lead(CNT) over(order by D) as QTY_STOP
from
(
  select D
  , sum(case when CNT > 0 then 1 end) CNT
  from
  (
    with CAL as
    (
      select add_months(DATE'2016-01-01', NUM-1) as D
      from BM_NUMBER
      where NUM between 1 and 12
    )
    select CAL.D as D
    , C.CUSTOMER_ID
    , sum(case when SS.STATUS_ID > 0 then 1 end) as CNT
    from CUSTOMERS C
    join CAL on (CAL.D is not null)
    join SERVICES S on (S.CUSTOMER_ID = C.CUSTOMER_ID)
    join SERVICE_STATUS SS on (SS.SERVICE_ID = S.SERVICE_ID
      and SS.DATE_BEG <= CAL.D
      and (SS.DATE_END is null or SS.DATE_END > CAL.D))
    group by CAL.D, C.CUSTOMER_ID
  )
  group by D
)
order by 1


На реальных данных за период в один месяц он выполняется около 8 секунд.
Но прежде чем запускать запрос за 6 лет, хочу его показать, может быть я в запросе чего-нибудь недосмотрел.
Ну и если возможно, хотелось бы избавиться от лишней вложенности.
...
Рейтинг: 0 / 0
2 сообщений из 2, страница 1 из 1
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Получение динамики изменений определенного поля
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]