10 Şubat 2010 Çarşamba

SQL Server 2008 R2 Üzerinde Report Builder 3.0 ve ReportViewer Kullanımı

SQL Server 2008 R2 sayesinde Report Builder 3.0 ile tanışmış olduk.
SQL Server 2008 R2 (Server 2008 R2 November CTP) kurulumunu bu adresten yapabilirsiniz. Önceden kurulu olan bir SQL Server 2008 kurulumunuz varsa, bu konuda bahsedeceğim yeni özelliklerden faydalanamama ihtimaliniz çok yüksek. Bu sebeple eski 2008 versiyonlarını kaldırarak R2 versiyonuna geçmenizde fayda var.
Burada yanlış anlaşılmaması gereken önemli bir noktayı belirtmek isterim; verileri alacağınız sunucunuzun versiyonu hiç önemli değil, SQL 2000 veya 2005 olabilir. Datasource olarak ne kullanmak isterseniz kullanabilirsiniz. Kritik olan konu şu; Report Builder 3.0 ile oluşturulan .rdl dosyaları sadece SQL Server 2008 R2 ile gelen Reporting Service üzerinde host edilebiliyor.
Sizde kurulu versiyonu öğrenmek isterseniz; "SELECT @@VERSION" sorgusunda alacağınız bilgilere göre bir kıyas yapabilirsiniz. Örneğin, ben çalıştırdığımda şu bilgiyi alıyorum: "Microsoft SQL Server 2008 R2 (CTP) - 10.50.1352.12"

Bunun yanında SQL Server Management Studio'da açılırken aşağıdaki şekilde bir imaj ile açılmalı.

Sadece Report Builder 3.0 kurulumu yapmak isterseniz, Microsoft değiştirmediyse buradan bu işlemi yapabilirsiniz.

SQL Server 2008 R2 artık kurulu ise konumuza başlayabiliriz.

Report Builder 3.0 ile nasıl rapor oluşturulacağı kısmına burada hiç girmeyeceğim. Benim örneklerimde kullandığım sürüm gene November CTP sürümü.


Raporumuz oluştuktan sonra elimizde bir .rdl dosyamız olacak. Bu dosyayı Reporting Service'e publish etmemiz gerekecektir. Bu işlemi iki şekilde yapabiliriz;
  • Report Builder üzerinden
  • Reporting Services Web Yönetim ekranı üzerinden
Web yönetim ekranı ile yapmak isterseniz, öncelikle uygun adresi bulmanız gerekli. Bunun için Reporting Services'ın yüklü olduğu bilgisayarda;
Başlat > Microsoft SQL Server 2008 R2 November CTP > Configuration Tools > Reporting Services Configuration Manager kısa yolunu açmamız gerekiyor.
Burada karşımıza Reporting Services için kullanacağımız yönetim aracına ulaşıyoruz.
Server ve Instance seçimi ile istediğimi Reporting Service'a ulaşıyoruz. Bu aracın sağ tarafında iki adet URL var. Bunlardan birisi Reporting Services hizmeti veren servisin adresi, diğeri ise raporları deploy etmemize yarayan web yönetim arayüzünün adresi. Biz Report Manager URL üzerinden gideceğiz.
Sunucumuzun adı SQL2008R2 ise, muhtemelen adres "http://localhost:8080/Reports_SQL2008R2" şekilde olacaktır. Buradan "Upload File" diyerek .rdl dosyamızı deploy edebiliriz. İstersek klasörler kullanarak, ileride raporlarımızın artması durumunda daha derli toplu bir görünüm elde edebiliriz.

Web arayüzünden önce Report Builder ile deploy işlemini denemenizde fayda var, çünkü eğer Reporting Services versiyonu uyumsuz ise (R2 değilse) raporları deploy edemeyeceğimizi hiç uğraşmadan anlamış oluruz.

Report Builder üzerinde, Publish Report Parts veya direk Connect to a report server dediğimizde bizden servis adresini girmemizi isteyecektir. Bu adres "http://localhost:8080/ReportServer_SQL2008R2" gibi bir adres olacaktır. Buraya web yönetim arayüzünün adresinin girilmesi sık yapılan bir hatadır, dikkatli olmak gerekli.

