Professional Documents
Culture Documents
VERİTABANINA ERİŞİM
Tipik bir iş yeri veri tabanı yüklemesinde, veri tabanının çalıştığı bilgisayarı göremezsiniz.
Veritabanı, server odasındaki server’dadır ve siz masaüstü bilgisayarla çalışacaksınızdır. Veritabanıyla
bağlantı kurmak için ona ağ üzerinden bağlanmalısınız.
Genelde bağlantınız LAN (yerel ağ bağlantısı) veya WAN (geniş ağ bağlantısı)’la sağlanır.
Bilgisayarınız, ağ arayüz kartı ve bu karta takılı ağ kablosuna sahiptir. Bu kartların en yaygını Ethernet
adaptörüdür. Bununla beraber Token ring adaptör de kullanabilirsiniz. Ağ arayüz kartı server’la iletişim
sağlar (istekte bulunur, cevap alır). İletişim, protokoller adı verilen bir grup sözleşmeye göre yapılır.
Bunların en yaygını Transmission Control Protocol / Internet Protocol (TCP/IP)’dir.
Protokoller, ağdaki diğer bilgisayarlarla iletişimi sağlamak için 2 tip isme izin verirler. Her
bilgisayar, kendisini ağda belirten, karakterlerden oluşmuş bir string’e sahiptir. Ağdaki bir bilgisayarla
iletişim sağlamak isterseniz o bilgisayarın ismini Run diyalog kutusuna yazmanız yeterlidir (Windows’un
yerel sürücüde aramaması için başına 2 tane backslash (\\) koymalısınız).
Diğer bir bağlanma yolu da ağ adresiyledir. Ağlar, isimleri adreslere eşlemek için özel servisler
kullanırlar. Bunlardan en yaygınları Internet’te kullanılan Domain Name System (DNS) ve Windows
altında çalışan Windows Internet Name Service (WINS)’tir. Eğer bunlar çalışmazsa bağlanacağınız
bilgisayarın adresini bilmeniz gerekir.
SORGULAMA ARACINI KULLANMAK
Bütün veri tabanları değişik tipte sorgulama aracı sunarlar. Windows altında çalışan bütün
sorgulama araçları bazı yaygın özelliklere sahiptir. Hepsi de başladıklarında veritabanıyla bağlantıyı
sağlamak için bağlantı diyalog kutusunu ekrana çıkarır. Her bir bağlantı penceresi 2 parçadan oluşur:
Birisinde SQL sorgusunu yazarsınız, diğerinde de sorgulamanın sonucunu görürsünüz.
SQL Server’ın Query Analyzer aracında bağlantı diyalog kutusunda 3 tip bilgi vardır: Birincisi,
server’ın ismi (adresi de kullanılabilir). İkincisi, eğer server durdurulmuşsa yeniden başlatılıp
başlatılmayacağı. Sonuncusu da sizi doğrulamak için kullanıcı adı ve şifre.
Genel olarak Windows altında veritabanına bağlantı için 2 yöntem vardır: ODBC kullanmak veya
OLE DB kullanmak. (SQL Server Query Analyzer her iki yöntemi de desteklemektedir.)
ODBC’Yİ KULLANMAK
Her veritabanı satıcısının veritabanına bağlanmak, login olmak ve sorgu yollamada kendine has
aracı vardı. Kurumlar için karışıklıktan düzenin daha anlamlı olduğu düşünülmüş ve Microsoft ile büyük
satıcılar Open Database Connectivity (ODBC) adı verilen stratejiyi geliştirmişlerdir.
ODBC, kullanıcı tarafında veritabanına bağlanmak için standart bir yol, işletim sistemi tarafında
her satıcıya veritabanının ihtiyaçlarını karşılamak için kullanıcı tarafından sağlanan bilgiyi çevirmeye izin
veren uygulamanın bir katmanı haline geldi.
Denetim Masalarından ODBC applet’ini açtığınızda diyalog kutusunun 3 sekmesini ayarlama
ihtiyacı duyarsınız.
Veritabanına bağlantı kurarkenki ilk sorunuz bu 3 sekmeden hangisini kullanacağınız olacaktır.
Bağlanmak için Data Source Name (DSN) oluşturmanız gerekir. Eğer bir kullanıcı User DSN
oluşturmuşsa bu DSN login olmuş kullanıcıyı bağlar. Eğer siz login olmuşsanız veritabanı bağlantısına
erişebilirsiniz. Eğer ben login olmuşsam sizin oluşturduğunuz User DSN’e erişemem. User DSN’ler,
değişik kullanıcıların aynı bilgisayarı paylaşması, fakat değişik veri kaynaklarına erişmesi gerektiğinde
kullanıma uygun olan bir durumdur.
Bir System DSN, zıttına, sisteme ilişkilendirilmiş veri kaynağı sağlar. Veritabanına herhangi bir
kişi kendi kullanıcı ismiyle login olabilir.
File DSN’ler dosyalarda tutulur ve sonuç olarak taşınabilir çapraz sistemlerde file DSN’i başka
bir sisteme taşımak sadece dosyayı kopyalamaktan ibarettir. File DSN’ler çok kullanışlıdır. Ayrıca
bunları Notepad’le açıp bağlantı stringi’nin bütün bölümlerini kontrol de edebilirsiniz.
DSN oluşturma işlemi her 3 olayda da benzerdir. Biz örnek olması açısından bir System DSN
oluşturacağız. Şu adımlar izlenir:
1. Bağlantınız için kullanacağınız sürücüyü seçin (Biz SQL Server’ı seçtik) ve Finish’e tıklayın.
2. Bağlantınız için isim giriniz. İsmi, ilerde veri kaynağına bağlanırken kullanacaksınız.
3. İsteğe bağlı olarak tanımlama girebilirsiniz.
4. Bağlanacağınız server’ı seçin. İsim yazabileceğiniz gibi drop-down list’ten de seçebilirsiniz.
5. Kullanmak istediğiniz güvenlik düzenini seçiniz. Windows NT güvenliği varsayılandır ve
size Windows NT kullanıcı ismini kullanmanıza olanak tanır. Bu düzende alanınıza bir kez girdiğinizde
SQL Server’a bağlanmanıza gerek kalmaz. SQL Server güvenirliliğini seçerseniz veritabanı yöneticisi
tarafından oluşturulmuş olan kullanıcı adı ve şifreyi girmek zorunda olursunuz.
6. Bir sonraki diyalog kutusu, bazı özel parametreleri ayarlamanıza izin verir. Veritabanı
yöneticisi size aksini bildirmedikçe varsayılan değerleri kullanınız. Değiştirebileceğiniz değer örneğin,
listeden seçebileceğiniz varsayılan veritabanı olabilir.
7. Son diyalog kutusu size daha ince ayarlar yapmanıza imkan tanır. Veritabanı oturumunuz için
log dosyalarını ayarlayabilir, varsayılan şifreleme düzeneğini değiştirebilir veya sistem için kullandığınız
dili değiştirebilirsiniz. Genelde varsayılan değerleri değiştirmenize gerek kalmaz. Finish’e tıklayın.
8. Son diyalog kutusu, bağlantı için kullanacağınız ayarların bir özetini oluşturur. En önemli
(kritik) kontrol Test Data Souce düğmesidir. Bağlanabileceğinizden emin olmak için tıklayın. Eğer
bağlanamazsanız Cancel diyerek ayarları gözden geçirin. Bağlantı ayarlarını sonlandırmak için OK’e
basın.
Bu noktada ODBC kullanarak veritabanına bağlantı sağlamış oldunuz. Şunu unutmayın ki bütün
veritabanı satıcıları bu metodu desteklerler.
OLE DB’Yİ KULLANMAK
ODBC, bilgisayar endüstrisinin veritabanına genel erişimi sağlamada ilk adımıydı. İşletim
sisteminiz için ODBC sürücünüz olduğu zaman veritabanına bağlanabilirsiniz. Bununla beraber, işletim
sisteminin servislerini kullanarak bağlantı ayarlarını yapmak zorundasınız. Bu da her makine için bağlantı
ayarlarının ayrı ayrı yapılması anlamına geliyor. Örnek verirsek, 2000 düğümden oluşan bir ağda 2000
defa bu ayrların yapılması gerekir ki bu da pek kolay bir şey değildir.
Her bir bilgisayar için bağlantı ayarları yapılma zorluğunu aşabilmek için Microsoft umumi
veritabanı erişim stratejisi üzerinde durdu. Distributed Internetworking Architecture (DNA)’nın bir
parçası olarak herhangi bir veri kaynağına bağlantısız bağlantıları sağlamaya karar verdi. DNA için
umumi veri erişiminin arkasındaki kavram, provider olarak bilinen yüklenebilen sürücüydü.
Gerçekte siz bir kullanıcıysanız ODBC Control Panel Applet haricinde direk olarak
bağlanamazsınız. Bununla beraber siz bir programcıysanız bağlanabilirsiniz ve bunu yapmak için de
ODBC ayarlarını yapmanıza gerek yoktur. Bağlantı string’i provider’ın veritabanı bağlantısını başlatması
için gerekli bütün bilgileri içerir. Bu teknolojiyi uygulamak için Microsoft, OLE DB ismini seçti. OLE
DB bağlantısı yapmak için olan programlama teknolojisi ActiveX data objects diye anılır.
Bu teknoloji, veritabanına programlama bağlantısı üzerine odaklandığı bağlantının nasıl
yapıldığına şimdilik değinmiyoruz.
PROGRAMDAN BAĞLANMAK
Veritabanıyla kullanışlı bir iş yapmak için programdan bağlantının nasıl yapılacağını
öğrenmelisiniz.
Bağlantı kurmak için veritabanına arayüz kullanmalısınız. Alçak seviyede, makine dili emirleri
bağlantı kurar ve programınıza veri servisleri sağlar. Makine dili veya assembler’da yazmak kolay bir iş
olmadığından dolayı yüksek seviyeli dillerde güç anlaşılır, karışık formdaki program yazımları basit
şekilde tasarlanmıştır. Bellekte veri depolamak için adresleri ve kütükleri yönetmek için şunu yazarız:
Veritabanıyla bağlantı kurmak için özelleştirilmiş bir arayüze ihtiyaç vardır. Veritabanı satıcıları
bunları destekler ve bunlara tipik olarak Application Programmming Interfaces (API) adı verilir. API’ler
nispeten alçak seviyeli olabilir (programınıza bağlantı kurabileceğiniz ve veriye erişim için
çağırabileceğiniz bir grup C dili fonksiyonları gibi). API’ler oldukça yüksek seviyede de olabilirler
(Microsoft’un halkın anlayabileceği bir şekle getirdiği nesneya dayalı arayüzler gibi). Alçak seviye
arayüzler hız sağlarken, yüksek seviye arayüzler de kolaylık sağlarlar.
BAĞLANTI KÜTÜPHANESİNİ KULLANMAK
Alçak seviye arayüze örnek olarak C’de yazılmış ve dosya isimlerinde ODBC içeren bir grup
DLL(dynamic-link libraries)’de depolanmış ODBC API’ı verebiliriz. Tipik olarak bu kütüphaneler belirli
bir veritabanı erişim programıyla ilişkilendirilmiştir.
Bu dosyalarda içerilen fonksiyonlar fazla değildir. Bunları görmek için en kolay yol Visual
Studio development environment’ta içerilen ODBCAPI.BAS’ı açmaktır.
Usüle göre veri tabanına bağlanmak için veritabanı işaretçisine veya handle’a ihtiyaç vardır.
Handle elde etmek 2 işlem adımıyla gerçekleştirilir. İlk önce bağlantı kurmak için SQLDriverConnect’i
çağırırsınız, ardından handle’ı elde etmek için SQLAllocHandle’ı çağırırsınız. Diğer fonksiyonlar imleci
yönetmeye, kayıt kümelerini almaya ve saireye izin verir.
Bir kere uygun dahil edilme işlemini izlediğinizde veriye erişmek için fonksiyonları çağırabilirsiniz.
ODBC çağrısını direk olarak kullanarak veritabanına bağlanmanın en kolay yolu SQLDriverConnect
fonksiyonunu kullanmaktır. Bu fonksiyonu kullanmak istiyorsanız veritabanına bağlanmak için
kullanılacak geçerli bir bağlantı stringi’ne sahip olmanız gerekir. Bağlantı stringi ODBC ile 2 temel biçim
alır. İlkinde sürücü ismini ve server ismini aşağıdaki gibi açıkça belirtisiniz:
“DRIVER={SQL Server}; SERVER=AYKUT; UID=sa; PWD=MyPwd;
DATABASE=pubs;”
Bağlantı stringi’nin bu biçiminde sürücü ismi parantez içinde yazılır. Server adı ve ek bağlantı
bilgileri düz yazıyla yazılır. Diğer biçimde, ODBC Control Panel applet’ini kullanarak kurduğunuz
DSN’in adını kullanırsınız. Bu biçim şu şekilde gözükür:
Bu durumda veritabanı server’ın ve varsayılan veritabanı’nın ismi DSN’de içerilir. Siz sadece
DSN’le bağlantı oluştururken kullanacağı kullanıcı adı ve şifreyi string’e ekliyorsunuz.
Gerçek bir bağlantı yapmak için bağlantı stringi’ni bir string değişkende saklamak
isteyeceksinizdir. Ardından, SQLDriverConnect fonksiyonunu çağırırsınız ve birkaç önemli parametre
aktarılır. Aşağıdaki Visual Basic kodu, nelerin gerekli olduğunu gösteriyor:
Bu üç deyimin hepsi bağlantı kurmak için gereklidir. İlki string değişken için bellekte yer tahsisi
yapar. İkincisi bağlantı stringini değişkene atar. Üçüncüsü de bağlantıyı yapar.
SQLDriverConnect birkaç gizemli parametre gerektirir. İlki, var olan bağlantı için bir handle’dır.
Var olan bir bağlantıyı tahsis etmediğimizde, aslında SQLDriverConnect’e bizim var olmayan bir
bağlantıyı ona verdiğimiz gerçeği ile baş etmesini anlatan SQL_NULL_HANDLE değerini şart
koşmalıyız. İkinicisi, çağrı yapan pencerenin handle’ıdır. Eğer, kullandığımız pencereyle ilişkilendirilmiş
bağlantı istiyorsak değer girebiliriz, aksi halde null yazarız. Üçüncü parametre bağlantı stringi’nin
kendisidir, dördüncü parametre uzunluğudur. 5. 6. ve 7. parametreler yerleşmiş olan buffer’daki bir string
buffer alıcı, uzunluğu ve adresidir. Alıcı bufferlar düşük seviyeli C programlarında yaygındırlar.
SQLDriverConnect dönüş bilgilerini bu değişkene yerleştirir ve bu sayede biz, bizimle hangi
fonksiyonların bağlantı kurmuş olduklarını görerek kontrol edebiliriz. Bu örnekte buffer kullanmadık, o
yüzden null string verdik. Son parametre ise bağlantı kurmaya çalışırken kaybolan bağlantı bilgileri için
kullanıcıyı uyarıp uyarmadığını belirten SQLDriverConnect değeridir.
Böylece ODBC kullanarak nasıl bağlantı yapılacağını öğrenmiş oldunuz.
DAO’YU KULLANMAK
Microsoft’un veritabanı programcılarına sağladığı ilk arayüz Data Access Objects (DAO) diye
anıldı. Kolay kullanımlarından dolayı popüler oldu. Çoğu geliştirici çevreler desteklemeye başladı. DAO,
size nesne arayüzü belirten bir referansı projenize eklemenize izin verir.
Eğer veriye erişmek istiyorsanız veritabanı nesnesini kullanmalısınız.
Microsoft dillerinde nesneleri, değişken gibi deklare ederek oluşturursunuz. Veritabanı nesnesini
oluşturmak için Visual Basic’te aşağıdaki deyimi yazarız:
Burada nesneyi deklare ettik ama kullanmak için hazır değiliz. Instantiate, soyut nesneye fiziksel
bir varlık verir. DAO Veritabanı nesnesini instantiate yapmak için DAO tip kütüphanesinde tanımlanan
metodlardan birini kullanırız. DAO, fazla açıklama gerektirmeden kullanmamıza hazır olan DBEngine
diye adlandırılan nesneyi sağlar. Bu nesne veritabanı nesnelerini bizim için instantiate eden
OpenDatabase metoduna sahiptir. Visual Basic’te herhangi bir nesneyi instantiate yapmak için Set
deyimini kullanırsınız. Veritabanına DAO bağlantısı oluşturmak için şu deyimi kullanın:
Set dbMyDatabase= DBEngine.OpenDatabase(“c:\NorthWind.mdb”)
Bu, yerel dosyada saklanan veritabanı için bağlantı sağlayan en kısa bağlantı biçimidir.
OpenDatabase gerçekte 4 parametre alabilir:
* Veritabanı ismi: Veritabanı için bağlantı stringini gösteren veya dosyanın adını veren string’tir.
* Seçenekler: Bağlantı stringi’ndeki kaybolan bilgiler için kullanıcıların uyarılıp
uyarılmayacağını belirten sabit değerdir. Mümkün değerler: dbDriverNoPrompt, dbDriverPrompt,
dbDriverComplete (gerekli olduğunda diyalog kutusunu gösterir), dbDriverCompleteRequired (daha önce
belirtilen seçenekleri geçersiz sayarak gerekli durumlarda diyalog kutusunu gösterir).
* Read-Only: Veritabanı bağlantısını salt okunur yapmak için True, okuma-yazmaya açık yapmak
için False seçiniz.
* Connection: Veritabanı ismi parametresinde belirtilmeyen ek bağlantı bilgilerinin yazıldığı
string değerdir.
Bütün bilgileri içeren DAO bağlantı deyimi şöyledir:
ADO’YU KULLANMAK
ActiveX Data Objects (ADO), Microsoft’un OLE DB’ye arkadaşlık etmesi için tasarladığı yeni
veri erişim stratejisidir. ADO nesneleri veritabanına erişim için değişik bir nesne hiyerarşisi sağlar.
Nesnelerin yapısı DAO’ya göre Microsoft Access’e daha az dayalıdır. Ayrıca, çoğu kişiler ADO’yu
veritabanıyla ilişkide bulunmak için DAO’dan daha sezgisel bulmaktadırlar.
ADO kullanarak veritabanına bağlantı kurmak için geliştirme projenize referansları eklemelisiniz.
Bunu yaptıktan sonra veritabanı bağlantısı istiyorsanız bir bağlantı nesnesi oluşturmalısınız. Bağlantı
nesnesinin tek ayarlamanız gereken özelliği vardır (Connection string özelliği). Bu nesnenin bağlantıyı
açmak için çağıracağınız Open Metodu vardır. ADO’da bağlantı kurmak için aşağıdaki kodu inceleyelim:
Dim cnnDatabase As ADODB.Connection
With cnnDatabase
.ConnectionString=”Provider=SQLOLEDB.1;Persist “_
“Security “Info=False;User ID=sa; Initial Catalog=pubs;” _
.Open
End With
Bağlantı stringi’ni ayarlamak oldukça açıktır. Bütün bilgiler aynı özellik kümesindedir. Bununla
birlikte, bağlantı stringi biraz değişiktir. Burada, Provider’ın ismini vermelisiniz. Provider’lar
OLEDB’nin bağlantı kurmak için kullandıkları sürücülerdir.
Bu kod çalıştığında veritabanına bağlantı sağlamış olursunuz.
Burada + işlemi iki sütunu birleştiriyor (string için tek tırnak kullanıldığına dikkat edin) ve
sütunun ismi de AS deyimi yardımıyla full_name olarak adlandırılıyor.
Tip: Bazı veritabanları SQL deyimlerinin sonuna “;” konmasını ister. Buna dikkat etmek gerekir.
(SQL Server istemezken Access, Oracle ve Sybase ister)
WHERE
Eğer tablodan döndürülecek kayıt sayısını sınırlamak istiyorsak SELECT’te WHERE ifadesini
kullanmalıyız.
Tablonun başından itibaren belli sayıda kayıt çekmek istiyorsak TOP deyimini kullanabiliriz.
Örneğin:
TOP deyimi sadece tablodan sırasıyla kayıtları çeker. Eğer belli bir koşula göre tablodan kayıt
çekmek istersek WHERE ifadesini kullanmalıyız. Kullanımına örnek verirsek:
SIRALAMA
Verinin sıralanmasını ORDER BY deyimiyle gerçekleştirebiliriz. Örneğin:
Burada sıralama çeşidini belirtmezsek artan (ascending =ASC) olarak sıralanır. Azalan şekilde
sıralanmasını istiyorsak deyimin sonuna DESC ifadesini de koymalıyız. (isteğe bağlı olarak [DESC] de
yazabiliriz.)
Eğer birden çok sütuna göre sıralama istiyorsak sütunları virgüllerle ayırarak (ORDER BY
au_lname, au_fname) ve öncelik sırasına göre yazmalıyız.
ÖZET EKLEMEK
AVG : ortalama değeri, COUNT : döndürülen eleman sayısı (boş olmayan, sayılabilir), MAX : en
büyük değeri, MIN : en küçük değeri, SUM : toplam değeri döndürür. Örnek verirsek:
Burada SQL ilk önce WHERE koşuluna uyan kayıtları ord_num a göre gruplar. Ardından da bu
gruptaki her kayıtın qty bilgilerini toplar ve ord_num sütununun yanına qty toplamlarını da ayrı bir sütun
şeklinde yazar. Eğer bu örnekte GROUP BY ı kullanmasaydık SQL hata verirdi. (Ya GROUP BY
kullanmalısınız ya da sales.ord_num bir aggregate(toplam) değer değildir diye bizi uyarırdı)
Eğer aggregate fonksiyonlarını WHERE’de kullanmak istiyorsak WHERE’de alt sorgulama
kullanılıyor olmalıdır. Aksi halde WHERE yerine HAVING ifadesini kullanmalıyız. HAVING, GROUP
BY’dan sonra icra edilir.
Veritabanından sadece birbirinden ayrı olan elemanlarını almak istiyorsak:
Burada COUNT ile geçerli olan 21 değer alınıyor. Bu 21 kayıdın qty toplamları 30’dan büyük
olduğu için HAVING sağlanır ve COUNT’un sonucu olan 21 değeri döner.
Eğer toplama fonksiyonunda sütun ismi verilmemişse GROUP BY’da verilmesi lâzımdır.
Ayrıca, bütün sütun isimleri toplama fonksiyonlarında içerilirse HAVING’i GROUP BY’sız
kullanabiliriz.
TABLOLARI BİRLEŞTİRMEK
Şimdiye kadar hep verilerimizi tek bir tablodan aldık. SQL, join adı verilen işlemle birden çok
tabloyla işlem yapmaya izin verir.
Burada anlaşıldığı üzere her iki tablonun da aynı kimliğe sahip elemanları döndürülüyor. Bu tür
birleşmeye iç birleştirme (inner join) adı verilir. Burada tabloya erişim tablo adı ile sağlanıyor.
(tablo_adi.sütun_adi = veritabani_ismi.sahip_adi.tablo_adi.sütun_adi)
Inner join oluşturmak için kullanılan yapı SQLS2 standartıyla değiştirildi:
Tip: Terminolojide, On yapısında eşitlik içerene equi joins, diğer operatörleri içerene nonequi
joins, bunların her ikisine theta joins, koşulsuz joinlere de cross join adı verilir.
Inner join haricinde iki tür birleştime daha var ki bunlara outer join de deniliyor. Bunlar right ve
left join’dir.
Right join sağdaki tabloyu aynen alır, soldaki tablodaki aynı elemanlarla birleştirir. Left ise tam
tersidir. Genel yapı şöyledir:
Başka bir örnek verirsek: Diyelim ki bir tabloda yazarlar, diğer tabloda yazılar, başka bir köprü
tablosunda da yazı ve yazar kimlikleri var. Bu tabloları şöyle birleştirebiliriz:
SELECT * FROM authors INNER JOIN titleauthor ON authors.au_id =
titleauthor.au_id INNER JOIN titles ON titleauthor.title_id = titles.title_id
Left ve right joinleri full join kullanarak birleştirebiliriz (iki tabloyu birleştirmek).
ALANLARI BİRLEŞTİRMEK VE SÜTUN OLUŞTURMAK
Alanları birleştirmeyi daha önce görmüştük. (+ operatörü ile) Bunun daha bir çok yolu vardır. Önemli
olan nokta, birleştirilerek oluşturulan sütuna sonradan tekrar erişebilmek ve isimlendirmek için AS
deyimi ile ad vermektir. Örneğin:
SELECT au_lname + ‘, ’ + au_fname AS full_name FROM authors
Bunlara ek olarak tabloya ek bir sütun ekleyip, bu sütunun elemanlarına istediğimiz sabit değeri
verebiliriz:
SELECT *, ‘Temmuz’ AS the_month FROM titles
Tip: As kullanılarak oluşturulan her isme ilişki ismi (correlation name) denir.
SQL bir bilgisayar programı içinde kullanılmışsa embedded SQL denir.
Outer join’in eski hali tablo isminden sonra + koymaktı.
VERİ EKLEME
INSERT’Ü KULLANMAK
Insert deyiminin amacı veriyi tabloya yerleştirmektir. Bu nedenle minimal formunda INSERT şu
temel elemanlara ihtiyaç duyar:
İfadeyi başlatıcak olan INSERT emri
INSERT işlemi için hedef
VALUES anahtar kelimesi ile belirtilen değerlerin listesi.
Böylece minimal yapı aşağıdaki gibi olur:
Burada, sütun ismini en sola yazıyor, peşine like komutunu ekliyor ve tek tırnak içinde girilmesi
gereken ifadeyi belirtiyoruz. (Bu örnekte, 7 haneli, 0 ile 9 arasında değişebilen rakamlardan oluşan sayı
girilmesi isteniyor.)
INSERT emri, INTO kullanmaya izin verir. (INSERT INTO) Böylece deyim, okuma açısından
daha anlaşılır olur.
Diğer bir yapı ise sütun isimlerini teker teker girmektir. Genel yapı:
Burada, girilmeyen sütunlar Null olmaz. Sütun özelliklerinde bulunan varsayılan değer
bölümündeki değer olur. Eğer sütun isimlerini vermezsek ilk değere ilk sütun, ikinci değere ikinci
sütun…. a göre yerleştirilir.
Gömülü SQL INSERT’lerde sütun isimlerinin listesini kullanmalıyız.
Not: Eğer INSERT işlemini kullanan bir programa sütun eklemek istersek o sütunu ya nullable
(hükümsüz olabilen sütun) yapmalısınız ya da o sütunu varsayılan bir değerle doldurmak lazımdır. Aksi
takdirde ya INSERT’e sütunu eklemeliyiz ya da hata mesajıyla karşılaşırız.
Not: Aynı değeri birden çok tabloya eklemek istiyorsanız her biri için ayrı INSERT
kullanmalısınız.
Sütun listesini, herhangi bir kişi tablonun tanımlanmasında değişiklikler yaptığında kodun
etkilenmemesi için kullanırız.
Verinin tipini değiştirmek için 2 yol vardır: CAST ve CONVERT:
CAST (SahipOlduğunuzVeriTipi AS OlmasınıİstediğinizVeriTipi)
CONVERT (OlmasınıİstediğinizVeriTipi, SahipOlduğunuzVeriTipi, (OpsiyonelStilTanımlayıcı))
Soru: Veriyi eklemeden önce herhangi bir yolla kontrol etmeli miyiz?
Cevap: Veritabanı programlamada bir ana kural vardır:İşe yaramayanı veritabanına koymamak.
Kullanıcıdan değerleri aldığında, onların doğru (istenilen) veri tipinde olduğunu ve doğru formatta
olduğunu kontrol etmek gerekir. Eğer her defasında yanlış formatta sonuç geliyorsa CAST veya
CONVERT kullanırız. Veri doğruluğu için birden çok gereksiz kontroller karışık programlar için kötü bir
fikir değildir. Her zaman, özellikle Windows programlarda sizin farkında olmadığınız program boyunca
bir yol daha vardır. Yol belki de bütün kontrollere engel olarak veriyi veritabanına sokmaktır.
Hatırlarsanız, kötü veriler her veritabanının kullanıcı ömrünü zorlaştırır.
SELECT’İ INSERT’LE KULLANMAK
INSERT’ü kullanırken önce yapmamız gereken tablo oluşturulmamışsa oluşturmanızdır (SQL
Server’da Enterprise Manager ile). Diğer husus ise bu türde SELECT * ı kullanmamanızdır. Aşağıdaki
örneği incelersek:
INSERT INTO temptable SELECT authors.au_id, au_lname, au_fname, phone,
address, city, titles.title_id, title, type, pubdate FROM authors INNER JOIN
titleauthor ON authors.au_id = titleauthor.au_id INNER JOIN titles ON
titles.title_id = titleauthor.title_id
Burada SELECT * ın kullanılması teknik olarak 2 tane au_id elde etmemize neden olacaktır.
(Aynı şekilde title_id de) Bu hatadan kaçınmak için tablonun bütün sütunlarını liste halinde alıyoruz.
Aynı yapıyla INSERT te SELECT içinde WHERE ve HAVING sözcüklerini de kullanabiliriz.
VERİYİ GÜNCELLEMEK
Bu ünitede tabloda bulunan veriyi değiştirmeyi inceleyeceğiz. Veritabanında hazır yerleştirilmiş
bir veriyi değiştirmek için kullanılan SQL emri UPDATE’dir. UPDATE, veriyi değiştirmek için esneklik
sağlarken aynı zamanda da tablodaki bütün verileri değiştirmeye gücü yettiğinden tehlikeli bir komuttur.
Kritik bir noktayı da vurgulamalıyız ki: WHERE veya HAVING’i kullanmayı unutmamalısınız. Eğer
unutursanız tablodaki bütün kayıtlar değiştirilecektir.
UPDATE’İ KULLANMAK
Güncelleme deyimi UPDATE emri ile başlar, güncellenecek tablonun ismiyle devam ettirilir, atama
operatörü ve ardından sütuna yerleştirilecek değerle sonlandırılır. Güncelleme için sadece bir tablo
kullanabilirsiniz. Buna karşın birden çok sütunu virgüllerle ayırarak aşağıdaki şekilde
güncelleyebilirsiniz:
UPDATE authors SET Contract=1, Phone=’’
WHERE SÖZCÜĞÜ EKLEMEK
Eğer veri tabanınızdaki bütün kayıtları güncellemek istemiyorsanız WHERE yapısını kullanmalısınız.
Örneğin:
UPDATE authors SET Conract=1 WHERE Zip=’40205’
Bu örnekte dizi 402 ile başlar ve diğer karakterler herhangi bir karakter kombinasyonu olabilir
(40205, 40213, 402AB).
Tip: Eğer wildcard karakterleri (% gibi) kullanma ihtiyacı duyarsanız, bu karakterleri özel anlam
taşımaması için köşeli parantez içinde yazmalısınız. (‘4020[%]’ gibi) Diğer bir örneği incelersek:
Bu örnek, ilk karakter olarak köşeli parantezler içinde kullanılan karakterlerden birisinin gelmesi
gerektiğini gösteriyor. (40205,50205,60205) Başka bir örnek:
UPDATE authors SET Contract=1 WHERE Zip LIKE ‘[^456]0205’
Burada kullanılan ^ tersi anlamındadır. Yani ilk karakter 4,5,6 haricinde başka bir karakter, diğerleri 0205
olmalı anlamındadır.
UPDATE authors SET Contract WHERE Zip LIKE ‘4020_’
Burada, alt çizgi karakteri, bu yere geçerli bir karakter konulacağını gösteriyor. Böylece 4020 ile
başlayan bir sonuç istenmiş oluyor.
WHERE yapılarında kullanabileceğimiz diğer ilginç ayar ise IN sözcüğünü kullanmanızdır. IN’i
aşağıda da gösterildiği gibi sütun değerlerinin bir listesini belirlemek için kullanırız:
IN, argümanı parantezler arasında virgüllerle ayrılmış bir değerler listesi olarak alır. Belirtilen sütunda
IN’den sonra gelen, parantezlerle belirtilen değerler listesi elemanlarının olup olmadığına bakar. Hangi
kayıdın sütununda o değerlerden birisini bulursa o kayıdı günceller.
WHERE discounttype LIKE ‘%20!%%’ ESCAPE ‘!’
Bu örnekte ilk ve son %’ler wildcard karakter olarak algılanıyor. ESCAPE karakter olarak
belirlenen ! den sonra gelen karakter olan % ise karakter olarak algılanıyor. Yani bu örnekte 20% içeren
elamanlar aranıyor.
Tip: Wildcard karakterleri string’inizde ESCAPE yardımıyla harf olarak kullanabilirsiniz. Yani,
# , % gibi ifadeler sade şekilde yazılsalar rakam, harf gibi anlamları vardır. Bunları ESCAPE yardımıyla
string içinde gerçek harf olarak kullanabiliriz. Burada yapmamız gereken, normal harf olarak
kullanacağımız karakterden önce bir ESCAPE karakter kullanmak ve bu ESCAPE karakteri sonda
ESCAPE ifadesi ile belirtmektir.
HAVING YAPISI EKLEMEK
Biraz karmaşık gözüken bir örneğe bakarsak:
UPDATE sales SET payterms=’cash only’ FROM (SELECT title_id FROM sales GROUP
BY title_id HAVING SUM(qty)>30) AS MySelect WHERE sales.title_id =
MySelect.title_id
Bu örnekteki UPDATE’i de SELECT’i de daha önce gördük. Görmediğimiz, bu metodların
birbirine bağlanma şekliydi. FROM’la, FROM anahtar sözcüğünü takip eden bilgiye göre sales
tablosundan kayıtların bir listesini alıyoruz. Bu kayıt listesine AS yardımıyla sonradan kullanabilmek için
isim veriyoruz ve WHERE yapısında bu kayıtları kullanıyoruz. Diğer bir deyişle, sales tablosunun title_id
sütunu gruplandırılıp, qty toplamı 30’dan büyük olanlar MySelect tablosu adıyla seçilip, sales
tablosundan MySelect’te olanlarının payterm sütunu ‘cash only’ ye setleniyor.
BİRDEN ÇOK TABLO KULLANMAK
Bu örnekte birden çok tablodan eleman alıyoruz. (Ama birden çok tabloyu tek UPDATE ile
güncelleyemeyiz) Burada dikkat çeken bir konu, WHERE yapısında birden çok olan koşulu AND ifadesi
ile birleştirebiliyor olabilmemizdir. Ayrıca DATEPART fonksiyonu da çok kullanışlıdır. Parantez
içindeki ilk ifade neyin çekileceği, ikinci ifade hangi sütundan çekileceğini belirtir. Datepart int değer
döndürür. (yıl-yy,yyyy. çeyrek-qq,q. ay-mm,m. yılın günü-dy,y. gün-dd,d. hafta-wk, ww. saat-Hh.
dakika-min. saniye-ss, milisaniye-Ms.)
Tip: FROM’un içinde SELECT’i kullandığınız zaman, SELECT için ayrı bir WHERE yapısı
kullanmamalısınız. Bütün WHERE koşulları tek bir WHERE yapısında FROM sözcüğü ile ilişkili olarak
kullanılmadır. Örneğin:
Not: UPDATE’de HAVING veya JOIN kullanmak için FROM (SELECT …) yapısına
ihtiyacınız vardır.
VERİYİ SİLMEK
SQL, veriyi silmek için 2 seçenek sunuyor: DELETE ve TRUNCATE TABLE. Herhangi bir geri
alma yolu yoktur. Sonuçlar kalıcıdır.
Tip: Veri silme işleminden önce veritabanınızın backup’ını almalısınız.
Silme işlemi için 2 yol var:
Bu iki ifade de tablodaki bütün verileri siler. Tablonun sütun yapısı sabit kalır. Böylece silme
işleminden sonra yeni veri rahatlıkla eklenebilir.
Peki, bu iki silme işleminin farkları nelerdir? Öncelikle şunu söyleyebiliriz ki: DELETE’i bütün
SQL veritabanları desteklerken TRUNCATE TABLE’ı hepsi desteklemez. (MsSQLServer bir çok
durumda TRUNCATE TABLE’ı desteklemesine rağmen bir veritabanından diğerine tablo kopyalarken
Data Transformation Services’ı kullanıyorsanız ana veritabanındaki tablonun verilerini silmek için
TRUNCATE TABLE’ı kullanmanıza izin vermez)
Bununla birlikte TRUNCATE TABLE yalnızca, tablonun bütün elemanlarını silinecekse
kullanılabilir. DELETE ise kayıtlarda seçime olanak sağlar.
WHERE yapısını diğer deyimlerde kullandığımız gibi kullanırız.
Bazı SQL veritabanları, onlardan birisi silindiğinde hepsi silinen ilişkili kayıtları tanımlamanıza
izin verir. Bu tür silme işlemine cascading delete adı verilir.
Bu SQL yapısı bütün SQL veritabanlarında kullanılır. Microsoft’un Transact SQL’i aşağıdaki yapıyla
JOIN’i de kullanıyor:
DELETE titleauthor FROM titleauthor INNER JOIN titles ON
titleauthor.title_id = titles.title_id WHERE titles.title_id LIKE ‘%novel%’
Microsoft, toplama fonksiyonları ve gruplandırmaya bu yapıda izin vermiyor. Yani toplama
fonksiyonu ya da gruplandırma kullanacaksanız JOIN kullanamazsınız.
Yanlış kayıtları silmemenin en iyi yolu her kayıdın kendine has bir kimlik no’sunun olmasıdır.
Diğer bir yol da transaction kullanarak veriyi silmeden önce ne olacağını görebilmektir.
Eğer DELETE’i bir SELECT koşulu ile kullanmayı planlıyorsanız her zaman SELECT INTO’yu
kullanın. SELECT INTO, tablo oluşturarak verilerin kopyasını oraya atar. Böylece hangi kayıtların
tablodan silindiğini görebilirsiniz.
TRANSACTION’LARI KULLANMAK
TRANSACTION size, kazayla silinen kayıt için bir kurtarma noktası sağlar. Bu kurtarma noktası
tam bir geri alma değildir. Çünkü transaction’a tamamlamasını söylediğiniz zaman yaptığınız işlemlerden
geri dönemezsiniz. Buna rağmen transaction ne olacağını size gösterir ve buna göre karar vermenize
olanak sağlar.
Transaction’lar ya tamamı başarılı ya da tamamı başarısız olması gereken SQL deyim gruplarıdır.
Grup, tek bir SQL deyimi kadar küçük olabilir. Transaction işleminde herhangi bir hata oluştuğunda
bütün emirler başarısız olur. Hiç hata olmazsa, hepsi başarılı olur. Transaction’ın bir dönüm noktası
vardır. Bu noktada hataları kontrol edebilir ve transaction’ı nasıl tamamlayacağınıza karar verebilirsiniz.
Transaction’ı uygulamak veya geri dönmek için başlangıç ve bitiş noktalarını işaretlemek gerekir.
Bu amaçla birkaç T-SQL deyimi vardır:
BEGIN: Başlangıç noktasını belirler.
COMMIT: Transaction’ı veritabanının geri dönülmeyen kalıcı parçası yapar.
ROLLBACK: Transaction’ın başından itibaren yapılanları unutmak istediğimizi belirtir.
SAVE: Kısmi geri almalar sağlamak için özel işaretçiyi belirtir.
BEGIN TRAN: Bir birimin başlangıcı olan işareti gösterir. Bazı sebeplerden dolayı
başaramadığımız veya transaction’ın uygulanmamasını istediğimizde bütün veritabanı işlemlerinin geri
döndürüleceği noktadır. Yapısı şöyledir:
BEGIN TRAN[SACTION] [transactionName | @transactionVariable]
COMMIT TRAN: Transaction’ın uygulanması, tamamlanmış transaction’ın sonlandırılmasıdır.
Bu, transaction’ı kalıcı yapar (sistem hatası olsa bile). Transaction’ın uyguladıklarını geri almanın tek
yolu, ilk transaction’ın fonksiyon olarak tersi olan başka bir transaction oluşturmaktır. Yapısı:
COMMIT TRAN[SACTION] [transactionName | @transactionVariable]
ROLLBACK TRAN: Rollback, transaction’ı başa döndürür. Begin’den itibaren yapılan işlemler
unutulur. Begin’e dönmenin tek istisnası savepointler kullanmaktır (Begin yerine bu saklı noktalara da
dönebilirsiniz). Yapısı:
ROLLBACK TRAN[SACTION] [transactionName | savepointName | @transactionVariable]
SAVE TRAN: Transaction’ı saklamak esasen bir işaret koymaktır. Bu noktadan sonraki işlemleri
geri almak isterseniz Rollback’te bu işaretin adını verebilirsiniz. Bir transaction’da birden çok işaret
koyabilirsiniz. Yapısı:
SAVE TRAN[SACTION] [savepointName | @savepointVariable]
Bir örnek incelersek:
Burada Transaction başlatılıyor, bir kayıt ekleniyor ve buraya işaret koyuyor. Sonra bir kayıt daha
ekliyor sonra ilk koyduğu işarete geri dönüyor. Ardından yine satır ekliyor ve ikinci bir işaret daha
koyuyor. Bir kayıt daha ekleyip ikinci işarete geri dönüyor. Son olarak bir kayıt daha ekliyor ve bu
transaction’ı saklıyor, yani veritabanının bir parçası haline getiriyor (değişiklikler kaydediliyor). Burada
ROLLBACK deyiminde, saklama noktasının ismi verilmemiş olsa veya begin’deki isim verilmiş olsaydı
en başa dönerdi.
TABLO OLUŞTURMAK
Daha önce tablo oluşturmak için SELECT INTO’yu kullanmıştık. Yalnız, bu metodun bazı
sınırlamaları vardı. İlki, tablonun bu sorgulama üzerine kurulması gerektiği, ikincisi de unique identifier’a
izin vermemesi idi.
CREATE TABLE’I KULLANMAK
Not: Mümkün oldukça char yerine varchar kullanın. Çünkü char’da, belrtilen sayıda karakter
girilme zorunluluğu vardır. Varchar’da ise o sayıya kadar istenilen sayıda karakter girilebilir.
Eğer kesinlikle Unicode’a ihtiyaç duymayacağınızdan eminseniz n ile başlayanlar (örneğin nchar)
yerine standart veri tipini (örneğin char) kullanın. Çünkü, Unicode’u depolamak için ek bir byte
kullanılmaktadır.
Mümkün oldukça küçük veri tiplerini seçmeye çalışın. Tiny ve small şekillerini yeterli olduğu
zamanlar kullanmaya çalışın. Çünkü bu veri tipleri daha az yer harcar.
Mümkün oldukça binary ve text veri tiplerinden kaçının. Eğer resim koleksiyonu gibi binary
large objects’in bir koleksiyonunu depolamanız gerekiyorsa, grafik dosyalarının adresini veritabanında,
dosyaları başka bir klasörde depolama yöntemini kullanın. Böylece veritabanınız daha az yer tutacak ve
sorgulamalarınız daha hızlı olacaktır. (Aynısı uzun text’ler için de düşünülmelidir)
Ayrıca, veri tiplerini belirlerken varsayılan değer ve nullability’yi de tablodaki sütunlar için
belirleyebiliriz. Yapı şöyledir:
İlk örnekte varsayılan değeri 0 olan bir sütun ile tablo oluşturduk. İkincisinde sütunun değerinin
boş olmasına olanak sağladık (NULL yazarsak boş olabilir, aksi halde 6 karakterlik string girmeliyiz).
Üçüncüsünde ise varsayılan olarak ‘ABCDEF’ yi aldık ve isteğe bağlı olarak (NULL yazarsak boş)
kendimizin de değer girebileceği şekilde ayarladık.
Not: Eğer veritabanınız, dosya isimlerini veya diskte veri içeren dosyaları temsil eden dosya
gruplarını destekliyorsa ON kelimesini kullanarak tablo oluşturmak için hangi dosyaların kullanılacağını
belirleyebiliriz.
Şimdiye kadar gördüklerimize özet olması açısından aşağıdaki örneğe bakabiliriz:
CREATE TABLE publishers (pub_id char(4) NOT NULL, pub_name varchar(40)
NULL, city varchar(20) NULL, state char(2) NULL, country varchar(30) NULL
DEFAULT(‘TURKIYE’))
Burada dikkat etmeniz gereken nokta, NULL gibi NOT NULL ifadesinin de kullanılabiliyor
olmasıdır (Boş olmaması gereken ifadelerde)
TABLOLAR ARASI ANAHTARLAR
Tablolar genellikle anahtar değerler içerirler. Anahtar değerler her bir kayıt için kendine hastır.
Anahtar, yalnızca bir sütun olmak zorunda değildir. Bir anahtar oluşturmak için birkaç sütunu
birleştirebilirsiniz. (Bunlara multipart key denir) Key’ler 2 genel tipte olur: primary ve foreign.
Primary key’ler SQL veritabanlarının key sistemlerinin temeli olduğu için bu konuyla başlayalım:
Her tablo, kayıtları birbirinden ayıran tek bir sütun veya sütunların birleşimi şeklinde olan primary
key’lere sahip olmalıdır.
Tip: SQL dökümantasyonları birkaç key türünü tanımlar: Candidate key, bütün kayıtları
birbirinden ayıran bir sütundur. Surragate key, asıl manası olmayan bir key’dir (Arabanın seri numarası
gibi). Intelligent key, bazı gerçek anlamları olan bir key’dir (coğrafik bir yeri belirtmek için key’de
kullanılan enlem ve boylam gibi). Super key ise bir çok sütun içeren bir key’dir.
Bir sütundan oluşan primary key oluşturmak için şu yapıyı kullanırız:
Bir foreign key, diğer bir tabloda ortaya çıkan bir primary key örneğidir. (Örneğin SQL Server’ın
pubs veritabanında titleauthor tablosu foreign key’ler içerir (au_id ve title_id)) Başka tablodaki primary
key’lere yönlendirmenin sebebi, tabloları birleştirmek için basit anlamlar kazandırmaktır. (Biz şimdiye
kadar titleauthor’un bize bir yazarın bütün başlıklarını seçmemize olanak tanıdığını gördük) Foreign key’i
temsil eden bir sütun oluşturacağımız zaman aşağıdaki yapıyı kullanırız:
Tip: Foreign key’i oluşturmadan önce primary key’in mevcut olup olmadığından emin olun.
INDEX’LER EKLEMEK
Veritabanınızdaki sorguların hızını artırmak için en uygun yol, verinizin fihristesini (index)
oluşturmanızdır. Bir index, değerleri bir sütunda hızlı şekilde bakma yoludur. Index’ler size değerler
listesinde bir değere işaret koymanıza izin verir ve ondan sonra o değeri bir alan veya bir dizi alanla çift
çift tertip eder. Böylece hızlı arama algoritmaları çalıştırılır.
Key değerinde index oluşturmak kolaydır. Bir çok veritabanı, tablodan primary key’i otomatik
olarak index’ler. Primary key’ler her kayıtı kendine has şekilde belirlediği için JOIN’de kullanmak için
iyi bir düşüncedir. JOIN’ler hızlı olması gerekir ve primary key’leri index’lemek, başka kullanıcı veya
yöneticinin müdahalesi olmadan JOIN’in hızını artıran emin bir optimizasyon stratejisidir. Bir çok SQL
veritabanında constraintleri oluşturduğunuzda index oluşturabilirsiniz. Ayrıca, CREATE INDEX’i de
kullanabilirsiniz, index oluşturmak için.
Index’ler üç tipte olabilir: Bir unique index, iki kayıtın aynı index değerini almadığı index’dir.
Böylece her satır index’te ayrı ayrı belirlenmiştir. Bir clustered index, değerlerin sıralandığı bir index’tir.
Bu sıralama yapısı her bir kayıtı sıralı şekilde depolar. Bir nonclustered index ise kayıtları index’ler fakat
kayıtların kayıt olma sırasını değiştirmez. (Ayrıca kendine has olmalı)
Key oluşturduğunuzda index oluşturmak için aşağıdaki yapıyı kullanırız:
Burada index’in türünü belirten kelimeler INDEX kelimesinden önce kullanılıyor. INDEX’ten
sonra ise index’in ismini yazıyorsunuz. ON’dan da sonra index’in yapılacağı tablo(sütun)’u
belirtiyorsunuz.
Tip: CREATE INDEX yazarsak (tipini belirtmeden) sade nonclustered olarak alınır.
CONSTRAINT’LERİ EKLEMEK
Constraint’ler primary key, foreign key, referans veya geçerli bir veri kuralı olabilir. Key
değiştiğinde neler olduğunu da belirtebilirler.
Burada foreign key bir multipart key’dir ve multipart primary key’i referanslamaktadır. Şimdi de
multipart key’in nasıl oluşturulduğunu inceleyelim:
Dikkate alınması gereken husus şu ki: constraint’in tanımlanması, içerilen bütün sütunların
oluşturulmasını takip etmesi gerekir. Bundan dolayı da karışıklıklar olabildiğinden multipart key’lerin
oluşturulmasının en yaygın yolu ALTER TABLE’ı kullanmaktır.
Bunlara ek olarak, veritabanında key olmayan sütunda eşsiz (unique)’liği zorlayan bir
constraint’le indeks oluşturabilirsiniz. Örneğin:
Bu SQL ifadesi, unique (kendine has) olması gereken stor_name ve city sütunlarında unique
index oluşturur. Bu constraint’ten dolayı aynı şehirde aynı isimle iki mağazanız olamaz.
Adından da anlaşıldığı gibi ALTER TABLE, var olan bir tabloyu değiştirir. Temel yapısı şöyledir:
ALTER TABLE MyTable ADD MyColumn VARCHAR(20) NULL
Bu örnek var olan tabloya MyColumn adında bir sütun ekler. Şimdi de bir tabloya 2 constraint
ekleyen örneği inceleyelim:
Dikkat edilmesi gereken bir husus da şudur ki: ADD bir defa yazılır ve her birinin arasına virgül
konur.
TABLOYU SİLMEK
VERİTABANI OLUŞTURMAK
Veritabanı oluşturmak için aşağıdaki bilgilere ihtiyacınız vardır:
Veritabanı için kullanmak istediğiniz isim,
Kullanacağınız en az ve en fazla veritabanı büyüklüğü,
Kullanacağınız en az ve en fazla kayıt (transaction) log’u büyüklüğü,
Kullanacağınız dosya büyüme faktörü,
Veritabanı ve transaction log dosyalarının tutulacağı yer (adres).
Şimdi bunları teker teker inceleyelim:
Veritabanı ismi oldukça açıktır, herhalde. Veritabanına erişileceği zaman kullanılır.
En küçük veritabanı büyüklüğü, veritabanı oluşturulduktan sonra boş bir veritabanının dosya
depolama büyüklüğüdür. Biz bu veri büyüklüğü ile başlarız. Genelde 10 MB uygun bir çözümdür.
Bir diğer madde, transaction log’un büyüklüğüdür. Çoğu SQL veritabanları her veri değiştirme
işlemlerini transaction olarak var sayar. Eğer bir ekleme yapmaya çalışır ve gerçekten de yanlış olursa
veritabanı kendi kendine başlangıç durumuna geri döndürür. Bu kapalı transaction size kontrol imkanı
vermez. Her bir transaction backup amacıyla log’lanmıştır ve bu loga transaction log adı verilir. Bu
dosyalar veri dosyalarından ayrı tutulur. Bu yüzden birini kaybettiğinizde diğerini kaybetmemiş
oluyorsunuz. Eğer verinizi kaybederseniz en son backup’a geri dönüp, bütün geçmiş transaction’ları
uygulayarak hatanın oluştuğu noktaya kadar gelebilirsiniz.
Tip: Transaction log’ları ayrı sürücüde tutabilirsiniz.
Eğer transaction log’lar kapasiteye ulaşıp aşamazsa hata mesajı alırsınız ve veritabanı
değişikliklerini uygulamaya devam edemeyeceğinizden dolayı transaction log’lar için geniş bir kapasite
isterseniz 5MB genelde başlangıç için uygun bir büyüklüktür.
Maksimum veritabanı ve transaction log büyüklüğü boşluğa göredir. Bu büyüklükleri nasıl
tutacağınız veritabanınıza bağlıdır. Bazı SQL veritabanları alanın dışına çıktığınızda ALTER
DATABASE iledeğiştirmenizi gerektirir. Diğer veritabanları veritabanının işaret edilen depolama
ünitesinin alanının sonuna kadar büyümenize izin verir. Tavsiye edilen ise, eğer veritabanınız limitsiz
büyüklüğü destekliyorsa limitsiz kullanmanız, desteklemiyorsa işletim sistemi ve depolama ünitesinin
izin verdiği en büyük değeri vermenizdir.
Büyüme (growth) faktörü veritabanına bağlı olarak değişik yollarla ifade edilebilir (Megabyte ve
percent). Genellikle, megabyte’ı kullanmak zorunda iseniz büyüme faktörü olarak veritabanının ilk
büyüklüğünü kullanmak uygundur. Burada istenildiğinde alan büyüyebiliyor. (Megabyte’da lineer bir
büyüme var) Ama önemli olan nokta her alan ayrımı için geçen zaman faktörüdür. Eğer percent’a göre
büyümeyi seçerseniz üstel bir büyüme uygulamış olursunuz. Bir veritabanı örneği inceleyelim:
NORMALLEŞTİRME
Veritabanıyla ilk defa uğraşanlar için tabloların niçin ve nasıl oluşturulduğu konusu ilginçtir.
OLTP (Online Transaction Processing), en yaygın olarak kullanılan veritabanı tipinden uzaktır.
Eğer veritabanıyla çalışıyorsanız, özel olarak aksini söylemedikçe başka şeyler OLTP’yi kaplar. OLTP
veritabanları isminden de anlaşıldığı gibi transaction işlemiyle tasarlanmıştır. OLTP veritabanları veri
bütünlüğü ve performans nedenlerinden dolayı bütün fazlalıkları elimine etmeyi dener.
OLAP (Online Analytical Processing) veritabanları ise tipik olarak o düşünceyle zıt kutuptadır.
OLAP veritabanları analizleme –raporlama- gibi şeyler için nesneleri değişik bir yönüyle düşünmeye
çalışırlar (az ya da hiç yapılmayan veri güncelleme, çok miktarda veri okuma gibi). OLAP’la biz asıl
olarak sadece veri okuruz. Bu yüzden genellikle fazlalıklar bize zarar vermez (yardım edebilir).
En yaygın veritabanı türü OLTP’dir. Bunun gibi, normalleştirilmiş veritabanı katmanlarının çoğu
3. normal form diye adlandırılan katmana sahiptir. Bu yüzden normal formun ne olduğu konusunu
inceleyelim.
Veritabanındaki merkezi nesne olan tablonun ne olduğuna kısaca bir göz atarsak:
Bir tablo, benzer genel nitelikteki veri örneklerinin bir koleksiyonudur. Bu veri örnekleri, verinin
satır ve sütunlarına organize edilir. Bir tablo, gerçek hayattaki verileri veya varlığı betimlemelidir ve
diğer tablolardaki verilerle ilişkilere sahip olmalıdır. Çeşitli tablolar ve ilişkilerin çizilmesi genellikle bir
‘varlık ilişki diyagramı’ (ER Diagram) olarak anılır. (ER diagram kısaca ERD olarak kısaltılabilir)
Çeşitli ilişkilerle bir veya daha çok tabloya bağlanılmasıyla, her iki tablodaki verilerin
kombinasyonlarından kaynaklanan ihtiyacın giderilmesi için geçici tablolar oluşturulabilir.
Normalleştirme, OLTP veritabanı tasarımının köşe taşı modelidir. Normalleştirme ilk olarak
ilişkili veritabanları kavramıyla ortaya çıkmıştır. Her iki kavram da E. F. Codd’un bir çalışmasıyla
gelmiştir. Codd, “metotsal olmayan işlemleri kullanarak işlenebilen bir dizi sıralanmamış tablodan oluşan
bir veritabanı” olan 4. düşünceyi ortaya attı. Birkaç şey bu düşünce için anahtardır:
Sıra önemli değildir.
Metotsal olmayan bir yolla tablolar birbirleriyle ilişkili olmalıdır.
Temel tabloları birbirleriyle ilişkilendirirken, yeni ihtiyaç durumuna gelen sanal tabloyu
oluşturabilirsiniz.
Normalleştirme, veritabanı ilişki tasarımının doğal yan ürünüdür. 6 adet normal form vardır.
(Genelde sadece 3 tane olduğu söylenir)
Normalleştirme kavramı, büyük ölçüde primary key ve ona bağlı olan sütunların ne olduğunun
belirtilmesiyle çevrelenen konuyla bağımlıdır. Normalleştirmede sık sık duyabileceğiniz bir deyim :
“The key, the whole key, and nothing but the key”
(Key, tam key, ve hiçbir şey fakat key) ‘dir. Bu deyim, 3.normal form hariç, normalleştirmenin ne
olduğunun çok kısa bir özetidir. Eğer, bütün sütunlarınız sadece tam key’e bağımlı ise siz 3. normal
formdasınızdır.
Verinizi 1. normal forma getirmeye çalışmadan önce birkaç şeyi bilmeniz gerekir:
Tablo, bir varlığı (entity) belirtmelidir.
Bütün satırlar kendine has olmalı ve tabloda bir primary key bulunmalıdır.
Sütun ve satır sırası önemli olmamalıdır.
Bir tablonun bir varlık belirtmesi gerekir. Bir varlık, hakkında veri kaydetmek istediğiniz kişi, yer
veya herhangi bir şeydir. Bir varlıkta değişik şeyleri toplama cazibesinden kaçınmanız gerekir. (müşteri
ve siparişler gibi)
Ardından, sahip olmak için doğru varlıkları belirtmelisiniz. Bunların bazıları oldukça aşikar
olacaktır. Varlıkların bir çoğu meydana çıkarılmış ve normalleştirme işlemi boyunca arıtılmış olacaktır.
Eğer nesneye dayalı programlamaya aşina iseniz, çoğu mantıksal yüksek seviye varlıkları nesne modeli
içindeki nesnelere benzetebilirsiniz.
Çok basit bir örnek ele alalım. (satışlar örneği) Bu örneğe başlarken değişik çeşitlerin
mümkünlüğünden veya hangi sütunlara sahip olacağımızdan endişe duymayız. Fakat, sistemimizin temel
varlıklarını belirtmekten endişe duyabiliriz.
İlk olarak en temel işlemi düşünelim. Yapmak istediğimiz şey, işlem boyunca tutmak
isteyeceğimiz veri için her bir atomik üniteye bir varlık oluşturmaktır.
Eğer varlığınızın nasıl olmasını istediğinize dair düşünceleriniz varsa, bir sonraki gideceğiniz
adım, sütunlara başlama ve bir primary key’i hesaplamaktır.
Sütun listenizi incelerseniz key adayları ortaya çıkar. Key adayları listesi, varlığınız içindeki her
bir satırı kendine has olarak belirtecek potansiyele sahip sütunları içermelidir. (Bazı durumlarda hiçbir
key adayı bulamıyabilirsiniz ve bir tane bulma ihtiyacı hissedersiniz)
İçinde OrderNo, CustomerNo, CustomerName, CustomerAddress, CustomerCity, CustomerState,
CustomerZip, OrderDate, ItemsOrdered, Total sütunları bulunan bir tablomuz var.
Mantıksal olarak sipariş numarası orders tablosundaki bütün kayıtlar için ayrı olmalıdır. Bu
yüzden OrderNo’yu primary key olarak seçebiliriz.
Böylece temel bir varlık oluşturulmuş oldu. Şimdi normalleşme işlemlerini inceleyelim:
1. NORMAL FORM
Birinci Normal Form (1NF)’un tamamı, tekrarlayan veri gruplarının elimine edilmesi ve
atomic’liğin (veri kendini içerir ve bağımsızdır) teminat altına alınmasından ibarettir. Yüksek seviyede
primary key oluşturulur, ardından, tekrarlayan veri gruplarının yeni tablolara taşınması ve yeni tablolar
için primary key’lerin oluşturulması şeklinde devam eder. (Ayrıca biz, her bir veriyi ayrı satırlara
birleştiren her hangi bir sütundan kaçınırız.)
Daha geleneksel düz dosya tasarımlarında veri tekrarlanması olağandır. (bir sütunda birden çok
bilgi gibi). Bu, şu yönlerleden şüpheliydi:
O zamanlar disk depolama son derece pahalıydı. Çok defa veriyi saklamak işe yaramayan
alan anlamına gelir. Veri saklama şimdilerde daha ucuzladı ve eskisi gibi büyük sorun
olmaktan çıktı.
Tekrarlayan veri, daha çok veri hareketi ve daha büyük I/O hesabı anlamına gelir. Bu da veri
yolundan veya ağdan geniş veri bloğunun geçmesi gerekmesi gibi performansı düşürür. Bu,
bugünün hızlı teknolojisiyle bile performanstaki esas negatif etkiyi yapar.
Tekrarlanmış olması gereken satırlar arasındaki veri, ekseriyetle, çelişkili gibi görünen
verinin herhangi bir şeyini ve veri bütünlüğünün genel ihtiyacını karşılamayı kabul etmez.
Birleştirilmiş veri içeren bir sütundan bilgi sorgulamak isterseniz ilk olarak o sütundaki
veriyi çözümlemelisinizdir. (Bu da hız kaybı demektir)
Order Order Customer Customer Customer ItemsOrdered
No Date No Name Address
100 1/1/1999 54545 ACME Co 1234 1st 1A4536, Flange,
St. 7lbs, $75; 4-
OR2400, Injector, .
5lbs, $108; 4-
OR2403, Injector, .
5lbs, $116; 1-4I5436,
Head, 63lbs, $750
101 1/1/1999 12000 Sneed 555 Main 1-3X9567, Pump,
Corp. Ave. 5lbs, $62.50
102 1/1/1999 66651 ZZZ Co. 4242 SW 7-8G9200; Fan, 3lbs,
2nd $84; 1-8G5437, Fan,
3lbs, $15; 1-3H6250,
Control, 5lbs, $32
103 1/2/1999 54545 ACME Co 1234 1st 40-8G9200, Fan,
St. 3lbs, $480; 1-
2P5523, Housing,
1lbs, $165; 1-
3X9567, Pump, 5lbs,
$42
Customer No Customer Name Customer Address
54545 ACME Co 1234 1st St.
12000 Sneed Corp. 555 Main Ave.
66651 ZZZ Co. 4242 SW 2nd
Yeni ve eski tabloların her ikisinde de dikkat etmeniz gereken bir-iki husus var:
Her bir satırın kendine has olduğundan emin olmanız için yeni tabloda bir primary key’iniz
olmalıdır. Customers tablosu için 2 primar key adayı vardır: CustomerNo ve CustomerName.
CustomerNo, gerçekten bu amaca hizmet etmek için oluşturulmuştur ve mantıksal tercih
olarak gözükür. CustomerName ise aynı isimde birden çok müşteri olabileceğinden
adaylıktan düşürülür.
Orders tablosundan verileri çıkartmanıza rağmen yeni Customers tablosundaki verilerle
bağını devam ettirmelisiniz. Aksi halde, bir önceki siparişi kimin verdiğini
ilişkilendiremezsiniz. (Orders tablosunda CustomerNo’nun foreign key gözükmesinden)
Örneğin ACME CO’nun bilgilerini elimine edebiliyordunuz. Bu, tekrarlayan gruplarda (bir
defa depolamak için) veri hareketinin amacının bir parçasıdır. Bu size daha çok yer depolar
ve değerlerin çakışmasını önler.
Siz sadece tekrarlayan veri gruplarını taşıdınız. Dikkat ederseniz aynı sipariş tarihi çok defa
tekrarlanmasına rağmen gruplandırılmayacaktır. (Tablonun dışında ilgisi bulunmayan veri
kısmı görecelidir)
Şimdi, 1. Normal Formu bozan ikinci ihlali –atomicity- kaldırabilirsiniz. ItemsOrdered sütununda
birkaç değişik veri vardır. Part Number, Weight ve Price, her biri ayrı tutulduğunda atomic parçalardır,
fakat biçimsiz bir grupta toplanmışlardır. Her birini parçalara ayırmalısınız.
Order Order Customer Part No Description Qty Unit Total Wt
No Date No Price Price
100 1/1/1999 54545 1A4536 Flange 5 15 75 6
100 1/1/199 54545 OR2400 Injector 4 27 108 .5
100 1/1/1999 54545 OR2403 Injector 4 29 116 .5
100 1/1/1999 54545 4I5436 Head 1 750 750 63
101 1/1/1999 12000 3X9567 Pump 1 62.50 62.50 5
102 1/1/1999 66651 8G9200 Fan 7 12 84 3
102 1/1/1999 66651 8G5437 Fan 1 15 15 3
102 1/1/1999 66651 3H6250 Control 1 32 32 5
103 1/2/1999 54545 8G9200 Fan 40 12 480 3
103 1/2/1999 54545 2P5523 Housing 1 165 165 1
103 1/2/1999 54545 3X9567 Pump 1 42 42 5
Burada ortaya çıkan problem ise her bir bilgiyi parçalara ayırdığınızda artık primary key’in her
satır için farklı olamadığıdır. Bu yüzden, tabloya line item numarası ekleyerek satırları kendine özgü
biçimde belirtebilirsiniz. (OrderNo ile LineItem ikisi beraber primary key oluşturuyorlar)
Order Line Order Customer Part No Description Qty Unit Total Wt
No Item Date No Price Price
100 1 1/1/1999 54545 1A4536 Flange 5 15 75 6
100 2 1/1/1999 54545 OR2400 Injector 4 27 108 .5
100 3 1/1/1999 54545 OR2403 Injector 4 29 116 .5
100 4 1/1/1999 54545 4I5436 Head 1 750 750 63
101 1 1/1/1999 12000 3X9567 Pump 1 62.50 62.50 5
102 1 1/1/1999 66651 8G9200 Fan 7 12 84 3
102 2 1/1/1999 66651 8G5437 Fan 1 15 15 3
102 3 1/1/1999 66651 3H6250 Control 1 32 32 5
103 1 1/2/1999 54545 8G9200 Fan 40 12 480 3
103 2 1/2/1999 54545 2P5523 Housing 1 165 165 1
103 3 1/2/1999 54545 3X9567 Pump 1 42 42 5
Bundan sonra, geri kalan sütunları başlık tablosu olarak hizmet edecek yeni bir tabloya
aktarmalısınız.
Order No Order Date Customer No
100 1/1/1999 54545
101 1/1/1999 12000
102 1/1/1999 66651
103 1/2/1999 54545
OPERATÖRLERİ KULLANMAK
İLİŞKİSEL ve BOOLEAN OPERATÖRLER
İlişkisel Operatörler daha yaygın olarak matematiksel ilişkiler olarak bilinir. Bu operatörler
matematikteki anlamına benzer anlam taşırlar. (= eşittir, > büyüktür, < küçüktür, >= büyük eşittir, <=
küçük eşittir, <> eşit değildir)
Bu operatörler sayılarla kullanılabileceği gibi diğer değerlerle de kullanılabilir. Tam anlamları,
veritabanınızın kullandığı kodun türüne (ASCII veya EBCDIC) bağlıdır. Kodda her bir karakterin sayısal
değeri vardır (ASCII’de ‘D’ 68’tir). İlişkisel operatörleri karakterlerle kullandığınızda aslında onların kod
değerlerini karşılaştırmış olursunuz.
Bu operatörleri kullanmak çok basittir (WHERE contract=1 gibi)
Boolean operatörler ise mantıktaki anlamlarıyla kullanılmaktadır (True AND False = False, True
OR False = True, NOT True = False)
Boolean operatörler kullanılarak WHERE’de birden çok şart koşulabilir (SELECT * FROM
address WHERE city=’Louisvelle’ AND NOT state=’KY’ gibi)
EXISTS
Bir grup sütunun veritabanınızda var olup olmadığını öğrenmek istiyorsanız EXISTS anahtar
kelimesini kullanabilirsiniz. Örneğin SQL Server’ın Pubs veritabanında yazısı olan yazarları bulmak
istiyorsanız şu ifadeyi kullanabilirsiniz:
SELECT * FROM authors WHERE EXISTS (SELECT * FROM titles INNER JOIN
titleauthor ON titles.title_ID = titleauthor.title_ID WHERE titleauthor.au_ID
= authors.au_ID)
EXISTS, basit şekliyle sorgu içinde sorgu diye ifade edebileceğimiz alt sorgulamayı kullanmayı
gerektirir. Alt sorgular EXISTS kelimesinden sonra parantezler içinde yazılır. Ana sorguyu alt sorguya
bağlamak için ana sorgudaki bazı değerlerin alt sorgudaki WHERE yapısında gözükmesi gerekir. Eğer iki
sorgulama arasında şartlı ilişki (WHERE titleauthor.au_ID = authors.au_ID) yoksa, alt sorgulama (her
zaman) bütün satırları döndürür.
Burada bütün yazarlar döner. Alt sorgu her zaman ana sorguda verilen yazarların her biri için
sonuç döndürür. Çünkü ana sorgudaki yürürlükte olmayan yazarların bir listesini döndürür. Sonuç olarak
ana sorguda verilen her yazar için alt sorguda satırlar olacaktır
EXISTS alt sorgusu, sonuç kümesine satırları seçmek için temel olarak bir grup satır kullanır.
Diğer operatörler benzer biçimdeki diğer satırları seçmek için satır gruplarıyla çalışmaya izin verir. Bu
seçeneklerin her biriyle hatırlamanız gerekir ki bir satırlar grubu buluyorsunuz ve diğer bir satır grubunu
seçmek için birkaç şekilde o satır grubunda çalışıyorsunuz. Bu araçlar sorguları uygun şekilde sınırlamak
için çok kullanışlı olabilmektedir.
BETWEEN
Between, kayıt kümesine satırları döndürmek için kullanılacak bir sütun değerleri grubu oluşturmanıza
izin verir. Temel yapısı şöyledir:
SELECT title, ytd_sales FROM titles WHERE ytd_sales BETWEEN 1000 and
7000
Between, sütun değeri verilen aralıktaki satırları seçmenizi sağlar. Buradaki and, Boolean
operatör değildir.
IN, ANY, ALL, SOME
IN sözcüğü, kayıt kümesi üretimini başka bir yoldan kontrol etmek için alt sorgu kullanmanıza
izin verir. IN, değerler listesinden bir sütun değeri arar. Yapı şöyledir:
SELECT au_lname, au_fname FROM authors WHERE au_id IN (SELECT au_id FROM
title_author WHERE royaltypes = 10)
Bu örnekte WHERE yapısı, au_id’nin, alt sorguyla oluşturulan listede bulunması gerektiğini
belirtiyor.
Tip: IN, alt sorgu kullanmayı gerektirmez. Parantez içinde virgüllerle ayrılmış bir değerler
kümesi de kullanabilirsiniz.
ALL, ana sorgudaki satırın, belirtilen yolla alt sorgudaki bütün sonuçlarla eşleşmesini gerektirir.
Aşağıdaki örneği inceleyelim:
SELECT au_lname, city FROM authors WHERE city <> ALL (SELECT city FROM
publishers)
Ana sorguda authors tablosunu çekiyoruz. Alt sorguda da publishers tablosunu çekiyoruz.
WHERE ifadesi, ana sorgudaki city sütununa karşı alt sorgudaki city sütununu kontrol eder. İki sütunun
eşit olmaması gerekir (<> kullanıldığı için). Böylece, publishers tablosunda bulunmayan şehirlerin olduğu
authors kayıtlarının au_lname ve city sütunları döndürülmüş oluyor.
Eğer bunun tam tersini (publishers tablosunda bulunan şehirlerin olduğu authors kayıtlarını
çekmek) isterseniz ANY’yi kullanabilirsiniz.
SELECT au_lname, city FROM authors WHERE city = ANY (SELECT city FROM
publishers)
Not: ANY ile SOME operatörleri aynı fonksiyonu icra ederler. (Aynı şeyi ifade ederler)
LIKE ve ISNULL
LIKE anahtar sözcüğü size, sütun için belirttiğiniz örüntüdeki satırları seçmenizi sağlar. Basit bir örnek
verirsek:
SELECT * FROM authors WHERE phone LIKE ‘502%’
Burada authors tablosunun telefon numarasının ilk 3 rakamı 502 olan ve ondan sonra herhangi bir
rakam gelen kayıtlar çekilir.
Bu konuyu UPDATE konusu içinde işlediğimiz için bu kadarla yetineceğiz.
SQL size, veritabanından veri çekildiğinde uygun olman NULL karakterleri kontrol etmeniz için bir
yöntem sağlar. ISNULL fonksiyonu NULL karakterleri kontrol eder ve sütun değeri NULL olduğunda
belirtilen değeri döndürür. Yapı şöyledir:
SELECT ISNULL(price, $0.00) FROM titles
Bu örnekte titles tablosundaki fiyat bilgilerini çekiyoruz. Ve gösterirken eğer bir NULL değere
rastlarsak onu $0.00 olarak gösteriyoruz. (NULL değilse kendi değeri)
ISNULL fonksiyonu aşağıdaki örnekte verilen IS NULL (ve IS NOT NULL) ile karıştırılmamalıdır.
SELECT price FROM titles WHERE price IS NOT NULL
FONKSİYONLARI KULLANMAK
SQL, bir dil olarak diğer programlama dilleri gibi fonksiyonları destekler. Fonksiyonlar, yaygın
işlemleri icra etmek için kullanışlı rutinlerdir. Önceden belirtilmişlerdir. Temel olarak, tekrar
kullanmamız için başka birileri tarafından yazılmış kayıtlı prosedürlerdir.
Burada programcıların sık sık kullanacağı fonksiyonları inceleyeceğiz (her fonksiyon sonunda
birer örnek vereceğiz):
AGGREGATE FONKSİYONLAR
Aggregating, veriyi özetlemenin bir yoludur. Aggregate fonksiyonların kullanım amacı sonuçları
inceleyenlerin, gidişi hızlı bir şekilde anlamasını sağlamaktır. Bu fonksiyonları aritmetik operatörlerle
beraber kullanıp birden çok sütunun sonucunu da özetleyebilirsiniz. Bu fonksiyonlarda genel yapı
Agg_Fonk_İsmi (sql_deyimi) şeklindedir. Fonksiyonlara kısaca bir göz atalım:
AVG: AVG veya GROUP BY ile belirtilmiş bir gruptaki değerlerin ortalamasını döndürür.
sql_deyimi tipik olarak bir sütun ismi olabileceği gibi daha karışık deyimler de olabilir. ALL veya
DISTINCT deyimi değiştirmek için kullanılabilir. Döndürülen değer sql_deyimi veri tipiyle aynıdır.
SELECT AVG (DISTINCT price) FROM titles
COUNT: COUNT veya GROUP BY ile belirtilmiş gruptaki eleman sayısını döndürür. Döndürülen değer
COUNT’u ifade eden bir integer’dır.
SELECT COUNT (city) FROM authors
sql_deyiminde sütun isminden başka aritmetik ifadeler de kullanılabilir. ALL veya DISTINCT
kullanılabilir. DISTINCT’in fonksiyonun genel durumunda bir anlamı yoktur. Verilen ifade için sadece
bir tane max değer vardır. ALL, deyimin bütün değerlerine fonksiyonun uygulanmasını zorlar. Bu,
işlemin varsayılan biçimidir.
SELECT MAX (ytd_sales) FROM titles
MIN: Deyimle ilişkilendirilmiş olan en küçük değeri döndürür. Kullanılan parametre MAX ile aynı
özelliğe sahiptir.
SELECT MIN (ytd_sales) FROM titles
sql_deyimi sütun ismi olabileceği gibi diğer tipteki deyimler de olabilir. sql_deyimi sayısal bir veriyi
göstermelidir ve NULL değerler atılmıştır. DISTINCT birden çok kullanılan değerleri sadece bir defa ele
almak için kullanılabilir.
SELECT SUM (advance) FROM titles
Sql_deyimi tipik olarak bir sütun ismidir ve sayısal bir veri tipini göstermek zorundadır. Aggregate
fonksiyonlar deyimde kullanılamazlar. NULL değerler atılmıştır.
SELECT STDEV (ytd_sales) FROM titles
DATEDIFF: Belirtilen iki tarih arasındaki tarih ünitelerinin sayısını döndürür. Yapısı şu
şekildedir: DATEDIFF (Part_of_date_code, sql_startingdate, sql_endingdate)
DATENAME: Belirtilen tarih kısmını karakter stringi olarak döndürür. Yapısı şöyledir:
DATENAME (Part_of_date_code, sql_date)
DAY: Tarih ifadesi ile ilişkilendirilmiş günü integer olarak döndürür. Yapı şu şekildedir: DAY (sql_date)
DAY (‘12/27/1954’)
ABS (5+12)
ACOS: Cosinüs’ü, bildirilen argüman olan açının raydan değerini döndürür. Yapı: ACOS
(sql_float_expression) şeklindedir. Sql_float_expression, kayan noktalı, geçerli bir sayı ifadesidir.
ACOS (-1.00)
ASIN: Sinüs’ü, bildirilen argüman olan açının raydan değerini döndürür. Yapı: ASIN
(sql_float_expression) şeklindedir.
ATAN: Tanjant’ı, bildirilen argüman olan açının raydan değerini döndürür. Yapı: ATAN
(sql_float_expression) şeklindedir.
ATN2: Tanjantı, argüman olarak verilen 2 değerin arasındaki açının raydan değerini döndürür. Yapı
şöyledir: ATN2 (sql_float_expression_low, sql_float_expression_high)
ATN2 (35.1, 128.01)
CEILING: Argüman olarak bildirilen sayısal değerden yüksek en küçük integer değeri döndürür. Yapı:
CEILING (sql_numeric_expression)
CEILING (10.95)
COS: Argüman olarak verilen açının cosinüs’ünü döndürür. Argüman raydan cinsinden verilmiş
olmalıdır. Yapı: COS (sql_float_expression)
COT: Girilen açının cotanjant’ını döndürür.
DEGREES: Argüman olarak raydan cinsinden verilmiş açının derece cinsinden değerini
döndürür. Yapı: DEGREES (sql_numeric_expression)
EXP: Verilen ifadeyi e tabanına üs alarak sonucu döndürür. Yapı: EXP (sql_float_expression)
FLOOR: Argüman olarak verilen sayısal ifadeye eşit veya ondan küçük en büyük integer değeri
döndürür. Yapı: FLOOR (sql_numeric_expression)
LOG: Girilen sayının doğal logaritmasını alır. Yapı: LOG (sql_floating_point_expression)
LOG10: Verilen ifadenin 10 tabanındaki logaritmasını alır. Yapı: LOG10
(sql_floating_point_expression) şeklindedir.
PI: PI değerini döndürür. Yapı PI () şeklindedir.
POWER: İlk argümana ikinci argümanı üs olarak alarak sonucu döndürür. Yapı: POWER
(sql_numeric_expression, power)
RADIANS: Argüman olarak sağlanan, derece cinsinden açıyı raydan cinsine çevirir. Yapı:
RADIANS (sql_numeric_expression)
RAND: 0 ile 1 arasında rastgele kayan noktalı sayı döndürür. Yapı: RAND (sql_integer_seed)
şeklindedir. Sql_integer_seed, rastgele sayı algoritmasını başlatmak için integer türünde bir sayıdır.
(RAND (5) gibi)
ROUND: İlk argüman olarak verilen sayıyı belirtilen haneden sonra yuvarlar veya atar. Yapı:
ROUND (sql_number_to_round, sql_precision [, sql_truncate]) şeklindedir. Sql_number_to_round, bit
veri tipinde olmayan herhangi bir sayı ifadesidir. Sql_precision, virgülden sonra kaç hanenin
yuvarlanacağını bildiren integer değerdir. Örneğin ROUND(745.045, 2) ifadesi 745.05 döndürür. Eğer
sql_precision negatifse virgülden öncesini yuvarlar. Örneğin ROUND (745.045, -2), 700 sonucunu
döndürür. Sql_truncate de sayıyı yuvarlamadan kesmeye yarar.
SIGN: Sayı pozitifse 1, diğer durumlarda -1 döndürür. Yapı: SIGN (sql_numeric_expression)
şeklindedir.
SIN: Raydan cinsinden verilmiş açının sinüsünü döndürür. Yapı: SIN
(sql_floating_point_expression) şeklindedir.
SQUARE: Girilen argümanın karesini alır (kendisiyle çarpar). Yapı: SQUARE
(sql_floating_point_expression) şeklindedir.
SQRT: Argümanın karekökünü alır. Yapı: SQRT (sql_floating_point_expression)
TAN: Argüman ifadesinin tanjantını alır. Yapı: TAN (sql_floating_point_expression)
STRING FONKSİYONLARI
Veri genellikle karakterler stringi şeklinde saklanır ve sizin stringler hakkında bilgi edinmeniz
gerekir. SQL’in string fonksiyonları, stringin bir kısmını almanıza, boşlukları silmenize ve string
hakkında bilgi edinmenize imkan tanır.
ASCII: String ifadesinin en sol karakteri diye anılan ilk karakteriyle ilişkili ASCII kodu döndürür. Yapı:
ASCII (string_expression) şeklindedir.
ASCII (‘Le Monde’)
CHAR: Argüman olarak verilmiş ASCII kodla ilişkilendirilmiş karakteri döndürür. Yapı: CHAR
(sql_integer) şeklindedir.
CHARINDEX: Aranacak olan string içinde, belirtilen string parçasının başlangıç yerini döndürür. Yapı:
CHARINDEX (string_to_find, string_to_search [, starting_position]) şeklindedir. String_to_find, bulmak
istediğiniz; string_to_search, içinde arayacağınız geçerli string veri tipindeki ifadelerdir. Starting_position
ise arama işlemine kaçıncı karakterden başlanacağını belirten integer’dır. (Belirtilmediği takdirde 1 olarak
alınır)
CHARINDEX (‘find me’, ‘look here to find me’)
LEFT: İlk argümanla belirtilen stringin soldan itibaren ikinci argümanla bildirilen sayı kadar
karakterini döndürür. Yapı: LEFT (sql_string_expression, sql_integer_expression) şeklindedir.
LEN: Argüman olarak girilen stringin karakter sayısını döndürür. Yapı: LEN
(sql_string_expression) şeklindedir.
LOWER: Argüman olarak belirtilen stringi, bütün karakterleri küçük karakter olacak şekilde
döndürür. Yapı: LOWER (sql_string_expression) şeklindedir.
LTRIM: Argüman olarak bildirilen stringi, başındaki boşluklar silinmiş şekliyle döndürür. Yapı:
LTRIM (sql_string_expression) şeklindedir.
NCHAR: Argüman olarak belirtilen kodun Unicode karakter karşılığını döndürür. Yapı: NCHAR
(sql_integer_expression) şeklindedir.
PATINDEX: İlk parametre olarak girilen örüntüyü ikinci parametre olarak girilen stringte arar ve
bulduğu zaman ilk karakterin stringteki kaçıncı karakter olduğunu döndürür. Yapı: PATINDEX
(‘%sql_pattern%’, sql_string_expression) şeklindedir. Sql_pattern, wildcard içerebilen bir dizi
karakterdir. İlk % karakteri örüntünün ondan sonra gelen karakter ile başlanacağını, sondaki % karakteri
de ondan önce gelen karakter ile bitirileceğini belirtir.
PATINDEX (‘%My%’, ‘My string’)
QUOTENAME: Unicode string alır ve stringin başına ve sonuna tırnak işareti (ya da sizin belirteceğiniz
işareti) koyar. Yapı: QUOTENAME (‘sql_character_string’ [, ‘sql_quote_character’])
QUOTENAME (‘column_1’, ‘/’)
REPLACE: İlk argüman olarak verilen stringte ikinci argüman olarak verilen stringi bulur ve
üçüncü argüman olarak verilen stringle değiştirir. Yapı: REPLACE (sql_string_to_search,
sql_string_to_find, sql_string_to_replace_with) şeklindedir.
REPLICATE: İlk argüman olarak verilen stringi, ikinci argüman olarak verilen sayı kadar
tekrarlar. Yapı: REPLICATE (sql_sting_expression, sql_integer_expression)
REVERSE: Argüman olarak girilen karakter stringinin karakterlerini ters sırada (ilk karakter son
karakter olacak şekilde) sıralar. Yapı: REVERSE (sql_string_expression)
RIGHT: İlk argüman olarak girilen stringin sağdan itibaren ikinci argüman olarak bildirilen
sayıda karakterini döndürür. Yapı: RIGHT (sql_sting_expression, sql_integer_expression)
RTRIM: Girilen stringin, sonundaki boşlukları silinmiş şeklini döndürür. Yapı: RTRIM
(sql_string_expression)
SOUNDEX: SOUNDEX, iki stringin ses benzeşmesini hesaplamada kullanılır. Bu fonksiyon, verilen
stringin soundex kod karşılığını döndürür. (Soundex kod, birbirine telaffuz açısından benzeyen iki
kelimede aynıdır. (Jane ile Jayne gibi)) Yapı: SOUNDEX (string_expression) Aşağıdaki örnek S500
döndürür.
SOUNDEX (‘Jane’)
STUFF: Girilen stringin belirtilen karakterinden itibaren belirtilen sayıda karakterini siler ve yerine,
girilen diğer bir stringi koyar. Yapısı: STUFF (sql_string_expression_to_modify, sql_integer_start,
sql_integer_length, sql_string_expression_to_insert)
STUFF (‘To be or not to be’, 7, 2, ‘well, maybe’)
CASE
ELSE 0
CAST: Argüman olarak girilen verinin tipini, belirtilen veri tipine çevirir. Yapı: CAST (sql_expression
AS sql_data_type)
CAST (date_column AS varchar(10))
CONVERT: Verilen ifadeyi belirtilen formatta belirtilen veri tipine döndürür. Yapı: CONVERT
(sql_data_type, sql_expression, sql_format_code) şeklindedir. Sql_data_type, geçerli bir SQL veri tipidir.
Sql_format_code ise veritabanınız tarafından belirtilen bir format kodudur. Yaygın olanları şunlardır:
(1=mm/dd/yy, 101=mm/dd/yyyy, 2=mm.dd.yy, 102=mm.dd.yyyy, 3=dd/mm/yy, 103=dd/mm/yyyy,
4=dd.mm.yy, 104=dd.mm.yyyy)
Varsayılan tarih kodu 0 (veya 100) ise şu formattatır: mon dd yy hh:mmAM (mon dd yyyy hh:mmAM)
CONVERT (datetime, column1, 101)
ISDATE: Eğer ifade, veritabanınız için geçerli bir tarih değeri ise true, aksi halde false döndürür.
Yapı: ISDATE (sql_expression) şeklindedir.
ISNULL: Eğer ifade NULL ise true, değilse false döndürür. Yapı: ISNULL (sql_expression)
ISNUMERIC: Eğer ifade sayı olarak alınabiliyorsa true, aksi halde false döndürür. Yapı:
ISNUMERIC (sql_expression) şeklindedir.
Bu SQL deyimi, bir kayıtlı prosedür gibi iyi çalışacaktır. Bu sorgu, School tablosundan bütün
satır ve sütunları döndürür. Bununla beraber kayıtlı prosedür olarak kullanmak için bu sorgu biraz daha
açık olmalıdır. Bu sorguyu ilerde geri döndüğümüzde devam ettirmek istediğimizde, en son istediğimiz
şey * in ne anlama geldiğini unutmak olacaktır. (Üç sütun mu, dört sütun mu, kaç sütun var?) Ayrıca
whitespace kullanarak sorguyu plana göre düzenlemek istersiniz. Dönen sütunları kolayca
yerleştirebilmek istersiniz.
Sorguyu plana göre düzenlemenin genel yolu şöyledir: SQL anahtar kelimeleri büyük harfle
yazılır, her bir sütun ismi ayrı satırlarda yazılır ve anahtar kelimeler satırların solunda diğerlerinden
yalıtılmış şekilde yazılır. Bu stil, prosedürleri daha iyi anlaşılır hale getirir:
SELECT School_ID
School_Name
Active
FROM School
CREATE PROCEDURE’Ü KULLANMAK
Oluşturduğunuz sorguyu kayıtlı prosedüre yerleştirmek için kullanacağınız deyim şu yapıdadır:
CREATE PROCEDURE name [; int number] AS sql_query
Name, prosedürün ismini ifade eder. Eğer noktalı virgül ve bir integer içerirseniz, aynı kök ismine
sahip bir grup kayıtlı prosedür oluşturursunuz ve onlar birbirinden, onlara eklenen sayılarla ayrılırlar.
Örneğin bir grup sipariş kaydı prosedürü OrderEntry;1, OderEntry;2, OrderEntry;3 şeklinde
isimlendirilebilir. Bu isimlendirme, prosedürleri self-documenting yollarla isimlendirmenize izin vermez,
fakat bütün OrderEntry prosedürleri DROP deyiminde sadece kök ismini kullanarak tek bir defada
silmenize olanak tanır. Sql_query de yukarda yaptığımız gibi bir sql sorgusudur.
AS
SELECT School_ID,
School_Name,
Active
FROM School
Burada kullandığımız isimlendirmeye dikkat edin. İlk üç harf (küçük harf olarak yazılmış)
sorguda kullandığınız emiri belirtir (Buradan SELECT sorgusu olduğu anlaşılıyor). Sonraki üç karakter,
bu sorgunun ilişkili olduğu programlama elemanının tipini belirtir (Frm, form olduğunu belirtiyor).
Sonraki karakterler sorguyla ilişkili programlama elemanının adıdır (FrmSchool). Sorgunun ismindeki
son eleman ise sorgunun kullandığı prosedür veya kontrolün ismidir.
Tip: Birden fazla program veritabanına eriştiği zaman, kayıtlı prosedürün ismine programı
belirtecek ek yapmak uygun olur. Eğer inceleme ihtiyacı duyarsanız kolayca hangi programın kodunu
çağıracağınızı bilirsiniz.
Dikkat etmeniz gereken bir ayrıntı daha var. Eğer kayıtlı prosedürü Enterprise Manager’da sağ
tıklayarak incelerseniz SQL kodunun en sonunda (FROM School’dan sonraki satırda) GO deyimini yazılı
bulursunuz.
GO deyimi, ondan önce gelen deyim yığınının şimdi koşulacağını işaret eder. GO’yu icrayı
başlatan bir işaretçi gibi düşünebilirsiniz. Bununla beraber kayıtlı prosedürdeki GO, bütün SQL
veritabanları tarafından desteklenmez. Onu, kayıtlı prosedürün sonunda çalışıyor bulabilirsiniz, fakat onu
başka yerde kullanırsanız söz dizimi hatasıyla karşılaşabilirsiniz.
Tip: Prosedürü silmek için DROP PROCEDURE procedureName ‘i kullanabilirsiniz.
PROSEDÜRÜ ÇAĞIRMAK
Kayıtlı prosedürü kullanmak için onu çağırabiliyor olmalısınız. Prosedürlerinden birini kullanmak
istediğiniz ve sonuçların size dönmesini istediğiniz, server’ı bilgilendirme araçlarına ihtiyacınız vardır.
Tam olarak server’ı böyle nasıl bilgilendirdiğiniz ve sonuçları nasıl aldığınız, içinde bulunduğunuz
koşullara bağlıdır.
Eğer bir sorgu aracındaysanız, araç kendi kendine kayıt kümesinin sonuçlarını alarak tutar. Sizin
sadece, server’a sizin için kayıtlı prosedürü icra etmesi için şu şekilde bir deyim yazmanız yeterlidir:
EXEC selFrmSchoolAdodc1
SONUÇLARI KULLANMAK
Herhangi bir kayıt kümesini kullanabildiğiniz gibi aynen, kayıtlı prosedürün sonuçlarını da
kullanabilirsiniz. Bir kere kayıt kümesi döner, diğer herhangi bir kayıt kümesiyle aynı biçimde davranır.
Kayıt kümesi kullanmadaki bazı seçenekler şunlardır:
Query Analyzer gibi araçlarla ona göz atmak
Data control’ün Recordset özelliğine kayıt kümesini atamak
Güncel kayıtla ilişkili değerleri, veriyi ekranda gösterecek bir grup kontrole atamak
Kayıt kümesinde ileri veya geri harekete ve güncel kayıdı ekranda gösteren kontrolün
değerlerini güncellemeye izin veren düğmeler oluşturmak
Kayıtları ekranda göstermeye izin vermek için, birt kayıt kümesini bir özellik gibi kabul eden
bir grid kontrolüne kayıt kümesini eklemek
Tip: Çoğu veritabanları için GO kullanmamıza gerek yoktur. GO’suz bir kayıtlı prosedür düzgün
çalışabilir. Bazı veritabanlarında, GO’yu prosedürü sizin için kesmesi için veritabanına izin vermede
kullanırsanız hata mesajı alırsınız.
Tip: Kayıtlı prosedürü sonlandırmak için GO’nun yerine RETURN de kullanabilirsiniz. SQL,
icra esnasında RETURN’e rastlarsa SQL kodunu icrayı durdurur. RETURN’den sonraki hiçbir deyim icra
edilmez. Bu davranıştan dolayı GO, RETURN’e göre gaha yumuşak sonlandırma olarak bilinir. GO,
veritabanına deyim yığınında icra edilecek kaç deyim olduğunu söyler, o deyimler onlarda gömülü
mantığa göre icra edilir ve ondan sonra prosedür sona erer. Bununla beraber RETURN, prosedürün
çağıran programa değer geri göndermesine neden olur. Eğer RETURN ile aynı satırda onu izleyen bir
değer yoksa 0 değeri çağıran programa gönderilir. Eğer çağıran programa geri değer gönderme
ihtiyacımız varsa GO yerine RETURN kullanmalısınız.
Tip: Değişken ismindeki @ işaretinin özel anlamı vardır. Tek @ işareti ile başlayan değişken
isimlerine sahip değişkenler kayıtlı prosedür için yereldir. İki tane at işareti (@@) ile başlayanlar ise
global’dir ve server’da çalışan bütün kayıtlı prosedürler için kullanılabilirdir.
Tek satırda birden çok da değişken deklare edebilirsiniz:
Her bir değişken isminin değişken tipiyle beraber kullanıldığına dikkat edin. Ayrıca, varsayılan
değerler DECLARE deyimi kullanarak atanamazlar.
Varsayılan değerleri değişkenlere atamanın 2 yolu vardır. İlki olan SELECT deyimini şu şekilde
kullanabilirsiniz:
SELECT @OverNight=’4:00 am’
SELECT, belki de atama için en uygun yoldur. Çünkü bütün SQL veritabanlarında
belirtildiğinden emin olabilirsiniz. Daha sonraki standartlar, değişkenin değerini atamak için SET
deyimini sağlamıştır:
SET ile SELECT arasında çok küçük bir fark vardır. SET, bir sorgunun sonucu olan bir değeri
atamanıza izin verir:
Bu SET deyiminde SELECT değikenine atanacak olan Qty sütunundaki değerleri toplar ve
sadece ve sadece bir değer döndürür. Fakat bunu SELECT ile de yapabiliriz:
Bununla beraber SET, cursor’lar ve değişkenlerle çalışmanıza izin verirken SELECT buna izin
vermez.
AKIŞ KONTROLÜNÜ KULLANMAK
Akış kontrol deyiminin amacı koşullar belirtmektir. SQL 2 tip akış kontrolü sağlar:
IF … ELSE
Spesifik veritabanı temelinde uygulanmış loop yapıları
Bütün veritabanları IF … ELSE ‘i destekler. Bazı veritabanları LOOP ve FOR deyimlerini
destekler. Diğerleri WHILE deyimini destekler.
IF, bir koşulu test etmenize ve koşulun doğruluğuna göre bir veya bir grup deyimi icra etmenize
izin verir. Temel yapı şöyledir:
IF condition
BEGIN
Statements
END
ELSE
BEGIN
Statements
END
Condition, True veya False olarak değerlendirilebilecek bir SQL ifadesidir. Statements, geçerli
SQL deyimleridir. BEGIN ve END, ard arda çalışması gereken deyim bloğunun sınırlarını belirler. Bu
bloğun arasındaki deyimler, ondan önce gelen şartın uygunluğu durumunda çalışırlar.
Kayıtlı prosedürümüzün ilk koşulunu ayarlamak için o andaki saatin gecenin sona erme saatine eşit veya
daha ilerde mi olduğuna bakmak gerekir. Eğer koşul doğru ise önceki 24 saat için SUM deyimini
koşacağız:
IF DATEPART(hh, GETDATE())<DATEPART(hh,@OverNight)
BEGIN
END
Buradaki mantığa dikkat edelim. Eğer o andaki saat gecenin sona ermesinden küçük ise (ve gün
aynı ise) deyimi çalıştırıyor. @OverNight değişkenine yerleştirdiğiniz değer DATEPART() ile
çıkarılabilen bir saat değeri olmalıdır. 24 saat kullandığımızı farz edelim. (böylece sabah ile akşam ayırt
edilebilir) Ayrıca ord_date, tarih’in Aricinde zamanı da içermelidir. Son olarak, zamanın sona erme
vaktinden önce kayıtlı prosedüre başlamış olmak gerekir.
Geri kalan iki koşul da (CloseOfBusiness ile MidDay) de aynı yapıdadır.
SQL’de akış kontrolünde döngüler de kullanabilirsiniz. Oracle kullanıyorsanız koşulsuz
döngülere ve FOR LOOP’a aşinasınızdır. Diğer veritabanları bu döngü yapılarını desteklemezler. SQL
Server sadece WHILE döngüsünü destekler.
Size bir görüş vermesi açısından Oracle’da yazılmış bir döngü yapısına bakalım:
LOOPCOUNTER := 0
END LOOP;
END;
Dikkat ederseniz, SQL deyimlerinin sonuna noktalı virgül konuyor ve döngü deyimi
LOOPCOUNTER := 0 ile başlayıp END LOOP ile bitiyor. Ayrıca, özelleştirilmiş atama operatörü (:=)
kullanılıyor ve değişkenlerin önünde @ işareti bulunmuyor.
Aynı döngünün SQL Server 2000 ile yazılmış şekli şöyledir:
SELECT @LOOPCOUNTER = 1
BEGIN
END
Bu iki döngü de aynı işi yaparlar. Döngü 4 defa çalışır ve arurma değeri 1 olduğu için her adımda
sayıcı 1 artar. Sayıcı 5’e ulaştığında döngüden çıkılır.
Örneğimize dönersek, prosedürümüzün gecenin sona erme zamanında 10 dakika içinde icra
edilmesini isteriz.
WHILE (DATEPART(mi, GETDATE())
BEGIN
BREAK
END
Bu döngü sadece GETDATE() ile çekilen dakika değeri @OverNight ile çekilen dakika değeri ile
10 dakika öncesi arasındayken icra edilir (BETWEEN kullanımı, verilen 2 saat arasında saat seçmenize
imkan tanır). GETDATE()’in gün bölümünü de kontrol ettik ve @OverNight ile aynı olduğundan emin
olduk.
IF deyimlerinin olduğu yeri daha önce işlediğimiz için sadece etiketini koyduk. BREAK deyimi
IF deyimleri icra edildikten sonra koşulsuz olarak çıkmayı sağlar (örnekte sadece bir defa
hesapladığımıza dikket edin).
DEĞER DÖNDÜRMEK
Döndürülen değer, kayıtlı prosedürden çağıran prosedüre geri yollanan değerdir. Bu yolla sadece
tek değer döndürülebilir. Çağıran prosedüre geri değer döndürmek için RETURN deyimini kullanmanız
gerekir. Genel yapı şöyledir: RETURN [expression]
Eğer RETURN’ü sade (ifade kullanmadan) kullanırsak 0 değerini döndürür. Aksi halde,
RETURN kelimesini izleyen SQL ifadesinin değerini döndürürsünüz.
Tip: Çoğu veritabanları hata oluştuğunda hatanın numarasını tutan dahili global değişkenlere
sahiptirler. Örneğin SQL Server’da bu değişken @@error dur. Eğer hata oluşmazsa değişken 0 değerini
tutar. Değişkendeki değer, en son çalışan deyimle ilgili hata kodudur.
Kayıtlı prosedürden dönen değeri elde etmek için EXEC deyimini kullanmanız gerekir:
HATA TANIMLAMAK
Hata oluşursa, onu, kayıtlı prosedürün return değerindenbağımsız olarak çağıran programa
döndürmek isteyebilirsiniz. Bu, eğer uygulamanızın hata tutma kodu hatayı alabilir ve raporlayabilirse
çok kolaydır.
Her bir SQL veritabanı döndürülen hatalar için bir mekanizma sağlar.
SQL Server’da hatayı döndürmek için RAISEERROR deyimini kullanırsınız. Yapısı şöyledir:
RAISEERROR ({msg_num or msg_str}, severity_num, state, [,argument1
[,argument2] ]) [WITH Options]
Bu yapıda, mesaj numarası veya mesaj stringi kullanmanız gerekir. Ayrıca büyüklük derecesini
belirten bir numara da yazmalısınızdır. Geçerli numaralar 0 ile 25 arasındadır. Genellikle kullanıcılar 0 ile
19 arasındaki değerleri kullanırlarken, sistem yöneticileri 20 ile 25 arasındakileri kullanmaktadırlar.
State, hata oluştuğunda sistemin durumunu belirten 1 ile 127 arasında keyfi bir sayıdır.
Hata numarası kullanarak hatayı tanımlamak için bu deyimi şu şekilde kullanırız:
RAISEERROR (50025,1,1)
SQL Server 1 ile 50000 arasındaki hata numaralarını kendisi için ayırır. 50000’den yukarı olanlar
kullanıcı tarafından tanımlı hatalardır. Hatanın büyüklük derecesinin 1 olması bilgi seviyesinde olduğunu
belirtir. Daha büyük hatalar için büyüklük derecesi artırılmalıdır.
Mesaj stringine sahip bir hata tanımlamak istiyorsanız şu yapıyı kullanabilirsiniz:
Hata stringinizde ek bilgiler içermek için vekil parametreler kullanabilirsiniz. Örneğin hata
numarasını deyime yerleştirebilirsiniz.
Burada %d, en sonda belirtilen 50025 sayısının signed integer olduğu anlamındadır. (d veya I=
signed Integer, O= unsigned integer, P= Pointer, S=String, U= Unsigned Integer, x veya X= Unsigned
Hexadecimal)
Deyimin son kısmında seçenek anahtar sözcüğünü kullanabilirsiniz. Şu seçenekler var:
LOG: Veritabanı loguna hatayı yazar.
NOWAIT: İstemciye mesajı beklemeden yollar.
SETERROR: Sağladığınız mesaj numarası veya mesaj stringini @@error’un değerine atar.
PARAMETRELER KULLANMAK
Veriyi alıp alamadığımızı öğrenmek için (örnek olarak) strBuffer ile “MyDirectory” yi byte byte
karşılaştırmamız gerekir. Alınanın doğru olduğunu anlamak için muhtemelen 11 karşılaştırma yapmanız
gerekecektir. GetCurrentDirectory() ile uygulanan yaklaşımla, eğer 0 byte geri dönmüşse fonksiyonun
başarısız olduğunu anlıyoruz.
Peki, strBuffer nedir? Teknik olarak, Visual Basic’te bir string değişkenidir. İşletim istemi
açısından, fiziksel bellekte bir alan belirten isimlendirilmiş depolama yeridir. Bu fiziksel bellek,
fonksiyonun çalışması esnasında, o andaki dizin’in isminin yazıldığı yerdir. Ardından, programınız, o
andaki dizinin’in ne olduğunu öğrenmek istediği zaman bu depolama yerine erişebilir. Çıkış
parametresinin özü de, çağıran ve fonksiyon kodu tarafından erişilebilir olan depolama yeridir. Buraya
yerleştirilen her veriye, fonksiyon ve onu çağıran program tarafından erişilebilir.
SQL’de aynı tür rutinler vardır. Eğer parametreyi çıkış parametresi olarak belirtirseniz parametre,
depolama için tahsis edilmiş bellektir. Değer, o yere yerleştirilmiştir ve o yerin adresi çağıran program
tarafından elde edilebilirdir. Eğer işlem veritabanı server’ında çalışıyorsa veritabanı server’ında bellek
tahsis edilmiştir (istemcide çalışıyorsa istemcide tahsis edilmiştir). Veritabanı API’ları (ODBC API gibi)
çıkış parametreleri için bellek tahsis etme ve okuma yeteneklerine sahiptir. Ağ üzerinde bir makineden
diğerine veri hareketine ihityaç duyulursa bunu başarabilirler. Veritabanımızda istemci erişimi
programlaması için kullandığımız ActiveX Data Objects, parametre değerlerini alma ve depolama
yeteneğine sahiptir.
PARAMETRELER OLUŞTURMAK
Parametrelerin bütün avantajlarından yararlanmak için onları, parametreleri alacak olan kayıtlı
prosedürlerde ve kayıtlı prosedürleri çağıracak olan programlarda oluşturabiliyor olmanız gerekir. Kayıtlı
bir prosedürde bir parametre oluşturmak için, CREATE PROCEDURE deyiminde prosedür isminden
sonra ve AS’den önce bir değişkenler listesi vermeniz gerekiyor:
CREATE PROCEDURE myProc
@ParameterIN varchar(20),
Program tarafında parametre oluşturmak için ADO emir nesnelerini kullanırsınız. Bu nesneler, kayıtlı
prosedüre verebilen ve kayıtlı prosedürden alabilen parametrelerin bir koleksiyonunu tutar. Bir kere emir
nesnesini oluşturduğunuz zaman parametreleri eklemek için aşağıdaki gibi deyimler kullanmanız gerekir:
Set prmInput = cmdCommand.CreateParameter(“MyInputParameter”, adVarChar,
adParamInput, 20, “ParameterValue”)
cmdCommand.Parameters.Append prmInput
cmdCommand.Parameters.Append prmOutput
cmdCommand.Parameters.Append prmReturn
Genelde Set deyimi, parantezler arasında belirtilen nitelikleri olan bir parametre oluşturmak için
emir nesnesi içindeki CreateParameter metodunu kullanır. Bu niteliklerin hepsi opsiyoneldir. Bunlar:
Ad:Sonradan onu çağırmak için kullanabileceğimiz bir parametre ismi veren bir stringtir.
Tip: Parametrenin veri tipi. ADO, kullanımda SQL veri tiplerine benzer veri tipleri için sabitler
tanımlamıştır. Bu sabitler şunlardır: adBigInt, adBinary, adBoolean, adBSTR (Unicode stringler için),
adChapter, adChar, adCurrency, adDBDate, adDBTimeStamp, adDecimal, adDouble, adEmpty, adError,
adFileTime, adGUID, adInteger, adLongVarBinary, adLongVarChar, adLongVarWChar, adNumeric,
adSingle, adSmallInt, adTinyInt, adUnsignedBigInt, adUnsignedInt, adUnsignedSmallInt,
adUnsignedTinyInt, adVarBinary, adVarChar, adVarNumeric, adVarWChar (null’la bitirilmiş Unicode
string için), adWChar
Yön: Parametrenin yönüdür. Mümkün değerler: adParamInput, adParamOutput,
adParamInputOutput, adParamReturnValue, adParamUnknown.
Boyut: Parametrenin kullandığı karakter sayısını veya byte’ı belirten integer’dır (integer değerle 4
byte yer tuttuğu için 4 değeri yazılırken string değerlerde karakter sayısıyla orantılıdır).
Değer: Parametrenin değeridir. Bu niteliği, oluşturma zamanında bir değeri ayarlamak için
kullanırsınız.
Tip: Parametre koleksiyonundaki parametrenizin veri tipi kayıtlı prosedürde kullandığınız veri
tipiyle aynı olmalıdır.
DEĞERLER VERME
SQL’de değerleri EXECUTE deyiminde, parametre değerlerini kayıtlı prosedürün isminden sonra doğru
sırada listeleyerek verebilirsiniz:
EXECUTE ProcedureName ‘InputValue1’, ‘InputValue2’
Kayıtlı prosedürde varsayılan parametre değerini kullanabilirsiniz. Böyle yapmak için CREATE
PROCEDURE deyiminde değerleri içermeniz gerekir:
@ParameterIn varchar(20)=’ThisValue’
AS
İstemci programından parametreleri vermek için 2 yöntem vardır. İlkinde, parametreleri emir
nesnesinin CommandText özelliğini oluşturan string içinde toplarsınız. Bu metod, emir nesnesini
kullanarak giriş parametresinin bir koleksiyonunu oluşturmak istediğinizde kullanmanız gereken
metoddur. strInputValue değişkenini deklare ettiğinizi farz edersek şu yapıyı kullanarak kayıtlı prosedüre
değerleri verebilirsiniz:
Çıkış parametresini almak için parametre listesindeki parametreyi içerin ve OUTPUT anahtar kelimesini
kullanın:
EXECUTE @ReturnValue = MyStoredProcedure @OutputParameter =
@ReceivedValue OUTPUT
cmdCommand.Parameters.Append prmOutput
cmdCommand.Parameters.Append prmReturn
cmdCommand.CommandText = “MyStoredProcedure”
cmdCommand.CommandType = adStoredProcedure
rstRecordset.Close
intReturn = cmdCommand(“MyReturnParameter”)
strOutput = cmdCommand(“MyOutputParameter”)
intReturn = cmdCommand(1)
strOutput = cmdCommand(0)
Tip: Parametreleri aldıktan sonra kayıt kümesine erişimi elde etme ihtiyacı duyarsanız kayıt
kümesini Open metodu kullanarak bir daha açabilirsiniz.
Not: ADO’da parametre değerleri, kayıt kümesi tamamıyla döndürülünce serbest bırakılır.
CURSOR’LARI KULLANMAK
Bazen kayıt kümesine denk başka bir SQL işleme türüne ihtiyaç duyabilirsiniz. SQL, kayıt
kümesini içine almaya izin veren cursor’ı size sunar. İsimlendirilmiş bir cursor’unuz oldu mu, satırları u-
cursor’dan alabilir ve o satır üzerinde çalışabilirsiniz. SQL cursor’ını ADO kayıt kümeleriyle
karşılaştırırsanız bazı benzerlikler bulacaksınızdır. Bir satırdan diğerine geçiş, kayıt kümesinde yaptığınız
gibidir. Satırdaki alan değerlerine erişebilir, satırdaki alan değerlerini güncelleyebilir veya bir satırı
silebilirsiniz. Cursor ile istemci tarafındaki kayıt kümesi arasındaki fark, cursor’ın işlemi veritabanı
server’ında icra etmesidir. Cursor’lar verinin ağ boyunca sıralanmasını gerektirmez. Bir ADO kayıt
kümesiyle yapacağınız işlerin hepsini, cursor kullanarak bir kayıtlı prosedür olarak belirtirseniz, aynı işi
server tarafında işlenen şekliyle yapmış olursunuz. Böylece server’ın işleme gücünden yararlanırsınız.
Bununla beraber cursor’ı dikkatli kullanmanız gerekir. Çoğu SQL programcıları cursor’ları
performans hırsızı olarak görmektedir, ki bu iddia doğrudur. Cursor’lar, bütün işlemler server tarafında
yapıldığı zaman en iyi sonucu verirler. Cursor kullanan kayıtlı prosedür, istemciyle bağlantı kurmadan,
tek başına işlemleri server tarafında tamamlamayabilir. Cursor’lar, istemciye döndüreceğiniz (özellikle
kayıt kümesi dönünceye kadar işleme devam edemeyen) bir kayıt kümesi oluşturmak için cursor
kullanmanız gerektiğinde yavaş kalırlar.
Not: Cursor’ların yavaş olmasının bir sebebi, cursor’ın kullanımını kolaylaştırmak için geçici
tablolar oluşturması ve tutmasıdır. Tipik olarak bir cursor, cursor’la ilgili satırları tutması için TempDB
veritabanında geçici bir tablo oluşturur.
Bir SELECT deyimi, SELECT deyimi ile belirtilen kayıt kümesinde bir cursor’a göre daha hızlı
çalışır. Seçilen satır; kayıtlar, kayıtlara pointer ve cursor’da kayıtlar arasında gezinmenize izin veren
benzer yapılar içerecek olan veri yapıları üretmenizi gerektirmez. Cursor kullanma ile kullanmama
arasında bir seçim olduğunda genellikle cursor kullanılmayan çözüm performans bakımından tercih edilir.
Bununla beraber, yapılacak işin kayıtlı prosedür olarak tanımlandığı tek istemci etkileşiminin
kayıtlı prosedürü çağırmak olduğu, prosedürün çalıştığı ve görevin tamamen sever tarafında gerçekleştiği
durumlar tam cursor’ın kullanımına göredir. Ayrıca cursor esneklik ve doğruluk sağlar.
CURSOR’I DEKLARE ETMEK
Cursor’ı kullanmak için önce deklare etmeniz gerekir. Cursor’ı deklare etmek, bir cursor’ı
kullanmayı niyet ettiğinizi veritabanına bildirme işlemidir.
Temel bir cursor deklarasyonu şu şekildedir:
Bu deyimin temel elemanları: DECLARE anahtar kelimesi, cursor için bir isim, cursor’ı
oluşturuyor olduğunuzu belirten CURSOR FOR anahtar kelimeleri ve bir SELECT deyimidir.
Cursor’ın deklarasyonunda kullanacağınız ek seçenekler de vardır. Örneğin:
INSENSITIVE anahtar sözcüğü, TempDB’deki bir tabloya döndürülen verinin bir kopyasına
cursor’ın yerleşmesine neden olur. Veri üzerindeki bütün işlemler verinin bu gizli kopyasında
gerçekleştirilir. Insensitive cursor’ı veriyi güncellemek için kullanamazsınız.
DECLARE curAuthor CURSOR FOR SELECT * FROM authors FOR READ ONLY
Bu örnekte FOR ifadesini kullanmak, cursor’ı salt-okunur yapıyor. Veriyi okuyabilir fakat
değiştiremezsiniz. Eğer cursor’da alanları güncellemek isterseniz şu formu kullanmanız gerekir:
DECLARE curAuthor CURSOR FOR SELECT * FROM authors FOR UPDATE phone
FOR UPDATE ifadesi cursor’da virgüllerle ayrılmış listedeki sütunların cursor’da güncellenebilir
olduğunu belirtir.
CURSOR deklare edildikten sonra OPEN emri ile kullanılır.
OPEN curAuthor
OPEN deyimi, cursor’ın veri ile yaşaması için cursor’ın kayıt kümesini belirten sorguya neden
olur.
CURSOR’LARI KULLANMAK
Cursor’ları kullanmak için onları OPEN metoduyla açmanız gerekir. FETCH deyimini cursor’dan
satırları (işletebilmeniz için) belleğe almak için kullanabilirsiniz. Bütün cursor’lar şu deyime cevap
verecektir:
Bu deyim, bir sonraki satırın işlemler için geçerli olmasına sebep olur. Bu, sonraki satırın belleğe
alındığı ve SQL’in ona ve onun bütün alanlarına bir pointer (işaretçi) tanıttığı anlamına gelir. Eğer belirli
sütunların değerlerini değikenlere yerleştirmek istiyorsanız, prosedürdeki alana işlemini yapacak olan
değişkenleri deklare etmeniz gerekir. Spesifik alanları spesifik değişkenlere şu deyimle alabilirsiniz:
FETCH NEXT FROM curAuthor INTO @au_id, @au_fname, @au_lname, @phone, @address,
@city, @state, @zip, @contract
FETCH, esneklikle cursor’ın mevkiini ayarlamanıza imkan tanıyan ek anahtar sözcük sağlar.
NEXT’te PRIOR kullanımı bir sonraki yerine bir önceki satırın alınmasını sağlar. FIRST, cursor’ın ilk
satıra; LAST da cursor’ın son satıra gitmesini sağlar. Aşağıdaki deyim ise cursor’ın başından itibaren 8
satırın alınmasını sağlar:
FETCH ABSOLUTE 8 FROM curAuthor
Mutlak ve göreceli konumlandırma, baştan itibaren son kayıda doğru kayıtlar almak için pozitif
sayılar ve sondan başa doğru kayıtlar almak için de negatif sayılar kullanmanıza izin verir. Ayrıca direkt
sayı değeri yerine değişkenler de kullanabilirsiniz.
Başka bir cursor’tan alma yöntemi daha vardır. CURSOR veri tipinde olacak bir değişken
tanımlayabilirsiniz. Bu değişkene bir cursor’ı atayabilir ve kayıtlı bir prosedüre parametre olarak o
cursor’ı geçirebilirsiniz. Bu mekanizmaya bir göz atalım:
SET @MyCursor = CURSOR FOR SELECT * FROM authors FOR UPDATE phone
Bir cursor’a parametre olarak kabul edilebilen bir kayıtlı prosedürünüz olduğunu farz edelim.
Aşağıdaki yapıyla cursor’ı atayabilirsiniz:
Mevcut bir prosedüre bir cursor’ın geçirilmesinin ana nedeni cursor’ı bir çıkış parametresi olarak
veriyle doldurulmuş olarak döndürebilmeniz içindir. Kayıtlı prosedürde cursor’ı yaşatmak için SET
deyimini kullanırsınız. Mevcut prosedür döndüğünde, cursor değişkeni veri kümesine bir referans olarak
kalır. Bu, bir kayıtlı prosedürün çıkışı olarak bir grup satır elde etmek istediğimizde kullanışlı olur.
CUSOR’LARI GÜNCELLEMEK VE ARAŞTIRMAK
Cursor’da satırları değiştirmek ve silmek için UPDATE ve DELETE deyimlerini
kullanabilirsiniz:
SQL, cursor araştırmada bir çift yapı sunar. İlki, global değişken olan @@FETCH_STATUS’tur.
Veritabanınız, bu değişkenden en son alınan için bir sonuç kodu yerleştirir (Eğer alma işlemi başarılı
olmuşsa 0, alma işlemi başarısız olmuş veya cursor’daki son kayıttan öteye gitmeye çalışıldıysa -1,
almaya çalıştığınız kayıt kayıp ise -2). Cursor’ı araştırma işlemine başlamak için ilk önce cursor’ı
tanımlayın ve onu açın. Ardından, ilk satırı alın:
OPEN curAuthor
Bu örnekte Pubs veritabanındaki authors tablosundan 3 sütun almaya karar verdiğimize dikkat
edin. Bu kod parçasının sonunda ilk sütunu aldık ve değerleri değişkenlere yükledik. Artık araştırma
işlemini yapmaya hazırız.
Araştırma işlemi için FETCH_STATUS değeri 0 ise cursor’da satırları incelemeye devam
edebiliriz (0 değilse cursor’la ilgili problemimiz olduğu anlaşılır ve araştırma durdurulması gerekir).
WHILE @@FETCH_STATUS=0
BEGIN
END
Bu mantık, cursor’daki bütün satırları araştırmanız içindir. Soyadı “Stringer” olan yazarın kaydını
yerleştirmek için ise şu mantık kullanılır:
WHILE @@FETCH_STATUS=0
BEGIN
IF @au_lname = ‘Stringer’
RETURN 99
END
Bu örnekte, işlemin başarılı olduğunu belirtmek için bir değer döndürdük. SQL’de ekrana çıktı
sağlamak için PRINT deyimini de kullanabilirsiniz. PRINT sadece basılacak olan stringi argüman olarak
alır:
PRINT ‘Message’
Cursor ile daha karışık işler de yapabilirsiniz. Örneğin, çıkış parametresi olarak kayıtlı prosedüre
geçirilen bir cursor’ı açmak ve yazarların kayıtlarını içine almak gibi. @PassedCursor’ın kayıtlı
prosedüre bir parametre olarak tanımlandığını farz edersek kod şu şekli alır:
FETCH NEXT FROM curAuthor INTO @au_id, @au_fname, @au_lname
WHILE @@FETCH_STATUS=0
BEGIN
IF @au_lname = ‘Stringer’
BEGIN
RETURN 99
END
END
CURSOR’LARI KAPATMAK VE SERBEST BIRAKMAK
Böylece onu kapatmış oldunuz, ama henüz onu yok etmiş olmadınız. İstediğinizde onu yeniden
açabilirsiniz. Cursor’ı veritabanınızdan tamamen kaldırmak için onu deaalocate etmelisiniz:
DEALLOCATE curAuthor
Eğer deallocate etmeyi başaramazsanız, cursor’ın içinde tanımlandığı prosedür sonlandığı zaman
cursor deallocate edilir.
Not: Bazı veritabanları (SQL Server gibi) global cursor deklare etmenize imkan tanır. Bunlar
veritabanı sisteminde çalışan bütün prosedürler için kullanılabilirdir. Eğer global bir cursor oluşturursanız
onu deallocate etmeyi unutmamanız gerekir (Oturumunuz kapatılmadıkça deallocate olmaz).
UNION’LAR OLUŞTURMAK
Bazen sonuçlar istediğiniz gibi dönmeyebilir. Örneğin Pubs veritabanında yazarlar authors
tablosunda, memurlar employee tablosunda tutulmuştur. Burada, bütün yazarların ve memurların bir
listesini almak isteyebilirsiniz. Bu listeyi almak çok kolay değildir. Mesela şu yapıyı kullanamayız:
Bu deyim hata üretir. İlk olarak, FROM’dan sonra birden çok tabloyu listeleyemezsiniz. Tabloları
birleştirmeniz gerekir. Fakat bu iki tablo, birleştirilmenin gerçekleşmesi için ortak alana sahip değiller.
İkinci olarak, ad ve soyad her iki tabloda da aynı adla belirtilmemiştir. Employee tablosunda fname ve
lname olarak belirtilmişken authors tablosunda au_fname, au_lname olarak belirtilmiştir.
İstediğimiz kayıt kümesini oluşturmak için 2 SELECT deyimi kullanabiliriz:
Bu çözümle 2 liste oluşturmuş olduk. Eğer onların birleştirilmiş ve alfabetik olarak sıralanmış
olmasını istersek çok iş yapmamız gerekecektir (onları basıp, basılanı kesip, isimleri sıralayıp listeye geri
yapıştırmalı veya 2 kayıt kümesini almak ve birleştirmek için bir program yazmalıyız).
Bu işi yapmak için birden çok SQL deyimini bağlamaya izin veren bir operatör vardır. Bu
operatör UNION operatörüdür.
UNION OPERATÖRÜNÜ KULLANMAK
UNION operatörünü kullanmak çok basittir. İlk önce kayıtları seçecek olan SQL deyimlerini ayrı
bir yerde yazın ve onların veriyi doğru olarak çektiğinden emin olun. Sonra, UNION operatörünü
kullanarak iki deyimi birleştirin:
SELECT fname, lname FROM employee
UNION
Bu deyim çalışınca iki kayıt kümesi çıkışta tek bir kayıt kümesi olarak belirir. Sütun isimleri ilk
deyimde gözüktüğü gibidir (fname, lname).
Eğer veriyi sıralamak isterseniz UNION’daki son sorguya ORDER BY ifadesini yerleştirmeniz gerekir:
SELECT fname, lname FROM employee
UNION
ORDER BY lname
Tip: ORDER BY’ı union’larla kullanırken bu ifadeyi sadece son sorguya koymanız gerekir.
Başka bir yere koymak hata çıkmasına sebep olur.
UNION SINIRLAMALARI
UNION’lar bütün veritabanlarında veya aynı veritabanının geçmiş sürümlerinde aynı şekilde
uygulanamayabilirler. Örneğin SQL Server 7.0 bir view yaptığınız zaman UNION operatörü
kullanmanıza izin vermezken, SQL Server 2000 buna izin verir. Veritabanınızın her zaman UNION
operatörünü desteklemediğini görebilirsiniz.
Eğer UNION kullanıyorsanız şu sınırlamaları aklınızda tutmanız gerekir:
Union’daki sütunlar, ilk sorguda kullanılan sütunlarla ilişkili olmalıdır.
Değişik sorgularda referanslanan sütunların veri tiplerinin aynı olması gerekmez. Örneğin
fname için veri tipi varchar(50), au_fname için veri tipi char(10) olabilir. Veri tipleri karşılıklı
olarak uygun tipe çevrilir. (İkinci sorgudaki değişkenin tipi ilk sorgudaki değişkenin tipine
çevrilir, gerekirse kırpılır)
Her bir sorguda aynı sırayla uygun sütunları referanslamalısınız. UNION, hangi sütunun
hangi sütunla eşleşeceğini yerlerine göre belirler. İlk sorgudaki ilk sütun ikinci sorgudaki ilk
sütunla, ilk sorgudaki ikinci sütun ikinci sorgudaki ikinci sütunla… eşleşir.
Uygun düşen sütunlar değişik tipteyse onların veri tipi dönüşümünün gerçekleşebileceğinden
emin olmanız gerekir. Eğer veritabanınız o iki tip arasındaki dönüşümü desteklemezse
sorgularla bu dönüşümü desteklemeniz gerekir.
Union’daki bütün sorgular SELECT ile FROM arasında aynı sayıda ifade içermelidir.
(“ifade” ile kastedilen, sütun ismi, aggregate fonksiyonlar, alt sorgular… SELECT deyiminin
yapısına göre kullanabileceğiniz bütün elemanlardır.)
Eğer union’ın sonuçlarının bir tabloda kayıtlı olmasını isterseniz union’daki ilk sorguya
INTO ifadesini yerleştirmeniz gerekir.
UNION operatörünü INSERT deyiminin yükleminde kullanabilirsiniz.
ODER BY ve COMPUTE sadece union’ın son sorgusunda kullanılabilir.
GROUP BY ve HAVING ifadeleri sadece kullanılmış olan sorguda uygulanabilirler ve
union’daki herhangi bir sorguda bulunabilirler.
UNION olmayan sorgulardan faklı olarak, varsayılan dönüş seçeneği ALL yerine
DISTINCT’tir. Bu gerçekten şaşırtıcıdır. Diğer sorgularımızda bütün sütunlar dönerdi ve bazı
satırlar tekrarlanırdı, fakat UNION bu şekilde çalışmaz. Sorgunuzda ALL anahtar sözcüğünü
kullanmadıkça (UNION ALL şeklinde) tekrarlayan satırlardan sadece birisi dönecektir.
UNION’la ikiden çok tablodan da veriler çekilebilir:
UNION
UNION
Not: Veritabanında global bir nesne olarak kalıcı mevcudiyeti olan bir tabloda veriyi geçici
olarak tuttuğunuz zaman, çakışmanın olması muhtemeldir. Union’ların çok kullanıcılı ayarlarında bu
çakışma potansiyeli çok daha fazladır. Böyle bir çakışmanın olmamasının garanti edilmesinin en basit
yolu yerel geçici tablolardır. Sade kilitleme (locking) stratejileri bu gibi çakışmaları önlemeye yetmez.
Not: Union’larla çalışırken geçici tabloları yerel olarak oluşturursanız veriyi kullanmak ve
tabloyu silmede bir sorunla karşılaşmazsınız. Burada dikkat edilecek konu zamanlamadır. Union’daki
veriyi dondurmuş oluyorsunuz ve bu donmuş (değişiklikleri göstermeyen) veriyle çalışıyorsunuz. Ve
bunu yenilemeniz gerekir. Eğer yenilemeyi unutursanız zamanı geçmiş verilerle uğraşmış olabilirsiniz.
Eğer veritabanınız bir view’da union’ı destekliyorsa, onla çalıştığınız müddetçe veriyi güncelleme işini
idare etmesini view’a verebilirsiniz. Bununla beraber bütün veritabanları bir view’ı belirten sorguda union
operatörünü kullanmayı desteklemez.
KİLİTLER VE ÇAKIŞMA
Çakışma bütün veritabanı sistemleri için çok önemli bir konudur. Bu, hepsi de aynı anda aynı
nesneyle etkileşime çalışan iki ya da daha fazla kullanıcıyı belirtir. Bu etkileşimin niteliği her kullanıcı
için ayrı olabilir. Nesnelerin kontrolü için yarışı engellemenin ideal yolu, sadece tüm kullanıcıların soruda
ne yaptıklarına ve olayların ne kadar önemli olduğuna bağlı olarak değişir.
Veritabanıyla çakışmalı ilişkinin temelinde kilitleme işlemi vardır. Kilitler, o nesne üzerinde
çakışan iki işlemi önleme mekanizmasıdır. Bu, eğer başka birisi ilk olarak o nesneye erişmişse sizin o
nesne üzerinde çalışamayacağınız demektir. Ne yapıp ne yapamayacağınız başka birisinin ne yaptığına
bağlıdır. Bu ayrıca neyin yapıldığının belirtilmesidir. Böylece sistem ikinci işlemin ilk işlemle uyumlu
olup olmadığını bilir. Örneğin 1,2,10,100,1000 veya daha başka sayıda kullanıcı bağlantısını tutabilen
sistemler genellikle bütün hepsinde, aynı veri kısmını aynı anda sadece salt-okunur temelinde paylaşıma
açarlar. Şeffaf bir dükkanınız olduğunu düşünün. Bir çok kişinin aynı anda aynı şeye baktığını ve
almadığını varsayalım. Eğer birden fazla kişi aynı anda mal almaya kalkarlarsa karkaşa çıkabilir.
Dükkancı genellikle ilk önce kimin ele alınacağına karar verir.
SQL Server Lock Manager da bu “dükkancıdır”. SQL Server dükkanına girdiğiniz zaman lock
manager size amacınızın ne olduğunu sorar. Eğer sadece göz atmak derseniz, lock manager içeri
girmenize izin verir. Eğer satın almak (update veya delete) isterseniz lock manager orada herhangi birinin
olup olmadığını kontrol eder. Varsa, biraz beklemeniz gerekecektir. Sizin girmenize izin verilince de
başkaları bekleyecektir.
Mümkün çakışma problemleri ve her birini önleyecek ayırma seviyelerini inceleyelim:
KİLİTLERLE HANGİ ÇEŞİT PROBLEMLER ÖNLENEBİLİR?
4 tane büyük problem vardır: *Bozuk okumalar *Tekrarlanamayan okumalar *Aldanışlar
*Kayıp güncellemeler.
Her biri ayrı problemler kümesini belirtir ve transaction isolation level’ın uygun ayarlarını içeren
çözümlerle de ele alınır.
Bozuk Okumalar: Bozuk okumalar, transaction henüz tamamlanmayan başka bir transaction’ın
bir parçası olan bir kayıdı okuduğu zaman ortaya çıkar. Eğer ilk transaction normal bir şekilde
tamamlanırsa muhtemelen problem olmaz. Fakat, eğer transaction geri alınırsa ne olur? Veritabanı
açısından hiçbir şeyin yapılmadığına dair bir bilgi alırsınız. Bir örnek inceleyelim:
BEGIN TRAN 3
ROLLBACK UPDATE 3 5
anything SET
SET whatever
= @var
Burada Transaction 2, geçerli olmayan bir değeri kullanmış oluyor. Eğer geri dönmeyi ve bu
sayının nereden geldiğini bulmaya çalışırsanız, hiçbir iz kalmadan ve büyük bir başağrısı ile bitirirsiniz.
Ama bu senaryo, SQL Server’ın varsayılan transaction isolation level’ını (READ COMMITTED)
kullandığınız zaman başınıza gelmez.
Tekrarlanamayan Okumalar: Tekrarlanamayan okuma, bir transactiondaki kayıdı iki kez
okumaya çalıştığınızda ve bu aralıktaki veriyi ayrı bir transaction değiştirmeye çalıştığında meydana
gelir. Örnek verirsek:
UPDATE Employees
GO
Ayrıca:
* Schema stability lock (Sch-S), schema modification lock (Sch-M) haricindeki bütün kilitlerle
uyumludur.
* Sch-M bütün kilitlerle uyumsuzdur.
* Bulk update (BU) sadece schema stability ve diğer bulk update kilitleriyle uyumludur.
Shared: Bu şekil, en temel kilitleme şeklidir. Paylaşılmış bir kilit sadece veriyi okumanız
gerektiğinde (hiçbir şey değiştiremezsiniz) kullanılır. Paylaşılmış bir kilit diğer paylaşılmış kilitlerle
uyumludur.
Paylaşılmış kilitler diğer kilitlere oranın dışında olduğunuzu anlatır. Anlamsız olsa da henüz onu
gözardı edemezsiniz.
Update: Update kilitleri, shared kilitleri ve exclusive kilitleri arasında bir melez yapıdır. Update
kilitleri sadece shared kilitleriyle uyumludur ve shared kilitlerine eğilimlidirler. Yani daha önceden
üzerinde bir update kilidi olan kaynağa update kilidi yerleştiremezsiniz.
Bir update kilidi, yer tutmanın özel bir çeşididir. Bir UPDATE yapmak için sadece hangi satırları
güncelleyeceğinizi hesaplayacağınız WHERE cümleciğinizi (bir tane olduğunu farz edersek) tasdik
etmeye ihtiyacınız vardır. Yani, gerçekten fiziksel güncelleme yapıncaya kadar sadece bir shared kilidine
ihtiyacınız vardır. Fiziksel güncelleme sırasında, bir exclusive kilide ihtiyacınız olacak.
Update kilitleri, tam olarak neyin güncelleneceğini hesaplamak için verinin başlangıç taramasını
yaptıktan sonra bir exclusive kilidi olacak bir shared kilidine sahip olduğunuzu gösterir. Bu, bir
güncelleme için 2 ayrı aşamanın olduğu gerçeğini onaylar: İlki, WHERE cümleciği kriteriyle neyin
buluşacağını neyin güncelleneceğini hesaplayacağınız aşaması (Bu, bir update kilidine sahip bir update
sorgusunun parçasıdır). İkincisi, update kilidinin bir exclusive kilidine gerçekten dönüşüp
dönüşmeyeceğine karar verme aşamasıdır. Diğer durumda, kilit bir shared kilidine dönüşür. Bu,
deadlock’ın bir çeşidine karşı bir engel oluşturması açısından çok iyidir. Deadlock bir kilit çeşidi değildir,
bir çelişkinin oluştuğu bir durumdur. Bir kilit, başka bir kilit kaynağı tuttuğu için bir şey yapamaz.
(Problem, kaynağın ilk transaction’da temizlemek (clear) için kilit bekliyor olarak saplantıda olmasıdır)
Update kilitleri olmazsa bu problem beklenmedik bir anda ortaya çıkabilir. 2 update sorgusu
shared mod’da koşuluyor olacak. A sorgusu sorgusunu tamamlar ve fiziksel güncelleme için hazırdır. Bir
exclusive kilidine dönüşmek ister, fakat olamaz. Çünkü B sorgusu sorgusunu bitiriyordur. B sorgusu o
zaman, (fiziksel güncelleme yapma ihtiyacı haricinde) sorgusunu bitirdi. Bunu yapmak için, B sorgusu bir
exclusive kilidine dönüşmelidir. Fakat dönüşemez. Çünkü A sorgusu halen bekliyordur. Bu bir çıkmaz
veya bir deadlock oluşturur.
Bunun yerine bir update kilidi diğer update kilitlerini kurulmuş olmadan önler. 2. transaction bir
update kilidini başarmaya çalıştığı zaman, onlar bir bekleme durumuna koyulacaklar, kilit kabul
edilmeyecek. Eğer ilk kilit, kilit timeout’una ulaşmadan önce temizlenirse, o zaman kilit yeni istekler için
kabul edilecek ve işlem devam edilebilecektir.Eğer öyle olmazsa bir hata üretilecektir.
Exclusive: Exclusive kilitleri tam olarak isminden anlaşıldıkları gibidirler. Exclusive kilitleri
diğer hiçbir kilitle uyumlu değildirler. Eğer diğer kilitler mevcutsa ulaşılamazlar. Exclusive kilidi hâlâ
aktif olduğunda kaynak üzerinde oluşturulması için yeni bir kilit çeşidine izin vermezler. Bu, 2 kişinin
aynı anda güncellemesini, silmesini… önler.
Intent: Intent kilidi, gerçek bir yer tutacağıdır. Bu, nesne hiyerarşisi konusunun başarılması
anlamına gelmektedir. Bir satırda bir kilit kurulmuş olduğu bir durumu düşünün, fakat birisi bir sayfada
bir kilit kurmak istiyor veya bir tabloyu değiştirmek istiyor.
Intent kilidi olmadan, yüksek seviyeli nesne sizin daha düşük seviyede bir kilide sahip
olduğunuzu asla bilemez. Intent kilitleri performansı arttırır. (SQL Server, bir işlemin tüm tabloyu
güvenli olarak kilitleyip kilitleyemeyeceğini hesaplamak için sadece tablo seviyesinde intent lock’larını
incelemeye ihtiyaç duyar ve tablodaki her satır veya sayfa kilidini kontrol etmez)
Intent kilitlerinin 3 farklı çeşidi vardır:
Intent Shared: Bir shared kilidi, hiyerarşide bazı düşük noktalarda sağlanır. Örneğin bir sayfada
satır seviyesinde shared lock uygulanmış olsun. Bu çeşit kilit sadece tablolara ve sayfalara uygulanır.
Intent Exclusive: Düşük seviye öğesinde yer alacak bir exclusive kilidi hariç Intent Shared
gibidir.
Shared with Intent Exclusive: Bir shared lock, düşük nesne hiyerarşisini kurar. Fakat intent veriyi
değiştirmek içindir. Böylece bazı noktalarda o, bir intent exclusive olacaktır.
Schema: 2 çeşittir:
Sch-M: Bir plan değişikliği nesneye uygulanır. Sch-M kilidi süresince bu nesneye karşı hiçbir
sorgu, CREATE, ALTER, DROP deyimleri çalıştırılamaz.
Sch-S: Bu kilidin tek amacı, nesnede aktif olan CREATE, ALTER, DROP ve diğer sorgulara
Sch-M kilidi sağlamaktır. Diğer bütün kilitlerle uyumludur.
Bulk Load: Bu kilit, tablo kilidinin değişik bir biçimidir. Tek önemli fark, tablo kilidinin
cause/source ‘una işarettir (BCP aracı veya DTS tabloya veriyi bulk copy yapar).
ÖZEL BİR KİLİT TİPİ BELİRTMEK
Bazen sorgunuzda veya bütün transaction’ınızda kilitlemeyle ilgili daha fazla kontrol
isteyebilirsiniz. Bunu “optimizer hint” leri kullanarak yapabilirsiniz. Optimizer hint, SQL Server’a bir
kilidi özel bir seviyeye yükseltmesini açıkça anlatmanın bir yoludur.
Hint Açıklama
SERIALIZABLE / Transaction’daki bir deyimle bir kilit kuruldu mu, o kilit transaction bitmeden
HOLDLOCK (ROLLBACK veya COMMIT ile) o kilit serbest bırakılmaz. Eğer eklenen kayıt, kilidi
kuran sorgudaki WHERE ifadesindeki kriteri de sağlıyorsa eklemeler de önlenmiştir.
Bu en yüksek ayırma seviyesidir ve verinin tam kararlılığını garanti eder.
READUNCOMMITTED Hiçbir kilit sağlamaz (shared lock bile) ve diğer kilitleri kabul etmez. Çok hızlı
/ NOLOCK olmasına rağmen bozuk okumalar gibi problemlere sebep olabilmektedir.
READCOMMITTED Varsayılandır. Bütün kilitleri kabul eder. Ayırma seviyesindeki READ COMMITTED
ile aynı şekilde çalışır.
REPEATABLEREAD Transaction’daki bir deyim tarafından bir kilit kuruldu mu, o kilit transaction bitinceye
kadar serbest bırakılmaz. Bununla beraber, yeni veri eklenebilir.
READPAST Silmek (clear) için bir kilidi beklemektense bütün kilitli satırları atlar. Atlama satır
kilitleriyle sınırlandırılmıştır (hâlâ sayfa, extent ve tablo kilitleri için bekler) ve
yalnızca SELECT deyimiyle kullanılabilir.
ROWLOCK SQL Server 6.5 için, ekelemeler için sayfa kilitleri yerine düşük seviye kilitlemeyi
kullanacağını belirtir. 7.0 için ise, optimizer sahip olacak olsa bile kilidin ilk seviyesini
satır seviyesinde olmaya zorlar, aksi halde daha az parçalı kilitleme stratejisi seçilir.
Eğer kilitlerin sayısı sistemin kilit üst sınırına erişmişse kilidin daha az parçalı
seviyeye yükselmesini önlemez.
TABLOCK Tüm tabloyu kilide zorlar. Gerçekten, bilinen tablonun tarama durumunu hızlandırır,
fakat, eğer diğer kullanıcılar tablodaki veriyi değiştirmek isterlerse büyük rekabet
problemleri oluşturur.
TABLOCKX TABLOCK’a benzerdir fakat exclusive lock oluşturur (Tablonun dışındaki bütün diğer
kullanıcıları deyim veya TRANSACTION ISOLATION LEVEL’ın nasıl
ayarlandığına bağlı olarak transaction süresince kilitler).
UPDLOCK Shared lock yerine update lock kullanılır. Bütün kullanıcıların shared lock edinmesine
izin verir. Fakat, deyim veya transaction bitinceye kadar hiçbir veri değişikliği
yapılmamasını sağlar.
Bunları kullanmak çok basittir (tablo isminden veya alias’tan sonra eklenir). Yapı şöyledir:
FROM <table name> [AS <alias>] [[WITH] (<hint>)]
Örnekler verirsek:
SELECT * FROM Orders AS ord WITH (TABLOCKX)
Bu örneklerin hepsi de aynı işi yaparlar. Birden çok tablolu bir örnek incelersek:
Burada Orders tablosu exclusive kilide zorlanır.Fakat, Order Details tablosuna hiçbir çeşit özel
kilit yerleştirilmez (SQL Server lock manager hâlâ bu tablonun tam kontrolünü elinde tutmaktadır).
Örneğin, Pubs veritabanındaki her bir başlığı, fiyatını, ve bazı satış karşılaştırma verisini listeleyen bir
rapor oluşturmak, her başlık için ortalama fiyatı göstermek isteyebilirsiniz. Bunu yapmak için aşağıdaki
kodu yazmanız yanlış olur:
SELECT title, price, AVG(price) FROM titles
GROUP BY deyimi, ortalama fiyatın başlık grubuna göre hesaplanmasına neden olur. Sonuç
olarak price ile average price’ın her ikisi de aynı değere sahip olmuş olur.
Bu problemleri gidermek için bir alt sorgu (subquery) kullanmalısınız:
SELECT title, price, (SELECT AVG (price) FROM titles) AS AveragePrice FROM
titles
Bu sorguyu çalıştırdığınız zaman doğru ortalama değerini elde edersiniz. Burada alt sorgu,
yalnızca grup için hesaplanan aggregate fonksiyonlarını ana sorguda kullanmaya zorlayan GROUP BY
deyimini içerme ihtiyacını ortadan kaldırır.
Alt sorguların, SQL sorguları yazmada önemli bir yeri vardır. Akılda tutmanız gereken tek kural
ise alt sorguların parantez içinde yazılacağıdır. Sonuçlar bir kayıt kümesinde ortaya çıkacağı zaman,
sonuçlara AS kullanarak iyi bir isim vermelisiniz.
BİR ÖĞE SEÇMEK
Asıl sorguda içerilmesi için öğe alan alt sorgular kesin kurallara uymalıdır. Alt sorguların
parantez içinde yazılması gerekir (böylece SQL çözümleyici, ona ayrı varlık olarak davranır). Ayrıca
parantezlerin içinde, herhangi bir verilmiş sade sorguya uygulanacak kurallara da uymalıdır. Eğer
gruplarsanız sorgu da gruplamaya uymalıdır. Tipik olarak seçilmiş sonuçları isimlendirmek için AS
kullanırsınız. Böylece sonuçları programınızda işleyebilirsiniz. Bununla beraber bu gibi alt sorgular tek
bir değer döndürmelidir. Aksi halde hata mesajı alırsınız. Tam merkezil (superordinate) bir sorguya dahil
etmek için bir öğe alıyorken, SELECT deyiminiz sadece ve sadece bir değer döndürmelidir. SELECT
deyiminiz birden çok değer döndürebileceği durumlarda, sonuçları tek bir değere sınırlamak için
DISTINCT veya TOP anahtar kelimelerini kullanmalısınız. Sorgu kendi kendini tıpki sütun ismiymiş gibi
tam merkezil sorgu tarafından seçilen öğeler listesine yerleştirir.
Eğer, alt sorgunun içindekileri ana sorgudaki bazı değerlere ilişkilendirmek istiyorsanız alt
sorguda WHERE ifadesini kullanmanız gerekir. WHERE ifadesindeki bir koşul, alt sorgudaki bir sütun
değerini ana sorgudaki bir sütun değerine eşitlemelidir. Aşağıdaki örnek, öğrencilerin listesi ile onların
kullandıkları, portfolio tablosundaki evrak çantalarının sayısını döndürür:
KOŞULLARI AYARLAMAK
Koşulları ayarlamak için alt sorguları WHERE veya HAVING ifadesi içinde de kullanabilirsiniz.
Bu durumda 3 seçenek vardır. İfadenin, değer döndüren bir ilişkiye sahip sabit bir değer mi yoksa ana
sorgudaki bir sütun mu olduğunu görmek için kontrol edeceği, yalnızca ve yalnızca tek değer dönüren alt
sorgu kullanabilirsiniz. Ana sorgudaki sütun değerleriyle ilişkili alt sorgudan dönen değeri kontrol etmek
için ilişkisel operatör kullanabilirsiniz:
Bu sorgu, evrak çantası bulunan öğrencilerin isimlerini döndürür. Alt sorgu, her bir öğrenci için
evrak çantası sayısını döndürür. Sonuç olarak alt sorgu ana sorguyla ilişkilidir, bu yüzden kayıt
kümesindeki her bir kayıt, sadece ve sadece bir öğrenciyle ilişkili olarak döndürülür.
Koşulu belirlemek için IN anahtar sözcüğünü de kullanabilirsiniz. Örnek olarak, aktif evrak
çantasına sahip öğrencilerin bir listesini almayı düşünün. Burada dikkat etmeniz gereken, sistemde evrak
çantasına sahip olan, ana sorgu tarafından döndürülen öğrencilerden emin olmanız gerektiğidir. Portfolio
tablosundaki bütün Student_ID’lerin bir listesini döndürmek için alt sorgu kullanabilirsiniz. Bu kayıt
kümesini aşağıdaki biçimde, uygun koşulu ayarlamak için kullanabilirsiniz:
Bu, daha sade gözükmektedir. Fakat, JOIN mantığının içinde sorgunun icrasının nasıl
gerçekleştirildiğine dikkat edin. Student_ID’nin her iki tabloda da bulunması gerektiğinden aktif evrak
çantasına sahip olan öğrencileri listemize ekleyen doğal bir filtre elde etmiş olduk.
JOIN’lerle (özellikle içi içe kullanılan) alt sorgular arasında bir tercih yapmanız gerekirse
(JOIN’lerin mantığı daha karışık olduğu için) alt sorguları seçmeniz daha uygundur.
Tip: Bazen (özellikle saniyede bir çok işlem yapan büyük veri tabanlarında) join’i kullanmakla
alt sorguları kullanma arasındaki performans farkını bilmek istersiniz. Alt sorgular, join’lere göre
index’leri kullanmada daha az etkilidir. Eğer performans önemliyse en hızlı seçeneği seçmeniz gerekir.
SİLME, GÜNCELLEME ve EKLEME
Alt sorgular diğer SQL deyimleriyle de kullanılabilir. Örneğin bir DELETE deyiminde alt
sorguyu, hangi kayıtların silineceğini belirlemek için WHERE ifadesinin içinde kullanabilirsiniz:
DELETE FROM Student WHERE NOT EXISTS (SELECT Portfolio_ID FROM Portfolio WHERE
Portfolio.Student_ID = Student.Student_ID)
Not: Ayrıca, sütunu güncelleştirmek için bir veri elde etmede UPDATE içinde bir alt sorgu
kullanabilirsiniz. Alt sorgu, ayarlanacak (SET) sütunların listesinde eşittir işaretinin sağına yazılabilir.
INSERT deyimi biraz farklı çalışır. Alt sorguyu isterseniz koşulu belirtmek için WHERE
ifadesinde kullanabilirsiniz. Alt sorgunun daha tipik kullanımı ise, eklenecek değerlerin bir listesini
sağlamadaki kullanımıdır:
Burada, her bir öğrenci için evrak çantası sayısını elde etmek için JOIN ve GROUP BY da
kullanabiliriz:
Bunun gibi durumlarda, sorgu arkasındaki mantığı size en doğal şekilde ifade eden sorgu çeşidini
kullanmalısınız.
Not: Alt sorgudaki bir gruplamanın ana sorgudaki gruplamaya tesir etmesini önlemek için alt
sorgudaki değerlerin, ana sorgudaki kritik gruplamayı belirlemediğinden emin olmanız gerekir.
VIEW OLUŞTURMAK
Şimdiye kadar veritabanı tablosunu bilgi depolamada birincil ünite olarak kabul etmiştik.
Tablolar, bireysel veri öğeleri için saklama yerini belirten satır ve sütunlara sahiptirler. Tabloda saklanan
veriyi gözden geçirmek isterseniz tabloyu sorgularsınız. Birden çok tablodaki verileri görmek isterseniz
sorgularınızda join kullanırsınız.
Yalnız tablolara güvenmek uygun metoddur. Bununla beraber tabloya göz atması gereken
kullanıcılarınız olduğunda, az miktarda endişelenebilirsiniz. Uzun zaman bir iş üzerinde çalışan bütün
veritabanı yöneticilerinin, (birisinin tabloya bakarken hata yapmasından dolayı) hiç olmazsa en az bir tane
yedek banda başvurma hikayesi vardır. Böyle hatalara karşı korumanız, veritablosuna direk erişildiğinde
kullanmak için sınırlı haklara, güncelleme ve silme haklarına sahip özel bir login’i kullanıcılara
sağlamaktır. Bu yaklaşımın en belirgin sınırlaması ise çoğu kullanıcıların doğru kimlik ile logout ve
logback yapmadaki tembelliklerinden dolayı tabloya direk erişimin sınırlanmasıdır.
Bir view bir tabloya benzer. Fakat veritabanında fiziksel bir mevcudiyeti yoktur. Bir view, bir
kullanıcının ulaşma isteği gerektiğinde oluşturulur. Sonuç olarak bir kullanıcı view’a erişince o andaki
verilere göre tablo yapısını görür. View’lar, oluşturma, yaşatma ve işi bitince silme gereksinimi olmayan
geçici tablolar gibidir. View, tablo yapısının temelini oluşturduğu için view’da güvenliği
ayarlayabilirsiniz. Veriye, (gözden geçirmek için) salt okunur erişimi garanti altına almak istiyorsanız,
view’ı salt okunur olarak belirtebilirsiniz. Burada kimin kullandığı önemli değildir, view, doğasında salt
okunur olarak kalır. Özel login kullanılacağından endişelenmenize gerek yoktur.
Not: View’lar, tablolar gibi veritabanında kalıcı fiziksel mevcudiyeti olmadığı için genellikle
sanal tablolar olarak adlandırılır.
VIEW’IN KULLANIMINI DÜZENLEMEK
View’lar bazı sınırlamalara sahiptir. İlk olarak, onlara ulaşıldığında isteğe bağlı olarak
oluşturulurlar. View oluşturma işlemi, view’a erişen sorgu için sorgu icra planına birleştirilmiş olmalıdır.
Sonuç olarak, benzer sorguların koşulmasını karşılaştırdığımız zaman, view’a erişen sorgu icra planının
biraz daha fazla yapacağı iş vardır. İkinci olarak, her ne zaman bir view bir view’a erişse artırma için
performans gecikmesi beklersiniz. Query optimizer en iyi icra planını kurmada çok iyi olsa bile plan,
view#2’nin sonuçları görüntülemesinden önce view#1’in görüntülemesi gerektiği gerçeği ile
bağdaşmalıdır. 2. view’da veri döndürülebilmesi için ilk view’da sorgunun icrasındaki bağımlılık bir dizi
olay kümesini icra planına dahil eder. Bazı örneklerde gecikmeler bir dizi problem oluşturur.
View’lar arası bağımlılıklar, query optimizer’ın çözmesi için ilginç problemler oluşturur. Kendi
kendilerine bağımlılık kalıtsal bir problem değildir. Bununla beraber, bağımlılıklar belirli öz yinelemeyi
icra planına soktuğu zaman gecikmeler olur. Şunu anlamalısınız ki: her veritabanının query optimizer’ı
bir programcı olarak size kara kutu niteliğindedir. Önceden ne olacağını kestirmek için iyi
donatılmadığınızdan sadece view’ları ve sorguları dikkatlice planlayabilir ve onların performansını
dikkatlice test edebilirsiniz.
Bunun gibi muhtemel problemlerle view’lar tehlikeli gözükebilir. Yine de view’lar gerçekte çok
kullanışlıdırlar. İhtiyacınız olan sadece onların gizli tehlikelerinin farkında olmak ve onları gereği gibi
nasıl yönetileceğini bilmektir. İlk olarak avantajları düşünelim:
Temel sorgu join içerebileceği için birden çok tablodan veri gösterebilirsiniz.
Kolayca veriye salt-okunur erişim sağlayabilirsiniz.
Bir view kullanarak tablodaki değerlere göz atabilirsiniz. Ardından da, o değerlerin başka bir
sorguyla ilgili olup olmadığını doğrulamak için IN kullanabilirsiniz.
View kullanarak değerlere göz atabilirsiniz ve bir sorgu içinde o değerleri içermek için view
ile bir join de kullanabilirsiniz.
View’ları kullanırken birkaç pratik önlemi almanız gerekir. View’ların tablo ile veritabanı
kullanıcısı arasına bir ara katman soktuğunu hatırlamanız gerekir. Bu ara katman tablolarınız için koruma
sağlar, bununla beraber performanstan da yoksun bırakır. Bu yüzden şu uyarıları dikkate almanız gerekir:
Mümkün olduğu kadar basit bir view belirten sorguyu tutun. Eğer sorgunun çalışması uzun
zaman alıyorsa, view’ınız kullanılmadan önce gerçekleşmek için uzun zaman alacaktır.
View’ları kullanan view’ları kullanan view’lardan kaçının. Maalesef, view’ları referanslayan
view’lar genellikle çok kullanışlıdırlar.
View’ları test ve optimize edin. Yavaş işleyen bir view’ı tespit etmeden, acele ederek
oluşturduğunuz zaman oluşabilecek büyük süprizlerden kaçının.
View’ları bir tablodaki, (performans düştüğünde view’ın sonuçlarını tanımlayabilen) küçük
alanlarla birleştirin.
VIEW OLUŞTURMAK
View oluşturmak için CREATE VIEW deyimini kullanmanız gerekir. Yapısı şöyledir: CREATE
VIEW tabloadi [(sütun1, sütun2, …)] AS sorgu [WITH CHECK OPTION]
Bu deyim büyük ölçüde INSERT INTO’ya benzemektedir. VIEW anahtar sözcüğüden sonra
view’ınıza bir isim verirsiniz. Sonuç tablosunda kullanmak için sütun isimleri listesi içerebilirsiniz. Eğer
isimler içermezseniz, temel tablodaki sütun isimleri kullanılacaktır. Query ise, çoktan oluşturduğunuz ve
test ettiğiniz SELECT deyimidir.
Geri kalan yapı elemanları sadece güncellenebilir olmasını istediğiniz view’lara uygulanır.
View’ınızın güncellenebilir olması için veritabanınızın güvenlik düzenini kullanarak ona güncelleme izni
vermeniz gerekir. SQL, birden çok tabloda çapraz güncellemeye izin vermediği için, view sadece ve
sadece bir tabloya dayandırılmalıdır. (Bazı veritabanları izin verebilir) View’ınızın güncellenebilir
olduğunu farz ediniz. WITH CHECK OPTION, view’ı belirten sorgudaki WHERE koşullarını eşlemek
için güncellemeyi zorlar.
Aşağıdaki yolla bir view belirtebiliriz:
StudentPortfolio view’ı, değer içeren StudentID sütununa sahip kayıtların bir listesini içerir. Eğer
view’ı güncellenebilir yaparsak view’da şu güncellemeyi de yapabiliriz:
Bu güncelleme çalışır ve view’dan bütün kayıtları siler. (Kayıtların hiç biri artık view’ı belirten
WHERE koşuluna uygun olmayacaktır.) Biz daha çok güncelleme izni vermeyi tercih ederiz, fakat
view’dan bir kayıt silecek olan güncellemenin çalışmamasını isteriz. Aşağıdaki yöntemle bir view
belirttiğimizi düşünelim:
Bu örnekte birden çok tablodan veriler JOIN’lerle birleştirilerek (ve adlandırılarak) alınıyor ve WHERE
koşuluyla sipariş tarihi dün olan kayıtlar seçiliyor.
VIEW’LARI ŞİFRELEME
View’ınızı şifrelemek için bütün yapmanız gereken WITH ENCRYPTION seçeneğini
kullanmaktır. Burada dikkat etmeniz gereken husus, WITH ENCRYPTION ifadesini view’ın isminden
sonra, AS ifadesinden önce kullanmak ve WITH ENCRYPTION ile OPTION anahtar sözcüğünü
kullanmamaktır.
ALTER VIEW deyimiyle, erişim hakları dışında var olan view’ın bütün ayarlarını
değiştirebilirsiniz. Bu, şifrelemenin zaten değiştirildiği anlamına gelir. Eğer ALTER VIEW yapılırken
şifrelenmesini de istiyorsanız ALTER VIEW’da WITH ENCRYPTION ifadesini kullanmanız gerekir.
WITH ENCRYPTION seçeneğini kullanmadan önce kaynak kodunuzu bir yerde saklamanız
gerekir. Bir kere şifrelendikten sonra daha geri almazsınız. Eğer bir yerde saklamamışsanız ve
değiştirmeniz gerekirse en başından yeniden yazmak zorunda kalırsınız.