powered by simpleCommunicator - 2.0.52     © 2025 Programmizd 02
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Задача разбивки-размножения строк по периодам действия
25 сообщений из 29, страница 1 из 2
Задача разбивки-размножения строк по периодам действия
    #39951176
Dmitry_z
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Друзья, добрый день.
Имеется одна с виду простая задачка, которая, однако плохо поддаётся.

В базе есть таблица сделок(очень большая, миллионы записей) со ссылкой на клиента, плюс сама таблица клиентов(также огромная).
У записей в каждой из таблиц есть период действия (см. пример с запросом ниже). "01.01.3000" - дата открытой записи.

Цель состоит в том, чтобы "размножить" исходную запись сделки, разбив по периодам действия её и клиента к ней относящегося.

То есть для сделки с id =1 результат должен получиться таким:
Код: plsql
1.
2.
3.
4.
deal_id     from_date     to_date
    1      01.01.2019    01.08.2019
    1      02.08.2019    05.08.2019
    1      06.08.2019    01.01.3000



Пока удалось только собрать запрос, который срабатывает по одной сделке(если больше - получается каша, оно и понятно с FULL JOIN), и он явно далёк от хорошего.

Код: 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.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
WITH deals_base AS ( -- а-ля в таблица в базе
                    SELECT 1 AS ID,
                           to_date('02.08.2019', 'dd.mm.yyyy') AS from_date,
                           to_date('01.01.3000', 'dd.mm.yyyy') AS to_date,
                           2 AS client_id
                      FROM dual
                    UNION
                    SELECT 3 AS ID,
                           to_date('08.02.2019', 'dd.mm.yyyy') AS from_date,
                           to_date('01.01.3000', 'dd.mm.yyyy') AS to_date,
                           4 AS client_id
                      FROM dual
               ),

   clients_base AS ( -- а-ля в таблица в базе                 
                    SELECT 2 AS client_id,
                           to_date('01.01.2019', 'dd.mm.yyyy') AS from_date,
                           to_date('05.08.2019', 'dd.mm.yyyy') AS to_date
                      FROM dual
                    UNION    
                    SELECT 2 AS client_id,
                           to_date('06.08.2019', 'dd.mm.yyyy') AS from_date,
                           to_date('01.01.3000', 'dd.mm.yyyy') AS to_date
                      FROM dual    
                    UNION 
                    SELECT 4 AS client_id,
                           to_date('05.02.2019', 'dd.mm.yyyy') AS from_date,
                           to_date('01.10.2019', 'dd.mm.yyyy') AS to_date
                      FROM dual    
                    UNION
                    SELECT 4 AS client_id,
                           to_date('02.10.2019', 'dd.mm.yyyy') AS from_date,
                           to_date('01.01.3000', 'dd.mm.yyyy') AS to_date
                     FROM dual                         
              ),

   deals AS ( -- сам запрос, как в базе
              SELECT d.id,
                     d.from_date AS deal_from_date,
                     d.to_date AS deal_to_date,
                     c.from_date AS client_from_date,
                     c.to_date AS client_to_date
                FROM deals_base d
                JOIN clients_base c
                  ON c.client_id = d.client_id
                WHERE d.id = 1  -- конкретная сделка
             ),

     -- выносим периоды по сущностям
   periods AS (SELECT deal_from_date AS from_date,
                      deal_to_date AS to_date,
                      'x' AS t -- вспомогательный столбец-константа для оконной функции
                 FROM deals d
               UNION
               SELECT client_from_date AS from_date,
                      client_to_date AS to_date,
                      'x' AS t
                 FROM deals d              
               )  ,                      

  deal_period AS (
                   SELECT d.id AS deal_id,
                   p.from_date,
                   nvl(LEAD(p.from_date -1)
                       over(PARTITION BY p.t ORDER BY p.from_date),
                       to_date('01.01.3000', 'dd.mm.yyyy')   )       AS to_date
                     FROM deals d
                     FULL JOIN periods p
                        ON 1 = 1
     )
    SELECT *
      FROM deal_period dp
    WHERE dp.from_date <= dp.to_date
      and dp.to_date >= dp.from_date
    ORDER BY 1, 2;