Artık raporumuz deploy edilmiş demektir. Bundan sonra geriye bu raporu bir web uygulamasına eklemek kalıyor. Bu kısım oldukça kolay. Visual Studio 2008 üzerinde bir web uygulaması veya web sitesi projesi yaratıyoruz. Design modunda sayfamıza MictosoftReportViewer ekliyoruz (Toolbox üzerinde Reporting sekmesinde bulabilirsiniz). ServerPath kısmına "/RaporAdı" giriyoruz, ReportServerUrl kısmına yukarıdaki servis adresini giriyoruz. Eğer makinaların birbirlerine erişiminde bir problem yoksa raporumuzu görebiliyor olmamız gerekli.

Bu şekilde Report Builder 3.0 ile hazırladığımız, grafiksel olarak zenginleştirilmiş raporlarımızı web uygulamalarında da kullanmış oluyoruz.

9 Şubat 2010 Salı

SQL Sorgularında "IN" - "NOT IN" Kullanımı

sqlservercentral.com'da okuduğum bir yazıyı burada paylaşmak istedim.

Konu sorgularımızda IN ve NOT IN kıyaslamalarını kullanmamız.
Aslında konuyu ikiye ayırmakta fayda var, ilk olarak performans konusunu ele almamız uygun olacaktır. Hemen en önemli kısım ile başlayalım; NOT IN kullanılan sorgularda INDEX kullanılmaz :)

Index'in mantığı gereği, bu indexte olmayanları bul dediğimizde, kayıtların sıralı olmasının bize bir faydası olmayacaktır. Tüm tablonun taranması gerekecektir. Konu ile çok ilgisi olmasada benzer bir durumu daha söylemekte fayda var. LIKE '%KRITER' şeklinde bir arama yaptığımızda Index'imizin bize faydası olmayacaktır. Bunun sebebi Index'lerin sıralı bir şekilde tablomuzda barınıyor olması, biz ilk karakteri bilemezsek bu sıranın bize faydası olmayacaktır. Bunu baş harfini bilmediğimiz bir kelimeyi sözlükte aramak olarak düşünebilirsiniz, fihristi kullanma imkanımız olmayacak, tüm kelimelere teker teker bakmamız gerekecektir.
NOT LIKE, <> gibi kriterlerde de Index kullanımı aynı sebepler yüzünden olmayacaktır. 

Hem NOT LIKE hemde '%KRITER' şeklindeki bir sorguda, SQL motoru tarafından kafamıza şişe fırlatılması ihtimali yüksektir :)

Bu sebeplerden olumsuz kriter kullanımlarımını sadece zorunlu durumlardaki sorgularımızda kullanmalıyız. Sistemi incelerken kontrollü bir şekilde bu sorguları kullanabiliriz. Ancak özellikle raporlarda bu eşitsizlik kontrollerinin kullanımı, ve özellikle büyük tablolarda kullanımı bizi çok ama çok zora sokacaktır. Kesinlikle bu tür kullanımlardan uzak durmamız gerekiyor.

Konunun bu kısmı nispeten biliniyordu, ancak bana asıl ilginç gelen NOT IN kullanımlarında dönen cevapların belirsizliği oldu, bunu ilgili sayfadaki arkadaşımız çok güzel bir örnekle açıklamış aynen iletiyorum.

IN kullanımlarında aslında arka planda şu şekilde bir sorgu çalışmış oluyor "WHERE myvalue = 'A' OR myvalue = 'B' OR myvalue = NULL"
Burada bir OR işlemi olduğundan dolayı, beklemediğimiz bir sonuç ile karşılaşmamız olası değil.


NOT IN kullanımlarında ise arka planda aslında olan 'WHERE myvalue <> 'A' AND myvalue <> 'B' AND myvalue <> NULL “

İşte burada bir AND işlemi var, NULL olan alanlar belirsiz olduklarından dolayı, sorgu sonucunda beklemediğimiz bir sonuç kümesi ile karşılaşmamız olası.

A IS NULL ve A = NULL arasında fark olduğunu unutmamak gerekli. Bir çok kişi bu basit hatadan dolayı saatlerce sorgusundaki hatayı arayabilir -ben çok aradım-.


