Készítek egy kis programot, amiben a következő feladat van:
Van egy folyószámla, amihez tartoznak tételek.
Azt szeretném, ha a folyószámla tételeinek listázásakor látszana, hogy az adott tétel a számla egyenlegét hogy módosította.
Példa:
kezdő egyenleg 0
1. tétel +500 - egyenleg 500
2. tétel -200 - egyenleg 300
3. tétel +200 - egyenleg 500
4. tétel +200 - egyenleg 700
A kérdés az, hogy hogyan lenne jó ezt kialakítani.Jelenleg egyenleget nem tartok nyilván, és nem is számolok.
A tételeknek van mennyisége és van dátuma (meg leírás), és kész.
A mostani lekérdezésben van egy sum(mennyiseg) a végén, ami a számla jelenlegi egyenlegét megmutatja, de az nem látszik, hogy mondjuk 1 hete mennyi volt az egyenleg.
Nincs nagyon sok tétel, mondjuk napi 10 a nagyságrend. Előfordul időnként, hogy régi tételek kerülnek be a rendszerbe. Viszonylag újak (pár hét) elég sűrűn, és nem is kevés. Régebbiek ritkán: néha soká (hónapokig) semmi, néha meg egyszercsak sok.
Több ötletem is van, de egyikkel sem vagyok teljesen elégedett.
1:
minden számlatétel mellett eltárolom, hogy éppen mennyi az egyenleg, és ha régi tételt rögzítek, akkor az összes későbbi tételnél ezt módosítom. - Kicsit félek a régi tétel beszúrásától - sok módosítás, illetve úgy érzem, hogy az egyenlegnek nem a számlatételnél van a helye logikailag. Viszont könnyű lekérdezésbe tenni, és megjeleníteni.
2:
készítek egy egyenlegek táblát, ahová minden folyószámlához és minden naphoz eltárolom, hogy mennyi volt a napi egyenleg. - Ez logikailag jobban tetszik, persze régi tétel beszúrásakor ugyanúgy át kell számolni és módosítani az egész táblát. Emellett a lekérdezés mem könnyű, tehát ennek inkább csak hátrányai vannak, mint előnye. :-)
2bis: tételenként az egyenleg külön táblában. Ez se tetszik jobban.
3:
valami ügyes lekérdezést kellene készíteni, ami az adott tételben, és az őt megelőző tételekben szereplő mennyiségeket összegzi. - Ez tetszik, mert nem kell beszúráskor, vagy ha pl. egy tétel egyik folyószámláról másikra kerül, végigmódosítani mindent, nincs egyenleg információ eltárolva itt-ott (ami kvázi felesleges, hiszen számolható mennyiség). És Viszont egyfelől még nem izzadtam ki a szükséges lekérdezést, másfelől félek, hogy bonyolult és lassú lesz.
Szóval a kérdések: valaki csinált már hasonló projektet? Mit használt, miért, és hogyan vált be?
A fenti hármon kívül van még ötlet?
Vagy bármi komment?
Ja, mindezt adatbázisban kellene, tehát az nem megy, hogy lekérdezek egy adathalmazt, és majd valami programban kiszámolom. adatmodell, SQL, esetleg tárolt eljárás
- 1318 megtekintés
Hozzászólások
Ha ez a konyhapénz számító algoritmus, akkor én úgy csinálnám, hogy maga a tábla 4 mezőből állna:
timestamp, betét, kivét, egyenleg. A táblához adnék egy triggert, ami INSERT/UPDATE/DELETE-re lefuttat egy DB tárolt eljárást, ami átmazsolázza az összes rekordot és frissíti az egyenleg értékét.
Így a számítást az adatbázis végzi, nem kell a külső alkalmazásból molyolnod. Mellesleg transzparens lesz a megoldás: egy beszúrásnál csak egy SQL parancsot kell kiadni, nem kell foglalkoznod a többivel.
- A hozzászóláshoz be kell jelentkezni
Ja, mondhatjuk, hogy konyhapénz.
Szóval egy szavazat az 1-es ötletre.
Egyébként ha nem konyhapénz lenne, akkor máshogy csinálnád?
- A hozzászóláshoz be kell jelentkezni
Igen, ez kb. az 1-es pont, de a lényeg, hogy ne a külső alkalmazás piszkálgassa az egyenleg számolást, hanem az a db feladata legyen.
Ha nem konyhapénz lenne, akkor nagyon sok változó lenne, ami alapján dönteni kellene. Bejöhetne a VIEW, MATERIALIZED VIEW (Oracle) függve attól, hogy inkább írjuk vagy olvassuk az adatbázis. Lehetne játszani azzal, hogy az INSERT-nél csak akkor szüttyögünk az egyenleg számítással, ha nem a legutolsó tételt írjuk be (azaz csak azon a részhalmazon számítjuk újra az egyenlegeket, amelyek garantáltan megváltoztak) stb stb.
- A hozzászóláshoz be kell jelentkezni
Tkp. semmi sem akadályoz meg abban - legalábbis a licensz nem - hogy DB2 Express-C-t tegyél fel, amely tud rollupot:
http://it.toolbox.com/blogs/db2luw/olap-sql-part-1-rollup-7985
Más kérdés, hogy kosztpénzhez még ez is verébre szegezett ágyú, de ha eccer ingyen van. :)
- A hozzászóláshoz be kell jelentkezni
No, kicsit nagy a konyha?:)
esetleg ki kellene próbálni, hogy egy summázó subselect nem felel-e meg... a triggeres módosítgatós cuccal nekem az a gondom, hogy redundanciát visz az adatbázisba és ha egyszeris valaki belenyúl kézzel egy tételbe, felborul az egész.
szerk: 1 szavazat a 3-ra.
- A hozzászóláshoz be kell jelentkezni
mondjuk a trigger az ellen véd, hogy boruljon az egész.
Ha kézzel nyúl bele, a trigger ugyanúgy elsül, és az üzleti logika nem sérül.
Engem is csak a redundancia része zavar ezzel.
- A hozzászóláshoz be kell jelentkezni
A redundancia része alatt pontosabban mit értesz?
- A hozzászóláshoz be kell jelentkezni
tárolni olyan adatot, ami más, az adatbázisban már tárolt adatokból előállítható
- A hozzászóláshoz be kell jelentkezni
Nincs szukseg triggerre, SQL gond nelkul megoldja a problemat, csak egy ugyes join kell neked (lasd lentebb).
- A hozzászóláshoz be kell jelentkezni
Viszont minden esetben bele kell biggyeszteni a joint a lekérdezésbe. Míg triggeres esetnél tetszőleges rekordot lekérdezhetek: minden kedd, hétvégenkénti bontás, stb. Joinolásnál minden egyes ilyen típusú lekérdezéshez külön passzítani kell a joinos részt. Ettől akarnám a posztolót megkímélni
- A hozzászóláshoz be kell jelentkezni
CREATE VIEW blablabla.
- A hozzászóláshoz be kell jelentkezni
Ez meg attól függ. Ha kevés az írás és sok az olvasás, akkor minden olvasáshoz legeneráltatod az egyenlegeket, ami nem mindig jó ötlet. Én inkább úgy vagyok vele, hogy egy adatot egyszer képezzünk le.
Ha sok az írás és kevés az olvasás, akkor már jobb lehet a VIEW.
- A hozzászóláshoz be kell jelentkezni
Jobb helyeken a DB cachel, foleg a view-kat.
Masreszt, optiomalizalni akkor erdemes, hamar van mit, es amikor szukseg van ra.
- A hozzászóláshoz be kell jelentkezni
Szerintem nem egyről beszélünk már ...
- A hozzászóláshoz be kell jelentkezni
ezek különböző megközelítések. A trigger az első, a te ügyes join-od a harmadik.
- A hozzászóláshoz be kell jelentkezni
Harmadik megoldas (postgres, de mukodhet hasonlo mysql-el is kis modositassal; sqlite ha jol neztem nem tud ilyet):
CREATE TABLE tetelek (id SERIAL, tetel INT);
feltoltod adatokkal, majd:
SELECT t1.id, t1.tetel, SUM(t2.tetel) FROM tetelek t1 JOIN tetelek t2 ON t1.id >= t2.id GROUP BY t1.id, t1.tetel ORDER BY t1.id;
Nalam ez igy nez ki:
algernon=# select * from tetelek;
id | tetel
----+-------
1 | 200
2 | 100
3 | 150
4 | -50
5 | -25
6 | 40
(6 rows)
algernon=# select t1.id, t1.tetel, sum(t2.tetel) from tetelek t1 join tetelek t2 on t1.id >= t2.id group by t1.id, t1.tetel order by id;
id | tetel | sum
----+-------+-----
1 | 200 | 200
2 | 100 | 300
3 | 150 | 450
4 | -50 | 400
5 | -25 | 375
6 | 40 | 415
(6 rows)
- A hozzászóláshoz be kell jelentkezni
+1
- A hozzászóláshoz be kell jelentkezni
Szóval 3-as megoldás.
Működik a lekérdezés, csak a join feltételén kellene valamit agyalni.
Ugye id nem használható, mert nem a rögzítés sorrendje, hanem a dátum számít.
A sima t1.datum >= t2.datum meg azért nem jó, mert az egy napra rögzített több tételt összemossa.
Szóval valami ebben az irányban elindulva jó lehet...
select * from tetelek2 order by datum
"ID","DATUM","TETEL"
"7","30-OCT-10","40"
"2","01-NOV-10","200"
"3","02-NOV-10","100"
"4","02-NOV-10","150"
"5","03-NOV-10","-20"
"6","03-NOV-10","-25"
"1","10-NOV-10","200"
select
t1.id, t1.datum, t1.tetel, sum(t2.tetel)
from tetelek2 t1 join tetelek2 t2 on t1.datum >= t2.datum
group by t1.id, t1.tetel, t1.datum order by datum;
"ID","DATUM","TETEL","SUM(T2.TETEL)"
"7","30-OCT-10","40","40"
"2","01-NOV-10","200","240"
"3","02-NOV-10","100","490"
"4","02-NOV-10","150","490"
"6","03-NOV-10","-25","445"
"5","03-NOV-10","-20","445"
"1","10-NOV-10","200","645"
...
- A hozzászóláshoz be kell jelentkezni
Most eddig jutottam:
select t1.n, t1.id, t1.datum, t1.tetel, sum(t2.tetel)
from
(select id, datum, tetel, rownum n from (select id, datum, tetel from tetelek2 order by datum, id)) t1,
(select id, datum, tetel, rownum n from (select id, datum, tetel from tetelek2 order by datum, id)) t2
where t1.n >= t2.n
group by t1.n, t1.id, t1.tetel, t1.datum
order by 1
"N","ID","DATUM","TETEL","SUM(T2.TETEL)"
"1","7","30-OCT-10","40","40"
"2","2","01-NOV-10","200","240"
"3","3","02-NOV-10","100","340"
"4","4","02-NOV-10","150","490"
"5","5","03-NOV-10","-20","470"
"6","6","03-NOV-10","-25","445"
"7","1","10-NOV-10","200","645"
Működik, bele is lehet tolni egy view-ba, ha csak adott tételeket akarok nézni, mondjuk.
De azért szépnek nem mondanám :-)
- A hozzászóláshoz be kell jelentkezni
Hasznalj timestampet, akkor nem mossa ossze ;)
De van egyeb megoldas is, ami segitsegedre lehet. Mind MySQL, mint Postgres doksit erdemes atnezni, sok tippet tudnak adni.
Leven a modellt is te allitod ossze, nagyjabol akarmit meg lehet csinalni.
- A hozzászóláshoz be kell jelentkezni
timestamp nem jó, mert csak dátum a bontás.
Most készítettem egy view-t, id, egyenleg mezőkkel, aztán a rendes listákhoz ezt hozzá lehet kötni.
Csak éppen a view szerintem ocsmány belül, de működik rendesen.
- A hozzászóláshoz be kell jelentkezni