Задача не разовая, предполагается её регулярное выполнение, пусть и с небольшим ограничениями объёмов.
Подскажите, пожалуйста, в какую сторону копать, чтобы добиться более оптимального решения задачи во вменяемое время с учётом большого кол-ва данных.
Изначально предполагалось решать одним запросом, но теперь рассматриваю любые варианты.

Вообще насколько критично, если в большом запросе с конструкцией with происходит многократное использование объёмного подзапроса(как в примере выше при использовании union)? Oracle ведь не перечитывает каждый раз исходную таблицу, верно?
Само собой оперативка тоже нерезиновая.

Заранее благодарю за помощь.
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39951261
123йй
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dmitry_zТо есть для сделки с id =1 результат должен получиться таким:
Вы смешали даты из таблицы сделок и клиентов и считаете это верным результатом ?

одно из решений Объединение временных промежутков
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39951321
Dmitry_z
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
123йй
Dmitry_zТо есть для сделки с id =1 результат должен получиться таким:

Вы смешали даты из таблицы сделок и клиентов и считаете это верным результатом ?


Такова постановка задачи.
То есть если у клиента поменялся какой-то атрибут, то текущая запись закрывается и открывается новая.
Сделка с этим клиентом также должна побиться на соответствующие интервалы, даже если эти атрибуты в конечном счёте не попадают в итоговый набор данных.
Но вариант, что таки-попадают я бы тоже предусмотрел, интересно, как составить запрос в этом случае.

Клиенты взяты для примера, могут быть и другие сущности.

За ссылки спасибо, погляжу.
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39951858
PuM256
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dmitry_z,

авторВообще насколько критично, если в большом запросе с конструкцией with происходит многократное использование объёмного подзапроса(как в примере выше при использовании union)? Oracle ведь не перечитывает каждый раз исходную таблицу, верно?

В таких ситуациях может произойти temp table transformation - вынесение CTE во временную таблицу. Смотрите план на предмет такого такого элемента, да и вообще, смотрите план. :)
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39951923
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dmitry_z

За ссылки спасибо, погляжу.

имхо
У Вас задача (грубо говоря) оратная к "обьеденению"

.....
stax
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39953800
SimonInBlues
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не вполне понятен требуемый алгоритм разбиения на периоды.
Например, почему у вас нет в результате периода с 05.08.2019 по 06.08.2019. Также не понятно, почему есть период 01.01.2019 по 01.08.2019, а не по 02.08.2019.
В общем, предлагаю свой вариант, может он поможет в решении задачи: все даты объединить в один столбец, а уже по нему считать периоды "с-по". Так для каждой даты "начала" брать дату "окончания" как ближайшую большую из дат.
Код: 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.
38.
39.
40.
41.
with 
deals_base as (
  select /*+ inline*/ 
    id, from_date, to_date, client_id
  from (
    select 1 id, to_date('02.08.2019', 'dd.mm.yyyy') from_date, to_date('01.01.3000', 'dd.mm.yyyy') to_date, 2 client_id from dual union all
    select 3 id, to_date('08.02.2019', 'dd.mm.yyyy') from_date, to_date('01.01.3000', 'dd.mm.yyyy') to_date, 4 client_id from dual
  )
),
clients_base as (     
  select /*+ inline*/
    client_id, from_date, to_date
  from (            
    select 2 client_id, to_date('01.01.2019', 'dd.mm.yyyy') from_date, to_date('05.08.2019', 'dd.mm.yyyy') to_date from dual union all
    select 2 client_id, to_date('06.08.2019', 'dd.mm.yyyy') from_date, to_date('01.01.3000', 'dd.mm.yyyy') to_date from dual union all
    select 4 client_id, to_date('05.02.2019', 'dd.mm.yyyy') from_date, to_date('01.10.2019', 'dd.mm.yyyy') to_date from dual union all
    select 4 client_id, to_date('02.10.2019', 'dd.mm.yyyy') from_date, to_date('01.01.3000', 'dd.mm.yyyy') to_date from dual
  )
),
deals as (
  select /*+ inline*/
    id, dt
  from (
    select d.id, d.from_date dt from deals_base d union all
    select d.id, d.to_date dt from deals_base d union all
    select d.id, c.from_date dt from deals_base d, clients_base c where d.client_id = c.client_id union all
    select d.id, c.to_date dt from deals_base d, clients_base c where d.client_id = c.client_id
  )
)
select
  id, from_date, to_date
