[ Zidar @ 31.08.2009. 14:42 ] @
U temi http://www.elitesecurity.org/t374236-Dva-poslednja-datuma potavljeno je zanimljivo pitanje:
Citat:
Imam pacijenta i za njega vezane posete (veza između tabela je jedan prema više- jedan pacijent ima više poseta). U izveštaju bih želeo da izađe datum poslednje posete i prve prethodne. Uspevam da nađem poslednju max([DatumPosete]), znači iz niza izvlačim "najveći datum", ali ne mogu da izdvojim i prvi pre njega.


Ponudjen je ovakav odgovor:
Citat:
SELECT TOP 2 DatumPosete AS ZadnjePosete
FROM tblPosete
ORDER BY [DatumPosete] DESC;


Odgovor nije potpuno tacan, ali usmerava u dobrom pravcu, sto je psotavljac pitaja lepo iskoristio i elegantno resio problem.

Zasto odgovor nije potpuno tacan? Zato sto daje poslednja dva datuma u tabeli tblPosete, a ne dva poslednja datuma za svakog pacijenta. Ponudjeni odgovor uvek vraca tacno dva rekorda, koji mogu da pripadaju razlicitim pacijentima. Pitanje je bilo kako dobiti poslednje dve posete za konkretnog pacijenta. Postavlajc pitanja je lepo zakljucio da PRVO treba da izfiltrira ulaznu tabelu po pacijentu i dbobice ono sto treba:

[code]
SELECT TOP 2 DatumPosete AS ZadnjePosete
FROM tblPosete
WHERE Pacijent = 'Marko Markovic'
ORDER BY [DatumPosete] DESC
[\code]

Ako uvedemo WHERE da nam isfiltrira tabelu tblPosete i prikaze tacno ejdnog pacijenta, onda uradimo TOP 2 za ORDER BY DESC i dobijemo ono sto nam treba - poslednej dve posete za Pacijent = 'Marko MArkovic'

Ova mozgalica trazi generalni odgovor, ovako:

Napisati kveri koji za sve pacijente u tabeli tblPregledi vraca dve poslednje posete. Rezultat treba da izgleda ovako:

Pacijent Poseta
---------------
'Marko', 12 Aug 2009
'Marko', 15 Jul 2009
'Laza', 10 Aug 2009
'Laza', 6 Jan 2009
'Ana' , 15 Mar 2008
'Ana', 6 Sep 2006


Uz poruku sam zakacio MDB sa tabelom tblPosete. Treba napisati kveri ili kod koji ce na izlazu dati trazeni skup podataka. Finalni kveri treba da se zove qryRezultat. Sve je dozvoljeno. Kad dobijete resenja, zakacite ga uz odgovor da vidimo kako radi. Ako piste kod koji ce ovo da resi, naznacite u odgovoru, na primer "Startovati modul basPoslednjaDvaDatuma i zatim otvorite qryRezultat". Fajl koji zakacite nazovite svojim imenom i dajte mu neki broj. Na primer, ja bih poslao prvo resenje pod imanom Zidar_01.mdb Ako ne valja, pa popravljam nesto, poslao bih Zidar_02.mdb. Naravno da cete fajlove smanjiti kroz ZIP ili RAR.

Cak i ako ne umete da resite problem do kraja, a mislite da imate ideju kako bi to trebalo, posaljite sta imate, dokle ste stigli, pa mozda neko pomogne oko sastavljanja komplikovanog kverija, zasnovanog na vasoj ideji.

Resenje se u potpunosti moze naci sistemom kverija, ili cak jednim jedinim kverijem, programski kod nije neophodan, ali ostavljamo i tu mogucnost. Bilo koje resenje je bolje nego nikakvo resenje.


Napomena: tabela koju sam dao ima i autonumber kolonu. Ne gubite vreme pokusavajuci da to iskoristite, rekordi nisu uneseni u redosledu datuma ili bilo cega. Podaci su preuzeti iz Exscel fajla i redosled nema veze sa autonumber redosledom.

