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

На тестовом наборе данных я обкатал два варианта учета.
Но на рабочей базе объем данных на 4 порядка больше, поэтому хотелось бы спросить предварительно совета.

1 вариант - если упрощенно, то я фиксирую во вспомогательной таблице статус клиента (действующий/недействующий) на каждую дату, а затем делаю два джойна с календарем и с помощью группировки определяю приток и отток:
Код: 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.
with S as
(
  select ... as D        --дата
  , ... as CUSTOMER_ID   --идентификатор клиента
  , ... as STATUS        --статус клиента на указанную дату, 1 или 0
  from ...
)
select CAL.D
, sum(SC.STATUS) as QTY_BEGIN
, sum(SN.STATUS) as QTY_END
, sum(nvl(SN.STATUS,0) - nvl(SC.STATUS,0)) as QTY_DELTA
, sum(case
    when nvl(SN.STATUS,0) > nvl(SC.STATUS,0)
    then 1
  end) as QTY_INCOME
, sum(case
    when nvl(SN.STATUS,0) < nvl(SC.STATUS,0)
    then 1
  end) as QTY_OUTCOME
from CUSTOMERS C --таблица клиентов
join DYNRPT_CALENDAR_DAY CAL on (CAL.D is not null) --календарь с датами
left join S SC on (SC.CUSTOMER_ID = C.CUSTOMER_ID and SC.D = CAL.D)
left join S SN on (SN.CUSTOMER_ID = C.CUSTOMER_ID and SN.D = CAL.D+1)
where (SC.CUSTOMER_ID is not null or SN.CUSTOMER_ID is not null)
group by CAL.D


Скрипт запускался на рабочей базе, считает точно и даже не очень долго (быстрее, чем я ожидал), но мне не нравится его идея — у меня порядка 10к клиентов и эти 10к записей нужно соединять с каждым днем календаря, а затем снова группировать по дням. Например при выполнении посуточного отчета за 6 лет во вспомогательной таблице будет почти 30кк записей, которые затем нужно будет сгруппировать.

2 вариант я на рабочей базе пока не запускал, но его идея другая. Я на каждый день считаю количество действующих клиентов и количество недействующих клиентов. Затем выполняю второй запрос с аналитикой и вычисляю отток (разница по количеству недействующих клиентов между следующим и текущим периодом) и вычисляю приток (разница между количеством действующих клиентов плюс отток).
Запрос получится примерно такой:
Код: 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_ACTIVE as QTY_BEGIN
, lead(CNT_ACTIVE) over (order by D) as QTY_END
, lead(CNT_INACTIVE) over (order by D)
- CNT_INACTIVE as QTY_OUTCOME
, lead(CNT_ACTIVE) over (order by D)
- CNT_ACTIVE
+ (lead(CNT_INACTIVE) - CNT_INACTIVE) as QTY_INCOME
from
(
  select D
  , sum(decode(ACTIVE,1,CNT)) as CNT_ACTIVE
  , sum(decode(ACTIVE,0,CNT)) as CNT_INACTIVE
  from
  (
    select trunc(...) as D --дата
    , case
        when ... then 0
        when ... then 0
        when ... then 0
        when ... then 0
        else 1
      end as ACTIVE        --статус клиента на указанную дату, 1 или 0
    , count(*) as CNT      --количество клиентов на указанную дату с указанным статусом
    from ...
    group by D
    , case
        when ... then 0
        when ... then 0
        when ... then 0
        when ... then 0
        else 1
      end as ACTIVE
  )
  group by D
)
order by D


Выглядит мой взгляд лучше, но мне не нравится case...end в выражении группировки, он будет достаточно сложным.

________________________
Мы смотрим с оптимизмом...
...в оптический прицел.
...
Рейтинг: 0 / 0
Сопоставление множеств и определение разницы
    #39402519
kaldorey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alibek B.,

Существует решение для хранения итогов, которое к тому же может и не сильно нагружать основную таблицу. Это матвью.
Как вариант можно составить scd понравившегося типа (для меня 2 либо 4 в зависимости от базы) в закреплением флага статуса. Сверху прикрутить итоги. К тому же, если явно создать цифры по таким правилам, в большинстве случаев отпадет необходимость еженощной валидации итогов и исходных данных.
Если же формировать данные по второму способу, то нет гарантии, что за прошлые дни физически не удалят данные и не пострадает итог (а значит опять проверки)
...
Рейтинг: 0 / 0
Сопоставление множеств и определение разницы
    #39402528
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Второй способ и основан на том, что данные не удаляются.
Через интерфейс информационной системы удалить их невозможно, поэтому количество недействующих клиентов (в теории) никогда не будет уменьшаться.
...
Рейтинг: 0 / 0
Сопоставление множеств и определение разницы
    #39402536
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Почитал про SCD.
В теории это наверное было бы лучшим решением.
В используемой информационной системе для ряда параметров используется тип 2.
Но для параметров, от которых зависит действительность/недействительность клиента, изменение значений не фиксируется, а модификация информационной системы слишком сложна.

Что касается материализованного представления, не могли бы вы пояснить, что именно имеется ввиду?
Мне на ум не приходит способа, который бы в этой задаче позволил их использовать.
В моем случае информация задним числом никогда не меняется, поэтому я рассчитывал просто добавить вспомогательную таблицу итогов, которую за весь прошедший период я заполню однократно, а затем буду пополнять каждый месяц.
...
Рейтинг: 0 / 0
Сопоставление множеств и определение разницы
    #39402538
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alibek B.2 вариант я на рабочей базе пока не запускал
Запустил, отлично работает, гораздо быстрее первого варианта. И насколько я проверил, считает точно.
К сожалению реальная задача у меня чуть более сложная, клиенты дополнительно распределены по группам и мне нужно считать динамику в разрезе групп. А сложность в том, что есть специальная группа для отключаемых клиентов, куда они перемещаются перед отключением, и в результате отток учитывается именно в этой специальной группе.
...
Рейтинг: 0 / 0
5 сообщений из 5, страница 1 из 1
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Сопоставление множеств и определение разницы
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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