from (  
    select
      d.id, d.dt from_date,
      (select min(m.dt) from deals m where m.id = d.id and m.dt > d.dt) to_date
    from deals d
  )
where
  id = 1 and 
  to_date is not null  
order by from_date


Результат:
Код: plsql
1.
2.
3.
4.
5.
ID	FROM_DATE	TO_DATE
1	01.01.2019	02.08.2019
1	02.08.2019	05.08.2019
1	05.08.2019	06.08.2019
1	06.08.2019	01.01.3000
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954012
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SimonInBlues,

Dmitry_z

У записей в каждой из таблиц есть период действия (см. пример с запросом ниже). "01.01.3000" - дата открытой записи.



обычно период действия непрырывный (нет пересечений и дырок)
тогда задачка сводится к простому


Код: 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.
with 
deals_base as (
  select /*+ inline*/ 
    id, from_date, to_date, client_id
  from (
    select 1 id, to_date('02.08.2019', 'dd.mm.yyyy') from_date, to_date('01.01.3000', 'dd.mm.yyyy') to_date, 2 client_id from dual union all
    select 3 id, to_date('08.02.2019', 'dd.mm.yyyy') from_date, to_date('01.01.3000', 'dd.mm.yyyy') to_date, 4 client_id from dual
  )
),
clients_base as (     
  select /*+ inline*/
    client_id, from_date, to_date
  from (            
    select 2 client_id, to_date('01.01.2019', 'dd.mm.yyyy') from_date, to_date('05.08.2019', 'dd.mm.yyyy') to_date from dual union all
    select 2 client_id, to_date('06.08.2019', 'dd.mm.yyyy') from_date, to_date('01.01.3000', 'dd.mm.yyyy') to_date from dual union all
    select 4 client_id, to_date('05.02.2019', 'dd.mm.yyyy') from_date, to_date('01.10.2019', 'dd.mm.yyyy') to_date from dual union all
    select 4 client_id, to_date('02.10.2019', 'dd.mm.yyyy') from_date, to_date('01.01.3000', 'dd.mm.yyyy') to_date from dual
  )
)
,t as (
 select id,from_date from deals_base where client_id=2
 union all /* union */
 select 0,from_date from clients_base c where client_id=2 
            and  not exists(select 1 from deals_base d where d.client_id=c.client_id and d.from_date=c.from_date)
)
select t.*
 ,lead(from_date,1,to_date('01.01.3000', 'dd.mm.yyyy')) over (order by from_date)-1  to_date
from t order by 2
/
SQL> /

        ID FROM_DATE  TO_DATE
---------- ---------- ----------
         0 01.01.2019 01.08.2019
         1 02.08.2019 05.08.2019
         0 06.08.2019 31.12.2999



конечно надо у автора уточнять
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954361
Dmitry_z
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SimonInBlues
Не вполне понятен требуемый алгоритм разбиения на периоды.
Например, почему у вас нет в результате периода с 05.08.2019 по 06.08.2019. Также не понятно, почему есть период 01.01.2019 по 01.08.2019, а не по 02.08.2019.

Период с 05.08.2019 по 06.08.2019 - лишний. В исходных данных времени нет, но представьте, что запись действует до 05.08.2019 23:59:59, а следующая с 06.08.2019 0:00:00.

SimonInBlues
В общем, предлагаю свой вариант, может он поможет в решении задачи: все даты объединить в один столбец...

Тоже пока пришёл к варианту "один столбец, пляшем от него".


Stax, ваш вариант чрезвычайно затратный по ресурсам, если выполнять его не по одной записи.
В таблице клиентов миллионы записей, в сделках и того больше.

Дополню задачку. Из архитектурных ограничений - результат должен выводиться с помощью табличных функций.
Плюс необходимо принудительно бить периоды по концам месяцов в зависимости от параметров, переданных в табличную функцию.

