[ gdjuric @ 10.02.2006. 16:29 ] @
Radim knjig. aplikaciju u C# i zelim da napravim stored proceduru koja ce da mi odradi izvestaj: kartica artikla. Dakle, ne da doradjujem dataset na klijentu, vec da mi sve odradi Sql server.

Select upit mi napravi tabelu sa kolonama, na primer: datum, ulaz, izlaz ... medjutim sledeca kolona : stanje, mora da se racuna od prvog reda pa do kraja.

Kako bi to bilo najbolje resiti ?

Pocetna ideja:
1. postaviti neku varijablu trenutno_stanje = 0
2. napraviti cursor
3. raditi fetch kolona ulaz i izlaz
4. racunati novo trenutno_stanje = trenutno_stanje + ulaz - izlaz
5. insertovati u temp tabelu podatke ulaz i izlaz i trenutno_stanje ...

Elegantnije resenje ? hvala
[ Fedya @ 10.02.2006. 16:37 ] @
Nisam siguran da sam 100% razumeo tvoje pitanje ali koliko sam shavtio treba ti nacin da izracunas vrednost za tu tvoju kolonu stanje.

Mislim da je tu najbolje resenje (ponavljam ako sam dobro shvatio pitanje) je da napravis UDF koji ti izracunava stanje i onda mozes da napises nesto ovako:

SELECT datum, ulaz, izlaz, RacunajStanje(idKolone) AS Stanje FROM...


Ako je to ono sto imas na umu reci, pa cemo detaljnije raspraviti ovo.
btw, izbegavaj upotrebu kursora kad god je to moguce.

[Ovu poruku je menjao Fedya dana 10.02.2006. u 17:39 GMT+1]
[ gdjuric @ 10.02.2006. 17:03 ] @
Da, sada kada procitam svoju poruku ... vidim i sam da nisam bio najjasniji

U stvari, meni treba da u svakom redu tabele, pocev od prvog reda imam podatak stanje, tj. stanje se menja u svakom redu ... stanje = stanje iz prethodnog reda + promena (ulaz ili izlaz) iz tekuceg reda ... i tako sve do kraja. To znaci da je u poslednjem redu stanje = ukupnom zbiru svih ulaza i izlaza.

Ne vidim kako bih to resio sem cursorom ?

Evo primera za fin.karticu (umesto ulaz/izlaz imamo duguje/potrazuje)



------------------------------------------------------------
declare @saldo money, @duguje money, @potrazuje money
declare karticakonto_cursor cursor for select duguje, potrazuje from ykarticakonto

create table #xkarticakonto (duguje money, potrazuje money, saldo money)
open karticakonto_cursor


select @saldo = 0
fetch next from karticakonto_cursor into @duguje, @potrazuje

while @@fetch_status=0
begin
select @saldo = @saldo + @duguje - @potrazuje
insert into #xkarticakonto values (@duguje, @potrazuje, @saldo)
fetch next from karticakonto_cursor into @duguje, @potrazuje
end

select * from #xkarticakonto
drop table #xkarticakonto
close karticakonto_cursor
deallocate karticakonto_cursor
------------------------------------------------------------

hmmm ... ovo radi, ali ...



[ Fedya @ 10.02.2006. 18:53 ] @
Pa zar onda nije
SELECT (sum(duguje) - sum(potrazuje)) AS Saldo FROM... ??


Mozda sam lupio ali meni tako izgleda.
[ gdjuric @ 10.02.2006. 19:23 ] @
Evo pojednostavljenog primera kartice.
Zaboravljam da nisu svi programeri kod nas programeri knjig. aplikacija (hvala Bogu) ...

Dakle ,

1. dan ulaz 100
2. dan ulaz 200
3. dan izlaz 50
4. dan ulaz 150
5. dan izlaz 200
_____________
konacno stanje: ulazi 450 - izlazi 250 = 200

a potrebno je korisniku prikazati:

1. dan ulaz 100, stanje=100
2. dan ulaz 200, stanje=300
3. dan izlaz 50, stanje=250
4. dan ulaz 150, stanje=400
5. dan izlaz 200, stanje=200

A sve je to decja igra, prema "cuvenom problemu otvorenih stavki" ...


[ Fedya @ 10.02.2006. 20:18 ] @
Ako imas incremental primary key, mozes kao sto sam prvi put rekao.

