Ceea ce ai tu este o problemă clasică de running sum, care nu prea poate fi rezolvată eficient, frumos şi corect (adică folosind doar facilităţi documentate) în SQL Server. Trebuie să renunţi la una dintre "eficient", "frumos" sau "corect". La care renunţi?
Dacă renunţi la "eficient", atunci rezultă ceea ce ai (eventul poţi să faci un index compus, pe Cont, DataInr şi NDS, dar nu ajută la mare lucru).
Dacă renunţi la "frumos", atunci foloseşti un cursor ca să completezi coloana respectivă în tabelă. În acest caz (la zeci de mii de înregistrări), cursorul va merge mult mai repede decât query-ul actual.
Dacă renunţi la "corect", atunci foloseşti o facilitate nedocumentată şi completezi acea coloană printr-un UPDATE de genul @variabila=coloana=expresie, astfel:
USE tempdb
GO
CREATE TABLE A_lstFisaCont (
cont varchar(20) not null,
datainr datetime null,
nds int not null,
coduser int not null default (1),
debit money not null,
credit money not null,
sold money null
)
GO
INSERT INTO A_lstFisaCont (cont, datainr, nds, debit, credit)
SELECT '456' as cont, NULL as datainr, 1 as nds, 200 as debit, 0 as credit
UNION ALL SELECT '1012' as cont, NULL as datainr, 1 as nds, 0 as debit, 200 as credit
UNION ALL SELECT '5121' as cont, '20080101' AS datainr, 2 as nds, 200 as debit, 0 as credit
UNION ALL SELECT '456' as cont, '20080101' AS datainr, 2 as nds, 0 as debit, 200 as credit
UNION ALL SELECT '5121' as cont, '20080102' AS datainr, 3 as nds, 10 as debit, 0 as credit
UNION ALL SELECT '766' as cont, '20080102' AS datainr, 3 as nds, 0 as debit, 10 as credit
UNION ALL SELECT '5121' as cont, '20080103' AS datainr, 4 as nds, 12 as debit, 0 as credit
UNION ALL SELECT '766' as cont, '20080103' AS datainr, 4 as nds, 0 as debit, 12 as credit
UNION ALL SELECT '5121' as cont, '20080103' AS datainr, 5 as nds, 13 as debit, 0 as credit
UNION ALL SELECT '766' as cont, '20080103' AS datainr, 5 as nds, 0 as debit, 13 as credit
UNION ALL SELECT '766' as cont, '20080131' AS datainr, 6 as nds, 35 as debit, 0 as credit
UNION ALL SELECT '121' as cont, '20080131' AS datainr, 6 as nds, 0 as debit, 35 as credit
GO
SELECT * FROM A_lstFisaCont ORDER BY cont, datainr, nds
GO
DECLARE @cont varchar(20), @sold money
UPDATE x SET
@sold=sold=debit-credit+CASE WHEN @cont=cont THEN @sold ELSE 0 END,
@cont=cont
FROM (SELECT TOP 9223372036854775807 * FROM A_lstFisaCont ORDER BY cont, datainr, nds) x
GO
SELECT * FROM A_lstFisaCont ORDER BY cont, datainr, nds
GO
--DROP TABLE A_lstFisaCont
Totuşi, nu recomand această variantă, pentru că nu e documentat niciunde că UPDATE-ul se va face în ordinea specificată în ORDER BY-ul din subquery (e doar o conincidenţă). Drept urmare, recomand varianta cu cursor, cel puţin până când se va implementa în SQL Server funcţiile agregate în care se poate preciza ordinea. Pentru ca acest lucru să se întâmple cât mai curând, vă rog să votaţi sugestia următoare pe Connect (eventual şi celelalte sugestii menţionate în http://www.insidetsql.com/OVER_Clause_and_Ordered_Calculations.doc):
https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=254387
Răzvan
PS. Clauza WHERE din query-ul tău putea fi scrisă mai simplu astfel:
where cont=fc.cont and coduser=1
and (datainr is null or fc.datainr>datainr or fc.datainr=datainr and fc.nds>=nds)