Buradaki kıyaslama için SET ANSI_NULLS = ON/OFF durumu önemlidir. Uygun olan kullanım genelde ON şeklindedir. Yukarıda yazdığım örnekte bu ayarın ON durumunda olduğunu varsaydım.

27 Ocak 2010 Çarşamba

Microsoft Expression Blend 3 SketchFlow İncelemesi

Microsoft geçen aylarda Expression ürünü piyasaya sürdü, veya ben yeni tanıştım :) Sizde tanışmak isterseniz buradan resmi sitesine erişebilirsiniz.

Çalıştığım şirket Expression içerisinde olan SketchFlow kullanımını incelememi istedi, bende inceleme sonuçlarını sizlerle paylaşmak istedim. Burada sadece Blend için bir SketchFlow projesi üzerine inceleme yaptım. WPF değil, "Silverlight 3 SketchFlow Application" projesi oluşturdum ve buradaki eğitim videolarını kullandım. Jeremy Osborn adlı birisi anlatımı yapıyor. 2009 Haziran ayında kaydedilmiş, henüz ürün betayken. Eğitim video sayfasında "Download the assets, step-by-step guide, and video package (127MB)" linkinden tüm ilgili videoları ve örnek kodları tek seferde indirebilirsiniz.

SketchFlow projelerinin amacı, özellikle web projelerinde, sayfa tasarımlarının en başta, tahta veya kağıt üzerinde çizilmesi yerine bilgisayar ortamında yapılmasına imkan vermek. Kağıda çizerek "abi bu olmuş mu" demek yerine, biraz daha çaba göstererek SketchFlow projesi oluşturursak bize ne avantajlar sağlıyor önce buradan başlayalım.

SketchFlow kullanıldığında, isteğinize göre el çizimine benzer şirin kontroller veya daha ciddi duran, web kontrolleri kullanma imkanınız var. Buradaki tercihimiz, ürünü kullanım amacımıza göre değişebilir. Örneğin şirket içinde kendi geliştirme akışımızda ürünü kullanacaksak, çok ciddi ekranlara ihtiyacımız yok, amacı net ortaya koyan ekranlar yeterli olabilir. Amacımız müşterilere yönelik bir sunum yapmak ise, -örneğin bir demo sunumu- animasyonlar ile süslenmiş ve ciddi tasarlanmış ekranlar seçilebilir.

Bu ürünü istediğimiz gibi kullanmakta özgürüz ancak ürün müşteri sunumları için tasarlanmış değil. Genede kullanılabilir, sadece müşterilere bu demonun amacının ne olduğu çok itina ile izah edilmeli :)

Teknik konulara girersek, SketchFlow'un en büyük özelliği çok basit bir şekilde sayfa hareketlerinin tanımlanmasını sağlaması. Bir sayfa eklediğimizde, sıradaki sayfanın ne/neler olacağını, nasıl bir akış ile ilerleneceğini ayarlamak gerçekten çok basit ve kullandığımız yazılım (IDE) bu konuda işlevsel. Sayfalarda UserControl ve ComponentScreen olarak kontroller tanımlayabilir ve bunları istediğimiz tüm sayfalara sürükle-bırak yöntemi ile ekleyebiliyoruz.

Butonlara geldiğimizde şu nokta önemli, butonun tek bir işlevi olmalı, bir kontrolün yapacağı işlem başka kontrole bağımlı olmamalı. Yani eğer butona ilk basıldığında şu olsun, sonrasında tekrar basılırsa bu olsun derseniz script kullanmanız gerekecek. Veya şu checkbox seçiliyse butona basıldığında bu olsun derseniz gene aynı şekilde script kullanmanız gerekecek. Script kullanma durumlarını ben incelemedim ve videolarda bu kısım geçmiyor, bir tek yerde script kullanılması gerekli ama bu bizim konumuz dışında şeklinde bir uyarı vardı. Kısacası script kullanımı kolay mıdır, zor mudur benim bir bilgim yok.

Sayfalarımızı basit tasarladığımızda, duruma göre davranan kontrollerden kaçındığımız durumlarda, SketchFlow bize çok büyük zaman kazandırabiliyor. Hem kısa zamanda güzel görsel bir sonuç elde ediliyor hemde aşağıda açıklayacağım farklı imkanlardan faydalanmamızı sağlıyor.