На данный момент остановился на том, что в основном запросе склеиваю сделки с клиентами таким образом, чтобы получить записи вида:
Код: plsql
1.
2.
3.
id      deal_to_date     deal_from_date   client_from_date  client_to_date	
1	 02.08.2019	   01.01.3000	   01.01.2019	     05.08.2019
1	 02.08.2019	   01.01.3000	   06.08.2019	     01.01.3000	


Далее отдельным запросом по каждой записи(табличная функция же) бью по периодам.
На первый взгляд выглядит не очень из-за переключения контекста, но на практике миллион записей бьётся минуты за 2, что вполне сносно с учётом большого количества записей в источнике.
Но теперь проблема в том, что в итоге получается достаточно много задвоенных записей, т.к. каждая из основного запроса обрабатывается отдельно.
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954366
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dmitry_z,

Вам надо разбить все сделки (миллионы), или одну/одного клиента?

если все,
то надо тестировать, мож дистинкт будет быстрее not exists(select 1 from deals_base d where d.client_id=c.client_id and d.from_date=c.from_date)
)

надеялся что есть индекс client_id, d.from_date

ps
с помощью табличных функций

я б шел (фетчил) последовательно попеременно по двух курсорах (сделок и клиента)
и в зависимости от дат пайпил, в том числе помесячно

зыы
про задвоение не понял, скорее бага алгоритма

.....
stax
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954372
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dmitry_z,

