Yürüyen bakiyenin (gridin her satırında o satıra / o tarihe ait bakiyeyi göstermesi) tek bir sql sorgusu ile (ki sorgu nasıl olursa olsun) yapılması mümkün değildir. Gerçi subselect ler ve subselect içinde sum lar ile buna yakın görünümler (veya belkide tamamen istenen) teoride sağlanabiliyor ancak pratikte anlaşılması, hata ayıklanması, bakımı çok zor bir kod çıkıyor ortaya ve performans da tartışılır.
Bunun çözümü için rdbms lerde cursor denen bir olay var.
cursor, tıpkı delphi deki tquery nesnesi gibi çalışıyor. Yani bir rdbms de bir stored procedure içinde bir select sorgusu yazıyorsunuz ve (where ile süzerek veya süzmeyerek) çektiğiniz veriyi bir cursor a bağlıyorsunuz. Bundan sonra bu cursor üzerinde ileri geri (Tquery nin First, Last, Next, Prev ine bezer şekilde) hareket ediyorsunuz (Oracle, MsSql, Firebird) (Mysql şu an durum nedir bilmiyorum).
Bu durumda, bakiye hesap kodunuz tıpkı client daki gibi oluyor.
Bunun avantajı hiç hata oluşturmayacak sağlam bir kodunuz oluyor çünki sonuçlarınız her seferinde hesaplanıyor ve kodunuz çok sade oluyor.
Ancak performans dezavantajı var. Ben bunu ilk denediğimde, çok uzun sorgu süreleri yüzünden vazgeçtim. O zamanlar indeksleri nasıl kullanacağımı bilmiyordum.
Zaman içinde fb gelişti ve hızlandı. Bir müsait zamanda tekrar deneyeceğim. Belki de artık performans sıkıntısı yoktur.
{ Buna sağlıksız bir alternatif, (benim de zamanında yaptığım bir hata), tabloda bakiye sütununun olması ve her insert işleminde o satırın bakiyesinin hesaplanıp kaydedilmesi. Bu yapının kusuru, araya kayıt eklemelerde kodun kırılması halinde sonuçlar tutarsız oluyor. İşlemler mutlaka transaction ile yapılmalı. Bir de bu kayıt eklemeler sırasında büyük miktarda veri güncellendiği (ve bu yüzden kilitlendiği) için lock conflict hataları oluyor. Eğer yine de destek vermek zorunda olduğunuz böyle bir kodunuz varsa, lock conflictlere çözüm olarak transaction parametrelerinde wait ile nowait arasındaki farka bakmanızı öneririm.}
Firebird site kaynak: http://www.firebirdsql.org/refdocs/lang ... are-cursor
Yine fikir açısından yazdığım yürüyen bakiye kodu (Benzer bir mantık kullansa da cursor kullanmadığına dikkat). Daha iyilerini bu veya başka forumlarda bulmak mümkün olabilir :
Kod: Tümünü seç
SET TERM ^ ;
CREATE PROCEDURE SP_BILESEN_HAREKET (
BILESEN_ID_ Integer,
TARIH1 Timestamp,
TARIH2 Timestamp )
RETURNS (
BILESEN_ID Integer,
TARIH_SAAT Timestamp,
MIKTAR Decimal(18,4),
GIR Decimal(18,4),
CIK Decimal(18,4),
BAKIYE_GIR Decimal(18,4),
BAKIYE_CIK Decimal(18,4),
BAKIYE_GEN Decimal(18,4) )
AS
begin
bakiye_gen = 0;
bakiye_gir = 0;
bakiye_cik = 0;
bilesen_id = bilesen_id_;
if(:tarih1 is null) then
select min(tarih_saat)
from bilesen_hareket
where bilesen_id = :bilesen_id
into :tarih1;
else begin
select
sum(miktar)
from bilesen_hareket
where miktar>0 and bilesen_id = :bilesen_id and tarih_saat < :tarih1
into :bakiye_gir;
select
sum(miktar)
from bilesen_hareket
where miktar<0 and bilesen_id = :bilesen_id and tarih_saat < :tarih1
into :bakiye_cik;
end --else begin
if(:tarih2 is null) then
tarih2 = CURRENT_TIMESTAMP;
for
select
tarih_saat, miktar
from bilesen_hareket
where bilesen_id = :bilesen_id and tarih_saat between :tarih1 and :tarih2
order by tarih_saat
into :tarih_saat, :miktar
do begin
if(miktar>0) then
gir =miktar; else
gir =0;
if(miktar<0) then
cik =miktar; else
cik =0;
bakiye_gir =bakiye_gir + gir;
bakiye_cik =bakiye_cik + cik;
bakiye_gen =bakiye_gen + miktar;
suspend;
end
end^
SET TERM ; ^