Napravi UDF nesto ovako:

Code:

CREATE function racunaj
(
    @id int
)
returns int
as
begin
declare @retVal int
    
SELECT @retVal = Sum(ulaz - izlaz) FROM testing WHERE id <= @id
return @retVal
end


onda mozes da napises ovako:

Code:

select ulaz, izlaz, dbo.racunaj(id) from testing
[ Fedya @ 10.02.2006. 20:28 ] @
I samo jos jedna mala dopuna.

Ne mora ID da bude u pitanju moze bilo koja druga jedinstvena vrednost po kojoj mozes da sortiras (npr datetime).
[ gdjuric @ 10.02.2006. 21:05 ] @
Zanimljiva ideja !

Izgleda jednostavnije nego resenje sa cursorom, mada mi se cini na prvi pogled da ce brzina izvrsavanja (cena) biti priblizna i u jednom i u drugom slucaju - za svaki red se poziva UDF , odnosno po jedan select ... probacu i jedno i drugo resenje na test podacima - tabela sa jedno 100.000 redova pa cu da postujem cifre.

hvala ...
[ Zidar @ 14.02.2006. 13:35 ] @
Ako radis u C#, verovatno je u pitanju neka web aplikacija. To veovatno znaci da u jednom momentu zelis da prikazes karticu artikla za tacno jedna artikl. Resenja sa subkverijima koji su kolege ponudili radice u tom slucaju mnogo brze, jer nece raditi sa 100,000 rekorda u tabeli, nego sa mnogo manje, jer ce u glavnom kveriju svuda biti WHERE ArtiklID=xxxxx. Gde ja radim, imamo bazu sa 3-4 miliona rekorda, i radimo slicno, kompleksne upite, sa subkverijima koji nesto sumiraju i broje, ali koji vracaju svega po 500-1000 rekorda, nekoj C# proceduri koja ih ispisuje na web stranici. Imamo po 400-500 korisnika odjednom, koji svi traze nesto od SQL servera i nemamo problema. Napravi stored procedure ili funkciju koja vraca rekorde za karticu za tacno jedan zadati artikl i trebalo bi da radi dovoljno brzo.
[ dekibre @ 27.02.2006. 12:12 ] @
Pozdrav svima,

imao sam sličan problem kada sam radio izveštaj analitičku karticu.
Rešenje je da se slogovi sortiraju po određenom kriterijumu tako da dobijamo neki sled transakcija (promena ulaza / izlaza)
Zatim se svi slogovi stave u privremenu tabelu sa identity kolonom i na kraju se stanje dobija sumiranjem svih ulaza i izlaza * (-1) za identity <= u odnosu na tekuću transakciju referenciranjem privremene tabele samu na sebe.

Upit bi izgledao ovako:

Code:
IF (SELECT OBJECT_ID('tempdb..#PRIVREMENA)) > 0 
    BEGIN
        DROP TABLE  #PRIVREMENA
    END

SELECT 
IDENTITY(INT, 1, 1) AS RBR
, DATUM 
, PROMENA
, KOLICINA
INTO #PRIVREMENA
FROM UIMAGACIN
ORDER BY DATUM

SELECT DATUM, PROMENA, KOLICINA, 
(
SELECT SUM( CASE WHEN PROMENA = 'U' THEN COALESCE(P.KOLICINA, 0)
    ELSE COALESCE(P.KOLICINA, 0)*(-1) END ) 
FROM #PRIVREMENA P
WHERE P.RBR <= #PRIVREMENA.RBR
) AS STANJE
 FROM #PRIVREMENA


Na ovaj način se izbegava i upotreba kursora i UDF.
U konkretnim slučajevima potrebno je promeniti order by i where uslov u self join-u.
[ gdjuric @ 02.03.2006. 17:17 ] @
Bravo Dejane !

to je to !

Odlicno resenje, dakle ideja je dvostruka referenca na privremenu tabelu, jedna za select obicnih kolona, a druga za sumiranje do tekuceg reda.

Kljuc je dakle u mogucnosti da se kaze:

... from #privremena p ...

sto omogucava razlikovanje jedne i druge reference (#privremena i p).

I ovo "self-join" resenje, kao i resenje sa UDF-om je svakako elegantnije od mog pocetnog sa cursor-om, evo dokaza da se cursor moze skoro uvek izbeci ...

pozdrav