в таблице сделок для сделки больше одной строки допускается?

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
WITH deals_base AS ( -- а-ля в таблица в базе
                    SELECT 1 AS ID,
                           to_date('02.08.2019', 'dd.mm.yyyy') AS from_date,
                           to_date('04.08.2019', 'dd.mm.yyyy') AS to_date,
                           2 AS client_id
                      FROM dual
                    UNION ALL
                    SELECT 1 AS ID,
                           to_date('05.08.2019', 'dd.mm.yyyy') AS from_date,
                           to_date('21.08.2019', 'dd.mm.yyyy') AS to_date,
                           2 AS client_id
                      FROM dual
                    UNION ALL
                    SELECT 1 AS ID,
                           to_date('22.08.2019', 'dd.mm.yyyy') AS from_date,
                           to_date('01.01.3000', 'dd.mm.yyyy') AS to_date,
                           2 AS client_id
                      FROM dual



....
stax
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954375
Dmitry_z
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax
Dmitry_z,
Вам надо разбить все сделки (миллионы), или одну/одного клиента?

Все сделки со своими соответствующими клиентами, да.

Stax

я б шел (фетчил) последовательно попеременно по двух курсорах (сделок и клиента)
и в зависимости от дат пайпил, в том числе помесячно

Вот это я не понял. Типа в функцию с запросом клиентов залетать с конкретным id, который мы получили по сделке? А дальше?

Stax

зыы
про задвоение не понял, скорее бага алгоритма

Само собой, через какое-то время, возможно, удастся перекинуть сюда запрос, чтобы было понятнее.

Stax
Dmitry_z,
в таблице сделок для сделки больше одной строки допускается?

Разумеется. В качестве первичного ключа используется id_deal+to_date.
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954396
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dmitry_z

Вот это я не понял. Типа в функцию с запросом клиентов залетать с конкретным id, который мы получили по сделке? А дальше?

не
разбиваем почти для всех сделок
select * from table (f(x...даты например))

в f() курсор по сделках - внутренний по клиентах
если чесно, лень кодировать IFы ...

....
stax
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954550
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dmitry_z

Вот это я не понял. Типа в функцию с запросом клиентов залетать с конкретным id, который мы получили по сделке? А дальше?

шаблон
Код: 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.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
create or replace FUNCTION stax_pp
return stax_ot
PIPELINED is
 v_id number;
 v_cl number;
 v_dat date;
 v_idx varchar2(8);
 type t_dat is table of date index by varchar2(8); --index by date не спахало
 vt_dat t_dat;
 procedure p_client(p_cid number,p_did number) is
 begin
   for rr in (select * from clients_base where client_id=p_cid) loop
     vt_dat(to_char(rr.from_date,'yyyymmdd')):=rr.from_date;
   end loop;
 end;
begin
  for r in (select * from deals_base order by id /*,from_date / to_date */) loop
     if nvl(v_id,r.id)<>r.id then
        p_client(v_cl,v_id);
/*
        --почему-то не сработало, не знаю почему
        for i in vt_dat.first .. vt_dat.last loop
           pipe row(stax_o(v_id,
        end loop;
*/
        --надеюсь что по дате отсортировано из=за index by, иначе упорядочить
        v_idx := vt_dat.first;
        WHILE (v_idx IS NOT NULL)
        LOOP
               v_dat:=vt_dat(v_idx);
               v_idx := vt_dat.NEXT(v_idx);
               pipe row(stax_o(v_id,v_dat,
                   (case when v_idx is null then to_date('01.01.3000', 'dd.mm.yyyy') else vt_dat(v_idx)-1 end)));
        END LOOP;
        vt_dat.delete; --мож и покрасивее есть очистка
     end if;
     v_id:=r.id;
     v_cl:=r.client_id;
     vt_dat(to_char(r.from_date,'yyyymmdd')):=r.from_date;
  end loop;
  p_client(v_cl,v_id);
  v_idx := vt_dat.first;
  WHILE (v_idx IS NOT NULL)
  LOOP
       v_dat:=vt_dat(v_idx);
       v_idx := vt_dat.NEXT(v_idx);
       pipe row(stax_o(v_id,v_dat,
               (case when v_idx is null then to_date('01.01.3000', 'dd.mm.yyyy') else vt_dat(v_idx)-1 end)));
  END LOOP;
end;
/
SQL> select * from deals_base;

        ID FROM_DATE  TO_DATE     CLIENT_ID
---------- ---------- ---------- ----------
         1 02.08.2019 01.01.3000          2
         3 08.02.2019 01.01.3000          4

SQL> select * from clients_base;

 CLIENT_ID FROM_DATE  TO_DATE
---------- ---------- ----------
         2 01.01.2019 05.08.2019
         2 06.08.2019 01.01.3000
         4 05.02.2019 07.08.2019
         4 08.02.2019 01.01.3000

SQL> select * from table(stax_pp);

        ID DATE_FROM  DATE_TO
---------- ---------- ----------
         1 01.01.2019 01.08.2019
         1 02.08.2019 05.08.2019
         1 06.08.2019 01.01.3000
         3 05.02.2019 07.02.2019
         3 08.02.2019 01.01.3000




......
stax
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954768
Dmitry_z
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax, здесь вы пытаетесь сортировать по символьному представлению даты.
Код: plsql
1.
v_idx := vt_dat.first;


Результат будет зависеть от NLS_SORT, да и в принципе работает это так себе.

Попробуйте с таким набором данных отсортировать:
Код: plsql
1.
2.
3.
4.
5.
 CLIENT_ID FROM_DATE  TO_DATE
---------- ---------- ----------
         2 01.01.2019 15.03.2019
         2 16.03.2019 05.08.2019
         2 06.08.2019 01.01.3000
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954776
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dmitry_z
Stax, здесь вы пытаетесь сортировать по символьному представлению даты.
Код: plsql
1.
v_idx := vt_dat.first;

Результат будет зависеть от NLS_SORT, да и в принципе работает это так себе.
Если ты такой умный, то продемонстрируй NLS-ненадёжность именно этого отображения даты в строку для использования в качестве индекса ассоциативного массива:
Код: plsql
1.
vt_dat(to_char(rr.from_date,'yyyymmdd')):=
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954783
Dmitry_z
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Elic
Если ты такой умный, то продемонстрируй NLS-ненадёжность именно этого отображения даты в строку для использования в качестве индекса ассоциативного массива:
Код: plsql
1.
vt_dat(to_char(rr.from_date,'yyyymmdd')):=


Не, не настолько умный. :)
Это не основной аргумент, просто в какой-то статье вычитал, что нужно быть осторожным в плане символьных индексов.
Каюсь, что в данный пример приплёл NLS_SORT.

А по сабжу есть мысли?
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954790
Dmitry_z
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
И по второму аргументу я тоже не прав.
Когда сам тестировал подобное, в качестве индекса использовал более классическое представление дат - dd.mm.yyyy.
В этом варианте, действительно, работает так себе.