Na posao.

:-)

[ Getsbi @ 31.08.2009. 15:06 ] @
Samo da se ogradim. Kolega sabacc je lepo rekao: "Imam pacijenta i za njega vezane posete (veza između tabela je jedan prema više- jedan pacijent ima više poseta)." http://www.elitesecurity.org/t374236-Dva-poslednja-datuma
Predpostavljam da kad je rekao "Uspevam da nađem poslednju max([DatumPosete])", da je našao za traženog pacijenta. Ja odavde ne vidim njegov izvor podataka dok ga ne zakači. Predloženi SQL iskaz, koji sam mu dao, treba da primeni nad izfiltriranim podacima za traženog pacijenta.
[ Zidar @ 31.08.2009. 15:59 ] @
@Getsbi: nista lose nema u iskazu koji si dao, nisam mislio da kritikujem, izvinjavam se ako je tako izgledalo. A iskaz je odradio posao - poslao ga je u pravom smeru. stavise, za praksu, ideja sa pre-filtrovanjem pa koriscenje jednostavnijeg iskaza je mnogo bolja nego generalno resenje, iz prostog razloga sto je generalno resenje prilicno komplikovano i sporo na duzi rok.

Kad zavrsimo mozgalicu, voleo bih da se vratimo resenju kojeje pristeklo iz tvog kverija, jer je to u stvari prava stvar. Mozgalica je vise da pobamo da pisemo komplikovane kverije . Resenje koje je proizislo iz vase razmene poruka jeste ono sto ja zovem 'inzenjersko resenje za praksu'.

Mozgalica ce nam dati teorijsko resenje, na nivou gimnazijske fizike. Fizika nas uci da telo koje slobodno pada ubrzava sve dok ne udari u zemlju. U praksi, telo koje bacimo sa velike visine ubrzava dok ne dostigne ok 20 m/s i onda pada konstantnom brzinom, zbog uticaja trenaj i otpora vazduha, koje fizika zanemaruje, ali inzenjerska praksa uzima u obzir.


[ Getsbi @ 31.08.2009. 17:26 ] @
@ Zidar
Ma sve je Ok. Ja sam više za brzo i efikasno. "Prženje" mozga mi slabo ide.
[ captPicard @ 31.08.2009. 20:51 ] @
Ziodar, zan8imljiva mozgalica, moram priznati.

Sa programskim kodom je to jednostavno uraditi, i mislim da to svi znamo, ali sa samo jednim upitom još nisam uspio, ali pokušati ću jer me baš živo zanima :-)

By the way, kada ovo riješimo, imam ja jednu mozgalicu (doduše, lakšu) ali mislim da će biti zanimljiva...
[ Zidar @ 31.08.2009. 22:07 ] @
@ captPicard : samo napred, i resenje sa kodom se broji, nije bas da 'svi znamo'. Nekolicina pokusava i resava mozgalice, ali mnogo vise ljudi posmatra i uci. Znaci, sva resenja su dobrodosla. Resenje s jednim kverijem je verovatno neprirodno, ne uzbudjuj se oko toga. Daj programski kod, i/ili resenje sa nekoliko kverija, sve je to dobro.

Sto se tice mozgalice, slobodno je postavi. Nema pisanih pravila koje zabranjuje postavljanje mozgalica. Nepisana pravila o mozaglicama su 1. svako moze da postavi mozgalicu, ako su drzi pravila koja slede
2. postavlajc mozgalice mora da zna resenje
3. ako dva dana po postavjanju mozgalice nema resenja, posatvljac ce postaviti svoje
4. postavljac treba da obezbedi ulazne objekte i podatke (tabele popunjene podacima)

Oni koji odgovaraju treba da se drze ovih pravila:
1. svi imaju pravo da ogovaraju na mozgalice i komentarisu rezultate
2. ko postavi odgovor, mora da ga proveri pre toga
3. mogu se dati i delimicna resenja i ideje, na primer 'zamislio sam ovako i stigao dovde, a dalje ne znam'