Animasyon konusuna da değinmek isterim, daha önce hiç animasyon ile uğraşmamış bir kişi olarak Silverlight SketchFlow projelerindeki animasyon imkanları gerçekten çok hoşuma gitti. Butona tıklandığında neler olacak, göstermek isterseniz, bunu inanılmaz kolay bir şekilde yapabiliyorsunuz. İşte bu yetenek, özellikle müşterileri görsel olarak etkileyecek bir sunumda çok faydalı olacaktır. Bu iş için tasarımcı ayıramayan şirketlerde; ön satış, satış hatta teknik ekipler bile etkileyici animasyonlar hazırlayabilirler.

Peki projemizi bitirdik, şimdi ne olacak.
Öncelikle karşımıza beklediğimiz şekilde bir web sitesi çıkmayacak. Silverlight SketchFlow projelerini "package" oluşturarak çalışır hale getirebiliyorsunuz. SketchFlow Player aracılığı ile sayfları gezebiliyorsunuz, bu player İnternet Explorer ile veya farklı bir browser ile, silverlight yüklü bir bilgisayarda açılabiliyor. Burada önemli nokta şurada, browser ile açabiliyor olmamız, elimizde web sayfaları olduğu anlamına gelmiyor. Basitçe player sayfaları gezme imkanını bize sunuyor. Player yoksa gezecek birşeyimiz de yok :)

Player sadece sayfları gezme imkanı vermiyor, altta map ile tüm sayfaları ve birbirlerine bağlantılarını bize gösterebiliyor. Sayfa sayımız arttıkça bu bağlantıları incelememiz zorlaşıyor, yani bu map kızmını akış çıkarmak için kullanmak pek olası değil. Sayfayı gezerken yan tarafta, o sayfanın etkileşimde olduğu diğer sayfaları ve o sayfa içerisindeki eventlerin neler olduğunu görebiliyoruz. Blend içerisinde bu işlemin adı event değil, sanırım behavior terimi kullanılıyor.

Player ile yapılan sayfaları gezen kişiler, ekran ile ilgili yorum, öneri ve isteklerini player aracılığı ile kaydedebiliyor. Bu çok uygun geri dönüşler alınmasına imkan sağlıyor. İzleyen kişi ekrana çizim yaparak müdahale edebiliyor, bu çizimler bizim projemizi bozmuyor. Çizim yanında yan tarafa not ekleyebiliyor, veya bazı yazıları "highlight" edebiliyor. Sonrasıda bunu bir "feedback" olarak kaydediyor ve projeyi yapana gönderiyor. Burada sadece feedback dosyasının gönderidiğini ve projenin tamamının gönderilmediği önemli. Projeyi yapan kişi, feedback dosyasını açtığında, kim-nerede-ne zaman-ne yorum yapmış, ekranda neresi için öneri/istekte bulunduş detaylıca görebiliyor. Bu kısım müşterilerle olan iletişimlerde de sayfalarda mutabık kalınması konusunda son derece verimli olarak kullanılabilir.

Projenin sonunda "Export to Microsoft Word" dediğimizde, projemizdeki her sayfa için bir screenshot barındıran bir çıktı elde ediyoruz. Bu word dosyasında, içerik bilgileri dahi var, kendi anlatımımızı gereken yerlere eklediğimizde elimizde harika bir doküman oluşmuş oluyor.

Sonuç olarak, bu ürün ile amacımız, karşımızdaki kim olursa olsun, onlara bir izlenim verebilmek. Detaylara girmeden, basitçe, mümkünse animasyonlar kullanarak, know-how'ımız nedir, neler yapabiliriz, fonksiyon setimiz nedir, gibi bilgileri muhattabımıza aktarmak.
Bana göre, sunumu yapılan veya tasarlanan gerçek sistemde, müşteri için 15 bilgi alacaksak, bunların tamamını sunuma koymaya gerek yok, 2-3 tanesini yazmamız yeterli olacaktır. Burada amacımız karşımızdakine müşteri bilgilerini tutarız fikrini verebilmek. İleriki aşamalarda, hangi bilgileri tutulmalıya kadar geldiğimizde gereken alanları ekleyebilir, karşı taraftan yeni alanlar için feedback alabiliriz.

