powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Количество месяцев долга. Как получить одним запросом ?
8 сообщений из 8, страница 1 из 1
Количество месяцев долга. Как получить одним запросом ?
    #39392642
lolo-soft
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Я только начал познавать PL/SQL в Oracle 11g.
Задачу решил через организацию цикла.

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

Задача следующая:
1. Есть две таблицы: клиенты с их текущим балансом (customers) + суммы начислений за каждый месяц (calcs)

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
create table customers(
  cust_id number,
  balance number(15,2)  --- для должника balance < 0
);

create table calcs(
  month_calc date,
  cust_id number,
  calc_money number(15,2),  --- всегда положительное число
  pay_money number(15,2)   --- всегда положительное число
);



2. Нужно определить количество месяцев для условия: abs(минимальная СУММА по calc_money для cust_id) >= abs(balance для cust_id)

P.S. Мое решение: в цикле увеличивал отрицательный balance для cust_id на calc_money каждого месяца, начиная с текущего и "спускаясь" по месяцам в прошлое. Считал полученное кол-во месяцев до тех пор, пока balance >= 0 .
...
Рейтинг: 0 / 0
Количество месяцев долга. Как получить одним запросом ?
    #39393175
stax..
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
lolo-soft,

приведите Ваше решение, будет более понятно что Вам надо

напр month_calc месяц или дата? уникально или нет?

и желательно тестовые данные

гляньте на sum( calc_money) over (partition by cust_id order by month_calc date DESC)


......
stax
...
Рейтинг: 0 / 0
Количество месяцев долга. Как получить одним запросом ?
    #39395085
lolo-soft
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
stax , спасибо за ответ.

Тестовые данные:
Код: 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.
create global temporary table tmp_customer_debts(
    cust_id number,
    balance number (15,2) default 0,
    cnt_month smallint default 0,
    constraint PK_CUST_ID primary key (cust_id)
) on commit preserve rows;

insert into customers values(1,-200);
insert into customers values(2,-250);
insert into customers values(3,-300);
insert into customers values(4,-100);

declare
    i smallint:= 0;
    dd date:= to_date('2016.12', 'yyyy.mm'); 
    
begin
    loop
        insert into calcs values(add_months(dd,-i),1,50,0);
        insert into calcs values(add_months(dd,-i),2,50,0);
        insert into calcs values(add_months(dd,-i),3,50,0);
        insert into calcs values(add_months(dd,-i),4,50,0);
        
        i:= i + 1;
    exit when i > 10;
    end loop;
    
end;




Мое решение:
Код: 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.
declare
    s_month date := to_date('2016.12', 'yyyy.mm');
    i smallint := 0;
    c_balance number(15,2);
    c_money number(15,2); 
    
begin
    --очистить вр.таблицу
    execute immediate('truncate table tmp_customer_debts');
    
    --выбрать должников
    insert into tmp_customer_debts(cust_id, balance)
    select cust_id, balance
    from customers
    where balance <= -0.01;
        
    -- цикл по должникам
    for rec in ( select cust_id, balance from tmp_customer_debts ) loop
        i:= 0;
        
        c_balance:= rec.balance;
        c_money:= 0;
            
        loop
            select calc_money into c_money
            from calcs
            where month_calc = add_months(s_month, -i) and cust_id = rec.cust_id;
            
            --dbms_output.put_line('cust_id: '||rec.cust_id || '  c_money:' || c_money || '  c_balance:' || c_balance || '  i:' || i);
                
            c_balance:= c_balance + c_money;
            
            i:= i + 1;
        exit when (i = 10 or c_balance >= 0);
        end loop;
            
        update tmp_customer_debts
        set cnt_month = i
        where cust_id = rec.cust_id;        
    end loop;
end;    

select *
from tmp_customer_debts
...
Рейтинг: 0 / 0
Количество месяцев долга. Как получить одним запросом ?
    #39395667
fortnet
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
stax..lolo-soft,

приведите Ваше решение, будет более понятно что Вам надо

напр month_calc месяц или дата? уникально или нет?

и желательно тестовые данные

гляньте на sum( calc_money) over (partition by cust_id order by month_calc date DESC)


......
stax

Ну и дальше просто:
select cust_id,balance,count(*)
from (
select c.balance, s.cust_id, sum( calc_money) over (partition by s.cust_id order by month_calc DESC) s_sum
from calcs s ,customers c where s.cust_id=c.cust_id)
where balance+s_sum <=0
group by balance,cust_id
order by 1
...
Рейтинг: 0 / 0
Количество месяцев долга. Как получить одним запросом ?
    #39396501
stax..
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
lolo-soft,

получилось?

.....
stax
...
Рейтинг: 0 / 0
Количество месяцев долга. Как получить одним запросом ?
    #39396892
lolo-soft
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Спасибо ВСЕМ !!
Этот запрос работает. Основную задачу решает. Нужно будет учесть только один момент - если всех начислений не будет "хватать", чтобы "погасить" текущий баланс.

Решение от fortnet
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
select
    cust_id,
    balance,
    count(1) as cnt_month
from
    (
        select c.balance, s.cust_id, sum( calc_money) over (partition by s.cust_id order by month_calc DESC) as s_sum
        from
            sam_tmp_calcs s
            inner join sam_tmp_customers c on c.cust_id = s.cust_id
    )
where
    balance + s_sum <= 0 
group by
    cust_id, balance
order by 1
...
Рейтинг: 0 / 0
Количество месяцев долга. Как получить одним запросом ?
    #39396893
lolo-soft
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Правильно ли понимаю - как будет работать подзапрос " ...sum( calc_money) over (partition by s.cust_id order by month_calc DESC) as s_sum.... " - суммировать (группировать) значения calc_money для каждого месяца month_calc только из значений предыдущих месяцев, отсортированных по убыванию, для каждого cust_id ?
...
Рейтинг: 0 / 0
Количество месяцев долга. Как получить одним запросом ?
    #39396961
fortnet
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да, при отсутствии задания параметров окна работает по умолчанию так (согласно заданной сортировке).
Это можно посмотреть :
select cust_id, calc_money, month_calc , sum( calc_money) over (partition by s.cust_id order by month_calc DESC) s_sum
from calcs s
order by cust_id,month_calc desc;
...
Рейтинг: 0 / 0
8 сообщений из 8, страница 1 из 1
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Количество месяцев долга. Как получить одним запросом ?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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