Soykan,
Defalarca anlattim aslinda:)
Kisaca gene anlatayim:
Visual Fox Pro
* rastgele sirayla girilmis dataya ornek
SELECT Country as ulke,City as sehir, INT(RAND()*10)*100 as MusteriSayi ;
FROM (_samples+'data\customer') ;
INTO CURSOR crsOrnek ;
NOFILTER
BROWSE
Simdi elimizde ornek olarak kullanilacak data var.
Visual Fox Pro
SET ENGINEBEHAVIOR 70
SELECT COUNT(sehir), sehir, ulke ;
FROM crsOrnek ;
GROUP BY ulke
SET ENGINEBEHAVIOR 90
Calisti ve saydi, ama neyi saydi? SQL'e bakinca Ulke basina sehirleri saymis gibi duruyor. Sonuc listesinde:
London,UK,7 (ben testdata ile arada oynuyorum belki orijinal rakamlarla tutmaz)
var. UK'yi anladik ulke gruplamasindan geldi. London nereden geldi? UK olan baska kaydimiz da yok. UK'da 7 tane London'mi var? 7 tane London ve baska hic bir sehir yok mu orada? Tum ulkeler birer kere geciyor listede, demekki her ulkede ayni zamanda sadece birer sehir mi var? VFP7'de cevabi o rastgele secilmis bir deger o ulke sehirleri icinden (rastgele degil aslinda, fiziksel olarak cursor/tablodaki en son UK olan satirda sehir olarak London var, USA icin Seattle var vs). Bu da bir anlamda rastgele demek, cunku gruplamanin yapildigi tabloya birisi "UK, Birmingham" girerse ve biz bunu yeniden calistirirsak:
Birmingham,UK,8
ya da kimse birsey girmedi ama biz icinde order by olan bir SQL sonucu cursorden filan aliyoruz. Ya da isin icinde joinle baska tablolar var, optimizasyon nedeniyle kullanilabilecek gecici tablolarin nasil olacagini bile kestiremiyoruz. Yani sonucta fiziksel sira o degeri beliriyor. Kabaca attim tuttu gibi bir deger:)
Visual Fox Pro
SET ENGINEBEHAVIOR 70
SELECT COUNT(*), sehir, ulke ;
FROM crsOrnek ;
GROUP BY ulke
SET ENGINEBEHAVIOR 90
Sonuc ayni. Yani aslinda oraya sehir yazmakla sehirleri saymiyor. Group basina ulkenin gectigi satir sayiliyor.
Burada gercekten emin oldugumuz tek sonuc, her ulkenin kac kere gectigi.
Visual Fox Pro
SELECT COUNT(*), ulke ;
FROM crsOrnek ;
GROUP BY ulke
sehir atilinca VFP9 icin de gecerli bir SQL.
count,max,min,avg,sum,std... bunlar aggregate fonksiyonlar. Yani bir set uzerinde yigin islemleri yapan fonksiyonlar. Group By sql'lerde bunlar serbest. Onun disinda kullanilan her alan ayni zamanda Group By icinde gecmeli.
Sehir nasil olsa atmasyon bir deger olarak geliyor VFP7'de, alfabetik olarak ilk geleni ya da son geleni secsek de olurdu.
Visual Fox Pro
SELECT COUNT(*), MAX(sehir), ulke ;
FROM crsOrnek ;
GROUP BY ulke
Max ile gercekte isimiz yok ama illaki orada birsey istiyorsam isimi goruyor.
VFP7 ile farki anadiktan sonra baska bir group:
Visual Fox Pro
Select Count(Distinct sehir), ulke ;
FROM crsOrnek ;
GROUP By ulke
Bunda sehir Count() ile ise yariyor. UK'da 2 sehirde musteri varmis. Veya:
Visual Fox Pro
Select Count(Distinct sehir), COUNT(*), ulke ;
FROM crsOrnek ;
GROUP By ulke
UK'da 2 sehirde toplam 7 musteri varmis:)
TestData.dbc, OrdItems'da Quantity*Unit_price = net satis olsun. Musteri basina toplam almak istedigimizde VFP7'de bunu yapabiliyoruz (9da enginebehavior ile):
Visual Fox Pro
SET ENGINEBEHAVIOR 70
Select Cus.*, Sum(oi.Quantity * oi.Unit_price) as NetSatis ;
FROM (_samples+'data\customer') cus ;
left JOIN (_samples+'data\orders') ord ON cus.cust_id == ord.cust_id ;
left JOIN (_samples+'data\orditems') oi ON ord.order_id == oi.order_id ;
GROUP By cus.Cust_id
SET ENGINEBEHAVIOR 90
Fistik gibi, bir raporda musterilerin istedigin fieldini + netsatisi gosterecek basit bir sonuc. Burada VFP7'nin yarattigi sonuc da dogru. Rastgele hicbir deger yok. Nasil olsa Customer tablosunda belli bir cust_id'nin Company,Contact ... alanlarinda sadece bir kez geciyor (yani ALFKI ise o Alfreds Futter.. baska Alfread Futterskie... yok).
VFP9'da ise hata veriyor (sadece VFP'de degil tum ANSI SQL kullanan backendlerde).
Hatanin nedeni Cus.* dedigimize gore sonucta tum alanlari istedik. O zaman tum alanlar "Group by" da gecmeli. Ya da onceki hile gibi Cust_id disindaki alanlarda max(), min() hilesini kullanmaliyiz. Group By icinde * kullanamayiz, N tane alan, ya da select bolumnune de N tane Min(),Max() yazilmaz ki:(
Cuneyt Arkin atiliyor,
-buldum! Modify query yapariz, customer tablosunu ve tum alanlarini seceriz, SQL koduna bakip copy&paste yapariz.
-Parlak fikir... hmmm... git isine ya kim ugrasir.
-Buldum. afields() textmerge ile alanlari alip yazacak kod yapalim. Gerisi copy&paste;)
-Harika benim hazirda onu yapan kodum var... Nerde, of... ufff ... baska fikir?
-...
-Buldum... Bir SQL yapip sadece Cust_id ve Sum() alalim. Ikinci bir SQL ile sonuclari birlestirelim.
-Guzel. Aferin be calisiyor da. Cok da guzel oldu.
Da da dan... Esas olan VFP9 giriyor kapidan (bayildim yazmaktan da ondan, kafayi yemedim henuz:)
-Group by'da sizi kisitliyorum ama artik akillara ziyan SubQuery'lere izin veriyorum. Secin, ya o subquery destegi ya eski group by:)
Visual Fox Pro
Select Customer.*, tmp.NetSatis ;
FROM (_samples+'data\customer') ;
INNER Join ;
(Select Cus.cust_id, Sum(oi.Quantity * oi.Unit_price) As NetSatis ;
FROM (_samples+'data\customer') Cus ;
left Join (_samples+'data\orders') ord On Cus.cust_id == ord.cust_id ;
left Join (_samples+'data\orditems') oi On ord.order_id == oi.order_id ;
GROUP By Cus.cust_id) tmp ;
ON Customer.cust_id == tmp.cust_id
Son fikrin, tek SQL versiyonu gibi. Isin ilginci baska yollari'da var artik:)
The End