Вот получился такой скрипт:
/*
Поиск расходных документов, просроченных по времени
*/
--Результирующая таблица (здесь временная, но вообще постоянная) :
CREATE TABLE #DocDebt(
[DTcheck] [datetime] NOT NULL, -- контрольная дата, на которую осуществляется расчет
[DTdoc] [datetime] NOT NULL,
[IDCust] [varchar](13) NOT NULL,
[IdDoc] [varchar](13) NOT NULL,
[DocSum] [decimal](14, 4) NULL,
[DocDebt] [decimal](14, 4) NULL,
[Days] [int] NULL -- сколько дней просрочки платежа по документу
) ON [PRIMARY]
CREATE UNIQUE CLUSTERED INDEX [PK_DocDebt_DT_Cust_Doc] ON #DocDebt
(
[DTdoc] ASC,
[IDCust] ASC,
[IdDoc] ASC
)
-- Контрольная Дата на которую надо получить просроченные документы
declare @dtCheck datetime
set @dtCheck = '2010-06-15' --например
set nocount on
--------------------------------------------------
-- Переменные для курсора по клиентам
declare @custID varchar(9), @custdebt money
--------------------------------------------------
-- Переменные для курсора поиска просроченных документов
declare @dt datetime, @iddoc varchar(9), @debkred int, @sum money
--------------------------------------------------
-- Промежуточные расчеты
declare @DEBTdoc money, @debtTotal money
--------------------------------------------------
-- КУРСОР Получить долги клиента на контрольную дату
declare CURR_Cust cursor for
select
cust.id
,CustDebt = sum(case when dbt.debkred=1 then -1*doc.docsum else doc.docsum end ) -- debkred=1 оплата
from docList doc
join Customers cust on cust.id = doc.idcust
where
doc.dtdoc <= @dtCheck
Group by cust.id
Having sum(case when dbt.debkred=1 then -1*doc.docsum else doc.docsum end ) >0 --ДОЛГ клиента нам > 0
--------------------------------------------------
open CURR_Cust
fetch next from CURR_Cust into @custID, @custdebt
---------------------------------------------------
WHILE @@FETCH_STATUS = 0
BEGIN
set @DEBTdoc = @custdebt -- начинаем с долга клиента,
set @debtTotal = @custdebt -- долг по расходному документу
print 'Проверка клиента ' + @CustID + ' на дату ' + cast(@dtCheck as varchar(16)) +' конечный долг = ' + str(@DEBTdoc)
--------------------------------------------------------------------------
-- КУРСОР сделать цикл для поиска просроченных документов
declare CURR_Doc CURSOR FOR
select
DocDate
,IDDOC
,debkred
,docSum
from docList doc
where IDcust = @custID
and dtDoc <= @dtCheck
order by dtDoc desc, idDoc desc
open CURR_Doc
fetch next from CURR_Doc into @dt, @iddoc, @docNo, @debkred, @sum, @DocDef
--------------------------------------------------------------------------
WHILE @@FETCH_STATUS = 0
BEGIN
-- при достижении нулевого долга прекратить поиск, т.к. неоплаченных документов больше нет
if @DEBTdoc <=0 break
-- промежуточный итог долга на этот документ
set @DEBTdoc = case @debkred when 1 then @DEBTdoc+@sum else @DEBTdoc-@sum end
-- Если этот документ - расходная накладная, то добавить ее в таблицу
if @sum >0 and @debkred=0
Begin
insert into #DocDebt (DTcheck, DTdoc, IDCust, IdDoc, DocSum, DocDebt, Days)
Values( @dtCheck, @dt, @CustID, @IdDoc, @sum,
case when @sum < @debtTotal then @sum else @debtTotal end ,
datediff(day, @dt, @dtCheck))
-- если док уже частично оплачен. то дальше не проверяем
if @debtTotal < @sum Break
-- промежуточный итог долга после документ
set @debtTotal = @DEBTdoc
End
fetch next from CURR_Doc into @dt, @iddoc, @docNo, @debkred, @sum, @DocDef
END -- цикл курсор по документам
close CURR_Doc
Deallocate CURR_Doc
--------------------------------------------------------------------------
fetch next from CURR_Cust into @custID, @custdebt
END -- цикл курсор по клиентам
close CURR_Cust
Deallocate CURR_Cust
-------------------------------------------------------------
Select * from #DocDebt
order by DTdoc desc
Скрипт работает 1 час 20 минут и рассчитывает данные за 1 день.
Может подскажет кто как оптимизировать?