:-)
[ izonic @ 31.08.2009. 23:33 ] @
Query:Prezadnji
SELECT Tbl_alias.Pacijent, Tbl_alias.DatumPregleda
FROM tblPregledi AS Tbl_alias
GROUP BY Tbl_alias.Pacijent, Tbl_alias.DatumPregleda
HAVING (((Tbl_alias.DatumPregleda) Not In (SELECT Last (DatumPregleda) as D From tblPregledi GROUP BY tblPregledi.Pacijent)));


Query:Zadnji
SELECT tblPregledi.Pacijent, Last(Prezadni.DatumPregleda) AS PrezadnjI, Last(tblPregledi.DatumPregleda) AS Zadnji
FROM tblPregledi INNER JOIN Prezadni ON tblPregledi.Pacijent = Prezadni.Pacijent
GROUP BY tblPregledi.Pacijent;
[ captPicard @ 01.09.2009. 11:01 ] @
Citat:
Zidar: @ captPicard : samo napred, i resenje sa kodom se broji, nije bas da 'svi znamo'. Nekolicina pokusava i resava mozgalice, ali mnogo vise ljudi posmatra i uci. Znaci, sva resenja su dobrodosla. Resenje s jednim kverijem je verovatno neprirodno, ne uzbudjuj se oko toga. Daj programski kod, i/ili resenje sa nekoliko kverija, sve je to dobro.

:-)


Ne stignem sada pisati kod, ali ovako:

q1. select distinct pacijent from tblPregled

i onda u petlji

while not q1.eof do

select top 2 datumpregleda from tblpregled where pacijent = :pacijent

q1.next

Nadam se da kužite šta želim reći :-)
[ captPicard @ 01.09.2009. 11:08 ] @
Citat:
izonic: Query:Prezadnji
SELECT Tbl_alias.Pacijent, Tbl_alias.DatumPregleda
FROM tblPregledi AS Tbl_alias
GROUP BY Tbl_alias.Pacijent, Tbl_alias.DatumPregleda
HAVING (((Tbl_alias.DatumPregleda) Not In (SELECT Last (DatumPregleda) as D From tblPregledi GROUP BY tblPregledi.Pacijent)));


Query:Zadnji
SELECT tblPregledi.Pacijent, Last(Prezadni.DatumPregleda) AS PrezadnjI, Last(tblPregledi.DatumPregleda) AS Zadnji
FROM tblPregledi INNER JOIN Prezadni ON tblPregledi.Pacijent = Prezadni.Pacijent
GROUP BY tblPregledi.Pacijent;


Ovo radi. Svaka ti čast na ideji, nisam se toga sjetio!!!!
[ izonic @ 01.09.2009. 11:27 ] @
E sad ovo je u 2 Query-a a moze se napraviti i u jedan.
Sacekat cu malo mozda ko odgovori ako ne postavit cu.
[ Zidar @ 01.09.2009. 20:22 ] @
@Zonic: od majstora majstorsko resenje. Svaka cast.

Mozda se moze malo pojednostaviti - qry predzadnji - probao sam bez GROUP BY i radi OK.

U qryZadnji, ipak bih umesto LAST stavio MAX. LAST je specificno Accesova funkcija, drugi SQL jezici to nemaju. I u Accesu, nije sigurno sta ce LAST da vrati u svim slucajevima. U ovom slucaju LAST izgleda da razume LAST DAtum, sto je isto sto i MAX datum, ali moglo je biti i LAST record umesto LAST datum.

U svakom slucaju, dobar posao

Stavi sve u jedan query, da imamo i to.