У Stax же представление yyyymmdd, и сортировка по нему работает корректно.

Так что прошу прощения.
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954797
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dmitry_z
А по сабжу есть мысли?
Dmitry_z
Дополню задачку. Из архитектурных ограничений - результат должен выводиться с помощью табличных функций.
По мне - это облегчение/упрощение.

И чисто личное мнение: регулярное перемножения лярда на лям - бессмысленное с точки зрения практического смысла занятие.
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954821
Dmitry_z
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Elic
По мне - это облегчение/упрощение.

Вполне возможно, только я пока не понимаю, как это удачно реализовать.

Elic
И чисто личное мнение: регулярное перемножения лярда на лям - бессмысленное с точки зрения практического смысла занятие.

Тоже верно.
Это задача классификации сделок в хранилище. Утешает тот факт, что в ежедневном режиме количество сделок таки будет вменяемым, а полноценный пересчёт будет происходить, например, раз в неделю.
Однако за несколько часов он таки должен отрабатывать.
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954873
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dmitry_z
тешает тот факт, что в ежедневном режиме количество сделок таки будет вменяемым, а полноценный пересчёт будет происходить, например, раз в неделю.
Я может чего-то не понимаю, но как факты могут меняться задним числом, чтобы их постоянно пересчитывать из пустого в порожнее. Обсчитывай свежую делту.
Dmitry_z
Однако за несколько часов он таки должен отрабатывать.
С таким подходом два часа со временем неизбежно выдут за сутки. С фатальнейшими последствиями для бизнеса, не так ли?
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954888
Dmitry_z
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Elic
Я может чего-то не понимаю, но как факты могут меняться задним числом, чтобы их постоянно пересчитывать из пустого в порожнее. Обсчитывай свежую делту.

Могут поменяться правила классификации, поэтому пересчёт необходим.
Взгляд в прошлое всё-таки будет ограничен месяцем-кварталом, однако и это огромный объём.
Elic

С таким подходом два часа со временем неизбежно выдут за сутки. С фатальнейшими последствиями для бизнеса, не так ли?

Нашей команде архитекторы жёстко диктуют правила и рамки, к сожалению, на данном этапе мы практически ничего не можем изменить.
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954890
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dmitry_z
Могут поменяться правила классификации, поэтому пересчёт необходим.
Тогда твой пример клиент-сделка неадекватен?

Те, кто не могут инвалидировать подмножество (я подразумеваю малое) в связи с изменением чего-там, чтобы только его пересчитать, пересчитывают тупо всё. Так же проще :/
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954893
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dmitry_z
Stax, здесь вы пытаетесь

Пытался
Код: plsql
1.
2.
3.
4.
5.
        --почему-то не сработало, не знаю почему
        for i in vt_dat.first .. vt_dat.last loop
               dbms_output.put_line('pipe '||v_id||' '||vt_dat(i)||' i='||i);
               pipe row(stax_o(v_id,vt_dat(i),vt_dat(I)));
        end loop;



почему выбивает из-цикла не знаю
мож для type t_dat is table of date index by
использовать for i in vt_dat.first .. vt_dat.last loop неправильно

из цикла вылетает после первого же pipe, при count=3
вторая итерация выбивает из ф-ции по no data found

Код: 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.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
create or replace FUNCTION stax_pp2
return stax_ot
PIPELINED is
 v_id number;
 v_cl number;
 v_dat date;
 v_idx varchar2(8);
 type t_dat is table of date index by varchar2(8); --index by date не спахало
 vt_dat t_dat;
 procedure p_client(p_cid number,p_did number) is
 begin
   for rr in (select * from clients_base where client_id=p_cid) loop
     vt_dat(to_char(rr.from_date,'yyyymmdd')):=rr.from_date;
     dbms_output.put_line('client '||p_did||' '||rr.from_date||' '||vt_dat.count);
   end loop;
 end;
begin
  for r in (select * from deals_base order by id /*,from_date / to_date */) loop
     dbms_output.put_line('deal '||r.id||' '||r.from_date||' '||vt_dat.count);
     if nvl(v_id,r.id)<>r.id then
        p_client(v_cl,v_id);
        --почему-то не сработало, не знаю почему
        for i in vt_dat.first .. vt_dat.last loop
               dbms_output.put_line('pipe '||v_id||' '||vt_dat(i)||' i='||i);
               pipe row(stax_o(v_id,vt_dat(i),vt_dat(I)));
        end loop;