20 Ocak 2010 Çarşamba

SQL'deki Bazı Fonksiyonlar : NTILE()

NTILE msdn
Açıkçası NTILE fonskiyonuna bugüne kadar hiç işim düşmedi, ancak geçmişte böyle bir fonksiyona ihtiyacı olan kişiler varsa, onlar için hayat kurtarıcı olduğuna eminim.

Bu yazımı da okumadan önce, SQL 2005 ile gelen yeni sıra numarası fonksiyonlarının temeli olan ROW_NUMBER() fonksiyonu ile ilgili yazımı okumanızda fayda var.

NTILE() fonksiyonu, diğer sıralama fonksiyonlarından farklı olarak bir parametre ile çalışır. Parametresi NULL veya 0 olamaz. Bu parametre, dönen satırları kaç parçada gruplamak istedimiz bilgisini içerir.

Örneğin dönen 13 satırımız varsa, parametre olarak da 1 gönderirsek, her satırın sıralama değeri 1 olacaktır. Parametre olarak 13 gönderirsek sıralama değerleri, 1 den başlayacak ve 13 e kadar gidecektir. Sıralama numarasını verirken kullanılacak olan değerler OVER() içerisindeki ORDER BY kolonu ile sıralanacaktır.

Peki 13 satırı 5 grup ile sırala dersek hesaplama nasıl olacaktır?

13/5 = 2,x = 3 yani ilk grup 3 elemandan oluşacak.
10/4 = 2,x = 3, ilk 3 satır yukarıda gruplandı, 10 satır ve 4 grup kaldı geriye, 2. grupta 3 satırdan oluşacak
7/3 = 2,x = 3
4/2 = 2
2/1 = 2

Sonuç olarak NTILE(5) fonksiyonu, 13 satırımıza aşağıdaki gibi sıra numarası verecektir.

1
1
1
2
2
2
3
3
3
4
4
5
5

NTILE(5) OVER(PARTITION BY "KOLONA" ORDER BY "KOLONB") şeklinde kullanıldığı durumda, tüm satırları, KOLONA'ya göre gruplayacak ve sonrasında, her grubu kendi içerisinde KOLONB'ye göre sıralayacak ve her grubu 5 iç gruba bölecek şekilde sıralama numarasını dağıtacaktır.

Başlarda biraz karmaşık gelse de, kullandıkça mantığa alışılacaktır diye düşünüyorum, dediğim gibi benim bu fonksiyona şimdiye kadar işim düşmedi. MSDN sayfasındaki örnekler gayet güzel, AdventureWorks örnek veritabanını indirerek kendi makinanızda denemeniz faydalı olacaktır. Özellikle PARTITION BY ve ORDER BY alanlarını değiştirerek mantığı kafanızda oturtmanızda fayda var.
Ben ilk denemelerimde pek beklediğim şekilde sonuçlar alamamıştım, mantığı kafamda oturtana kadar biraz şaşı bak şaşır modunda dönen dataset'leri incelemiştim :)

15 Ocak 2010 Cuma

SQL'deki Bazı Fonksiyonlar : RANK() ve DENSE_RANK()

RANK() msdn 
DENSE_RANK() msdn

Bu yazımı okumadan önce, ROW_NUMBER() ile ilgili yazımı okumanızda fayda olacaktır. Mantığı aynı olduğu için aynı detaylara daha fazla girmeyeceğim.

Sıralama ve gruplama fonskiyonlarından birisi de RANK() fonksiyonudur. Bu fonksiyon aslında ROW_NUMBER() ne yapıyorsa aynısını yapar, tek bir farkla. Eğer ORDER BY durumunda kullanılan değer, farklı satırlar için aynıysa, ROW_NUMBER() fonksiyonu sıra numarasını arttırmaya devam eder. Hangisine ilk sırayı verir derseniz, bence diskteki fiziksel sıralamada önde olana ilk sırayı veriyor olabilir, yani Clustered Index'e göre ilk geleni veya son geleni alabilir (ASC ise ilk DESC ise son). Bu kısımdan emin değilim, açıkçası tam olarak nasıl olduğuna pek işim düşmedi.