[ izonic @ 01.09.2009. 20:48 ] @
Posto niko nije htio, evo i drugo rjesenje.
SELECT tbl_alias.Pacijent, tbl_alias.DatumPregleda
FROM tblPregledi AS tbl_alias
WHERE ((((select count( DatumPregleda) from tblpregledi
Where Tbl_alias.pacijent=tblPregledi.pacijent and Tbl_alias.DatumPregleda<tblpregledi.DatumPregleda))<2))
ORDER BY tbl_alias.Pacijent, tbl_alias.DatumPregleda;
[ Zidar @ 03.09.2009. 13:59 ] @
Bravo za majstora!


Primetite da je ovaj kveri sustinski razlicit od prvog resenja. Prvo resenje daje tacno dva poslednja datuma, kao sto je zadatak i trazio. I ovo resenje daje dva poldednja datuma. Medjutim, moze i vise od dva.

Evo formatirana verzija, sa jednom izmenom - sada vraca 3 poslednja rekorda.

Code:

SELECT   tbl_alias.pacijent,
         tbl_alias.datumpregleda
FROM     tblpregledi AS tbl_alias
WHERE    ((((SELECT Count(datumpregleda)
             FROM   tblpregledi
             WHERE  tbl_alias.pacijent = tblpregledi.pacijent
                    AND tbl_alias.datumpregleda < tblpregledi.datumpregleda)) < 3))
ORDER BY tbl_alias.pacijent,
         tbl_alias.datumpregleda;



Jos jednom, bravo.

[ Zidar @ 03.09.2009. 14:27 ] @
Kao sto pravila nalazu, postavljac pitanaj mora da prilozi i svoje resenje. Evo. Moje resenje se zasniva na numerisanju postojecih redova i zatim izabiranjem onih redova koje zelimo da pokazemo.

Prvo s enapravi ovakav kveri:

qryRedosledPregleda_BrziNacin
Code:

SELECT a.pacijent,
       a.datumpregleda,
       (SELECT 1 + Count(* ) AS cnt
        FROM   tblpregledi AS b
        WHERE  a.pacijent = b.pacijent
               AND a.datumpregleda < b.datumpregleda) AS redosled
FROM   tblpregledi AS a;


ONda mogu da radim ovo:
Code:
SELECT Pacijent, DatumPregleda, Redosled
FROM qryRedosledPregleda_BrziNacin
WHERE (((Redosled)<=2))
ORDER BY DatumPregleda DESC;


Sad iz toga biram kog hocu pacijenta, a mogu i da promenim broj ako zelim.

Moglo je i u jednom kveriju, ali nije toliko pregledno i jasno sta se to desava:
Code:
SELECT a.pacijent,
       a.datumpregleda
FROM   tblpregledi AS a
WHERE  2 >= (SELECT 1 + Count(* ) AS cnt
             FROM   tblpregledi AS b
             WHERE  a.pacijent = b.pacijent
                    AND a.datumpregleda < b.datumpregleda);


Ako se udubite u ovaj poslednji kveri, videcete da je u sustini slicno onome sto je naopravio Zonic.

Moj kveri se zasniva na numeraciji redova. Sam postupak numeraciej moze biti od koristi i u drugim situacijama. Na priemr, zelite da imate tacno 20 redova po starni reporta. Numerisite redove u kveriju koji je DataSource za report, zatim odredite Starnice = int(Redosled/20) i date za reort da GROUPING bude po polju Stranica....

Posto je numerisanje korisna stvar,e vo jos jedan nacin za numerisanje - qryRedosledPregleda_JosjedanNacin
Code:

SELECT   a.pacijent,
         a.datumpregleda,
         Count(* ) AS redosled
FROM     tblpregledi AS a
INNER JOIN tblpregledi AS b
           ON (a.pacijent = b.pacijent)
              AND (a.datumpregleda <=   b.datumpregleda)
GROUP BY a.pacijent,
         a.datumpregleda;

Ovaj poslednji nacin je obicno sporiji od prvog nacina, ali u nekim situacijama, na SQL serveru moze biti i brzi. Neka ga za svaki slucaj.


Ima li jos resenja, pitanj ili komentara? Mozgalice su u principu uvek otvorene.