/*
        --надеюсь что по дате отсортировано из=за index by, иначе упорядочить
        v_idx := vt_dat.first;
        WHILE (v_idx IS NOT NULL)
        LOOP
               v_dat:=vt_dat(v_idx);
               v_idx := vt_dat.NEXT(v_idx);
               pipe row(stax_o(v_id,v_dat,
                   (case when v_idx is null then to_date('01.01.3000', 'dd.mm.yyyy') else vt_dat(v_idx)-1 end)));
        END LOOP;
*/
        vt_dat.delete;
     end if;
     v_id:=r.id;
     v_cl:=r.client_id;
     vt_dat(to_char(r.from_date,'yyyymmdd')):=r.from_date;
  end loop;
  p_client(v_cl,v_id);
  v_idx := vt_dat.first;
  WHILE (v_idx IS NOT NULL)
  LOOP
       v_dat:=vt_dat(v_idx);
       v_idx := vt_dat.NEXT(v_idx);
       pipe row(stax_o(v_id,v_dat,
               (case when v_idx is null then to_date('01.01.3000', 'dd.mm.yyyy') else vt_dat(v_idx)-1 end)));
  END LOOP;
end;
/
SQL> select * from table(stax_pp2);

        ID DATE_FROM  DATE_TO
---------- ---------- ----------
         1 01.01.2019 01.01.2019

deal 1 02.08.2019 0
deal 3 08.02.2019 1
client 1 01.01.2019 2
client 1 06.08.2019 >>3<<<
pipe 1 01.01.2019 i=20190101
SQL>
SQL> select * from deals_base order by id;

        ID FROM_DATE  TO_DATE     CLIENT_ID
---------- ---------- ---------- ----------
         1 02.08.2019 01.01.3000          2
         3 08.02.2019 01.01.3000          4

SQL> select * from clients_base ;

 CLIENT_ID FROM_DATE  TO_DATE
---------- ---------- ----------
         2 01.01.2019 05.08.2019
         2 06.08.2019 01.01.3000
         4 05.02.2019 07.08.2019
         4 08.02.2019 01.01.3000




....
stax
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954912
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Обычно в таких случаях я начинал с того, что получал таблицу интервалов (union исторических периодов или через вспомогательную таблицу-календарь), затем по каждому интервалу получал исторические значения всех атрибутов, а затем снова агрегировал периоды (если требовалось).
Результат получается избыточный, однако после этого итог проще понять и оптимизировать, чем пробовать сразу написать оптимальный запрос.
...
Рейтинг: 0 / 0
Задача разбивки-размножения строк по периодам действия
    #39954917
Dmitry_z
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Elic
Тогда твой пример клиент-сделка неадекватен?

Почему?
Elic
Те, кто не могут инвалидировать подмножество (я подразумеваю малое) в связи с изменением чего-там, чтобы только его пересчитать, пересчитывают тупо всё. Так же проще :/

Типа того. Бизнес хочет быть уверен, что после изменения правил и нажатия большой зелёной кнопки "счастье" все данные будут правильные и актуальные.
Другой вопрос, что архитекторы пока не очень понимают, как это всё будет в реальном режиме работать.
То есть с одной стороны можно было бы подмножество регулировать параметром табличной функции, но с другой - дополнительные арх. ограничения, в которых прописано, что параметры и вызовы табличной функции лежат в таблицах, а механизма быстрой корректировки и запуска с отсутствием коллизий нет.

Stax, попробуйте добавить в исходные данные по сделке ещё одну строку с периодом.
В результирующем наборе всё станет задваиваться, я пока на этом застрял.
То есть в PL/SQL табличной функции ещё как-то можно было бы проверять, что такая запись уже была, однако в исходных таблицах записи лежат в произвольном порядке, а если сортировать такой объём - о нормальной производительности можно забыть.
...
Рейтинг: 0 / 0
25 сообщений из 29, страница 1 из 2
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Задача разбивки-размножения строк по периодам действия
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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