Şimdi aynı sorgumuzu RANK() ile çalıştırırsak, göreceğimiz tek fark, ORDER BY için kullanılan değerin aynı olması durumunda, bu kayıtların tamamına aynı sıralama numarası verileceğidir. Eş kayıtların aynı numarayı almasından sonra, sıradaki kayıt ise bir sonraki numara ile devam edecektir. Mesela : 1,2,3,3,3,4,5,5,6,7,8,9........

Gene aynı sorgumuzu DENSE_RANK() ile çalıştırırsak göreceğimiz tek fark, eş sayıların sırasından sonra gelen yeni sayının, kaldığı yerden değil, gerçek sırasından devam edeceğidir. Yani bazı sıra numaraları atlanmış olacaktır. Anlatması biraz zor olduğu için direk yukarıdaki örneğe geçiyorum, hemen anlaşılacaktır. 1,2,3,3,3,6,7,7,9,10,11,12........



SQL'deki Bazı Fonksiyonlar : ROW_NUMBER()


ROW_NUMBER() msdn 
Eksikliği MSSQL'de çok uzun zaman hissedilmiş bir fonksiyondur. SQL 2005 ile aramıza katılmıştır kendisi. Basitçe, sorgumuzdaki satırların, sıra numarasını döner diyebilir. ROW_NUMBER() fonksiyonunun çalışabilmesi için OVER ile kullanılması şarttır. OVER'ın anlamı, fonksiyona, dönen datasetin, neye göre gruplanıp, neye göre sıralanacağı bilgisini aktarmaktır. ROW_NUMBER() fonksiyonu bize kaydın, dönen verilerin içerisindeki sıralamasını verecektir, orjinal tablodaki sırasını vermeyecektir, bu ilk başlarda kafamızda durumlar canlandırırken sıkça yapabileceğimiz bir hatadır. Gerçekten ihtiyacımız bu ise, tablodaki tüm kayıtları alarak ve tablodaki Primary Key ile uygun sırada sıralama yaparak (ASC, DESC) fiziksel sıralama bilgisine ulaşabiliriz.

ORDER BY ile kullanımı 
SELECT ROW_NUMBER() OVER(ORDER BY KOLON1), *
FROM TABLO 
WHERE ...
ORDER BY KOLON2

Bu şekildeki bir sorgu, WHERE şartlarımıza uygun olarak dönen kayıtları KOLON1'e göre ASC olarak sıralayacak, ilk sıradaki kayda 1 vererek ve her satırda 1 arttırarak bize satır sıra numarasını dönecektir. Buradaki sıralama kayıtların dataset içerisindeki sıralaması değildir. Yani dönen dataset içerisindeki kayıtlar KOLON2'ye göre sıralanmış olacaktır. Bu kısım başlarda biraz karışık gelebilir, özet olarak; eğer KOLON1 ve KOLON2 farklı şekilde sıralanıyorsa, yukarıdaki sorgudaki satır sayıları sıralı olarak listelenmeyecektir.


PARTITION BY ve ORDER BY ile kullanımı
SELECT ROW_NUMBER() OVER(PARTITION BY KOLON3 ORDER BY KOLON1), * 
FROM TABLO 
WHERE ...
ORDER BY KOLON2

Yukarıdaki sorgunun şu sırayla çalıştığını hayal edelim, WHERE şartlarımıza uyan kayıtlar, KOLON2' e göre sıralı olarak bize döner, ROW_NUMBER() alanı şu anda null'dır, bu kayıtlara orjinaldataset gibi bir isim verelim :) Kayıtların tamamı elde edildikten sonra, datasetimiz içerisindeki kayıtlar KOLON3'e göre gruplanır, her bir grup için kendi içerisinde KOLON1'e göre bir sıralama yapılır. Bu sıralama 1'den başlar ve 1 artarak ilerler. Her grubun kendi içerisinde sıralandığı unutulmamalıdır, yani grup sayısı kadar 1 değerine sahip ROW_NUMBER() olacaktır. Bu şekilde elde edilen satır sayıları ile orjinaldataset üzerindeki null olan ROW_NUMBER() alanı güncellenir ve elimizde son hali ile kayıtlarımız oluşmuş olur.