Sayfalar

PHP ve Veritabanı Bağlantıları - 11


SQL Yapilari ve Tablodan Istenilen Verinin Elde Edilmesi

Mysql istemcinizi acin ve bu bolumde yapacagimiz SELECT sorgu yapilarini ogrenin.Bir cok onemli yapi bu makalede orneklerle anlatilacaktir.Ilk olarak SELECT SQL yapisi ile ilgili bir kac hatirlatma yapmak istiyorum.Birincisi bu SQL komutu bir veritabani tablosuna ve/veya bir veritabanina ihtiyac duymaz.SELECT komutu verinin dondurulmesi icin kullanilir.Unutmayin burada yapacagimiz ornekler tamamiyle PHP fonksiyonlari yardimiyla da sunucu uzerinde uygulanabilir.(Bunun nasil yapildigini genis olarak onceki yazilarimizda acikladik.)

Biz simdilik MySQL istemcisini sorgularimizi gerceklestirmek icin kullaniyoruz ama sonucta onemli olan sorgu yapisinin kendisi.Nerede ve hangi teknigi kullanarak onu veritabani uzerinde uyguladiginiz degil :)

MySQL Veritabani Sunucusu cok fazla yapisal fonksiyon icerir.Buna bir ornek vermek gerekirse, saatinizi evde unuttugunuzu farzedin.Bunu MySQL sunucundan nasil ogrenebiliriz?

Iste cevap :

    mysql> SELECT now();
    +---------------------+
    | now() |
    +---------------------+
    | 2001-10-01 15:34:48 |
    +---------------------+
    1 row in set (0.11 sec)

Yukaridaki ornekte goruldugu gibi now() hazir fonksiyonu ile sunucu uzerindeki zaman verisini dondurmus oldum.now () fonksiyonu o andaki gecerli zamani dondurur.Eger gecerli tarih ve gecerli saati ayri ayri dondurmek istiyorsaniz curdate () ve curtime() fonksiyonlarini kullanabilirsiniz :

Tarih :

    mysql> SELECT curdate();
    +------------+
    | curdate() |
    +------------+
    | 2001-10-01 |
    +------------+
    1 row in set (0.00 sec)

Zaman :

    mysql> SELECT curtime();
    +-----------+
    | curtime() |
    +-----------+
    | 15:38:35 |
    +-----------+
    1 row in set (0.00 sec)

veya beraberce :

    mysql> SELECT curdate(),curtime();
    +------------+-----------+
    | curdate() | curtime() |
    +------------+-----------+
    | 2001-10-01 | 15:39:36 |
    +------------+-----------+
    1 row in set (0.00 sec)

MySQL hazir fonksiyonlari hemen hemen PHP ile ayni sekilde calisir.Bazi degisiklikler elbette vardir.Ornegin PHP'deki substr () fonksiyonu yerine MySQL'de hazir fonksiyon olarak substring () kullanilir.PHP sifirdan (0) saymaya baslarken ornegin MySQL hazir fonksiyonu birden (1) baslayarak sayar.Bir ornek vermek gerekirse :

    mysql> SELECT substring('test',1,1);
    +-----------------------+
    | substring('test',1,1) |
    +-----------------------+
    | t |
    +-----------------------+
    1 row in set (0.06 sec)

Bu islemin PHP'deki esiti asagidaki gibidir :

    $degisken_parcasi = substr('test',0,1);

Bir tablo alanindaki veriyi dondurmek

Simdiye kadar bir tablodan veriyi dondurmeyi gorduk.Peki yanlizca tablonun bir alanindaki veriyi dondurmek istersek ne yapabiliriz?

Bunun icin asagidaki gibi bir SQL sorgusu hazirlayip veritabani uzerinde uygulamak yeterlidir :

    mysql> SELECT kullaniciadi FROM kullanicilar;
    +--------------+
    | kullaniciadi |
    +--------------+
    | ahmet |
    | hikmet |
    | memis |
    | oktay |
    | serkan |
    | tayfun |
    +--------------+
    6 rows in set (0.22 sec)

Iki farkli alanaki veriyi dondurmek icin, alanlari virgul (,) ile ayirmak gereklidir :

    mysql> SELECT kullaniciadi,gercekadi FROM kullanicilar;
    +--------------+---------------------+
    | kullaniciadi | gercekadi |
    +--------------+---------------------+
    | serkan | Serkan Hadi Ceylani |
    | oktay | Oktay Altunergil |
    | tayfun | Tayfun Ulu |
    | memis | Memis Cetinkaya |
    | hikmet | Hikmet Gumus |
    | ahmet | Ahmet Yazici |
    +--------------+---------------------+
    6 rows in set (0.06 sec)

Tablodaki butun alanlardaki veriyi dondurmek icin (*) yildiz isareti kullanilmalidir :

    mysql> SELECT * FROM erisim;
    +-------------------------+--------------+---------------+----------------+
    | sayfa | kullaniciadi | ziyaretsayisi | erisimtarihi |
    +-------------------------+--------------+---------------+----------------+
    | /headbangers/index.html | serkan | 9 | 19990921123155 |
    | /index.html | oktay | 2 | 20000511161120 |
    | /index.html | tayfun | 8 | 20000522163110 |
    | /php/myscript.php | tayfun | 5 | 20000713220144 |
    | /php/myscript.php | memis | 1 | 20000826071502 |
    | /who.html | serkan | 6 | 19991123172000 |
    +-------------------------+--------------+---------------+----------------+
    6 rows in set (0.11 sec)

Donen Veriyi Belirli Limitlere Bolmek

LIMIT ve WHERE anahtar kelimeleri ile donen sonuc belirli limitlerde istenebilir.Boylece ornegin sifirdan baslayarak ilk iki sonucun dondurulmesini asagidkai gibi bir sorgu ile gerceklestirebilirsiniz :

    mysql> SELECT kullaniciadi,gercekadi FROM kullanicilar LIMIT 0,2;
    +--------------+---------------------+
    | kullaniciadi | gercekadi |
    +--------------+---------------------+
    | serkan | Serkan Hadi Ceylani |
    | oktay | Oktay Altunergil |
    +--------------+---------------------+
    2 rows in set (0.00 sec)

Aslinda sorgu icinde (eger tablonun basindan itibaren ilk iki sonucu istiyorsaniz) sifirin kullanilmasina gerek yoktur.Asagidaki gibi bir sorgu da tamamen ayni isi gorecektir.Boylece siz eger "0" notasyonunu yazmaz iseniz o kendiliginde baslangic degerini sifir alacaktir :

    mysql> SELECT kullaniciadi,gercekadi FROM kullanicilar LIMIT 2;
    +--------------+---------------------+
    | kullaniciadi | gercekadi |
    +--------------+---------------------+
    | serkan | Serkan Hadi Ceylani |
    | oktay | Oktay Altunergil |
    +--------------+---------------------+
    2 rows in set (0.00 sec)

Baska bir dusunce ile yanlizca "Turkiye"de yasayan kullanicilarin secilmesi (secimin biizm istegime gore limitlenmesi) saglanabilir : Burada WHERE anahtar kelimesi kullanilarak sorgu hazirlaniyor.

    mysql> SELECT kullaniciadi,gercekadi FROM kullanicilar WHERE milliyeti = 'Turkiye';
    +--------------+--------------+
    | kullaniciadi | gercekadi |
    +--------------+--------------+
    | hikmet | Hikmet Gumus |
    +--------------+--------------+
    1 row in set (0.05 sec)

Operatorler

Sorgularda esitlik,buyukluk vb. istekleri saglayabilmek icin operatorler vardir.Simdi asagiya bu operatorlerin hepsini yaziyorum :

    = (Esittir)
    != veya <> (Esit Degildir)
    < (Bundan Kucuk)
    > (Bundan Buyuk)
    <= (Bundan Kucuk veya Esit)
    >= (Bundan Buyuk veya Esit)

NULL degeri karsilatirilamaz.Yanlizca NULL'mu degilmi diye bakilabilir.NULL degeri = veya != gibi operatorlerle karsilastirmayiniz.Bunun yerine IS NULL veya IS NOT NULL notasyonlari ile alandaki degerin NULL olup olmadigina bakiniz.

Simdi de LIMIT ve WHERE anahtar kelimelerini beraber kullanarak bir sorgu yaratalim.Bu sorgumuzda "Amerika Birlesik Devletlerinde" yasayan ilk kullanicimizi ogrenmek isteyelim :

    mysql> SELECT kullaniciadi,gercekadi FROM kullanicilar WHERE milliyeti = 'Amerik
    a Birlesik Devletleri' LIMIT 1;
    +--------------+---------------------+
    | kullaniciadi | gercekadi |
    +--------------+---------------------+
    | serkan | Serkan Hadi Ceylani |
    +--------------+---------------------+
    1 row in set (0.00 sec)

Onemli NOT : LIMIT anahtar kelimesi her zaman en sonda yer alir

Coklu secimler AND ve OR mantiksal opratorleri ile yapilabilir : (Ingilizce AND "ve" anlamina OR ise "veya" anlamina gelmektedir.)

    mysql> SELECT kullanicinumarasi,kullaniciadi,milliyeti FROM kullanicilar WHERE m
    illiyeti = 'Ingiltere' OR milliyeti = 'Amerika Birlesik Devletleri' AND kullanic
    inumarasi < 5;
    +-------------------+--------------+-----------------------------+
    | kullanicinumarasi | kullaniciadi | milliyeti |
    +-------------------+--------------+-----------------------------+
    | 1 | serkan | Amerika Birlesik Devletleri |
    | 2 | oktay | Amerika Birlesik Devletleri |
    | 4 | memis | Amerika Birlesik Devletleri |
    | 6 | ahmet | Ingiltere |
    +-------------------+--------------+-----------------------------+
    4 rows in set (0.06 sec)

Yukarida cok onemli bir durum soz konusudur.Buraya iyi dikkat etmenizi oneriyorum.Sorguda goruldugu gibi "kullanicinumarasi" 5'den kucuk olan kayitlar istenmektedir.Yanliz dikkat ederseniz sonuc setinde halen 6 kullanici numarasina sahip bir kullanici bulunmaktadir.Sizce ne oldu dersiniz?MySQL hata mi yapiyor? Hayir.Biz sorguyu hazirlarken bazi seyleri goz onunden bulundurmaliyiz.Bunlaradan ilki sorgu devam ederken daha "kullanicinumarasi < 5" ifadesine gelinmeden ilk sarta gore (yani 'Ingiltere') zaten MySQL tablodan veri secimini yapmistir.Bu nedenle "kullanicinumarasi < 5" sarti yanlizca (milliyeti='Amerika Birlesik devletleri') satirina uygulanir.yani secilmis bir veriyi diger sart bunu saglamiyor diye geri alamazsiniz...

Eger yukaridaki gibi bir durumun olusmasini istemiyorsaniz "parantezlerle" sorgunuza bir anlama katabilirsiniz :

    mysql> SELECT kullanicinumarasi,kullaniciadi,milliyeti FROM kullanicilar WHERE (
    milliyeti = 'Ingiltere' OR milliyeti = 'Amerika Birlesik Devletleri') AND kullan
    icinumarasi < 5;
    +-------------------+--------------+-----------------------------+
    | kullanicinumarasi | kullaniciadi | milliyeti |
    +-------------------+--------------+-----------------------------+
    | 1 | serkan | Amerika Birlesik Devletleri |
    | 2 | oktay | Amerika Birlesik Devletleri |
    | 4 | memis | Amerika Birlesik Devletleri |
    +-------------------+--------------+-----------------------------+
    3 rows in set (0.00 sec)

Donen Sonuclari Siralamak

Donen sonuclari belirli bir alana gore siralamak istiyorsaniz ORDER BY anahtar kelimesini kullanabilirsiniz :

    mysql> SELECT kullanicinumarasi,kullaniciadi,milliyeti FROM kullanicilar WHERE k
    ullanicinumarasi < 5 ORDER BY kullaniciadi;
    +-------------------+--------------+-----------------------------+
    | kullanicinumarasi | kullaniciadi | milliyeti |
    +-------------------+--------------+-----------------------------+
    | 4 | memis | Amerika Birlesik Devletleri |
    | 2 | oktay | Amerika Birlesik Devletleri |
    | 1 | serkan | Amerika Birlesik Devletleri |
    | 3 | tayfun | Turkiye Cumhuriyeti |
    +-------------------+--------------+-----------------------------+
    4 rows in set (0.05 sec)

Onemli NOT : ORDER BY ile siralama yapilirken ASCII tablosuna gore yapilir.Bu nedenle kucuk harfler,buyuk harflerden sonra yer alir.

ORDER BY belirli bir alana gore siralamayi ongorulen olarak bastan sona dogru (Anahtar Kelime ASC kullanilarak) yapar.(Veya alfabede, alfabenin basindan sonuna dogru)Eger ters bir siralama yapmak istiyorsaniz DESC anahtar kelimesini kullanabilirsiniz.

    mysql> SELECT kullaniciadi FROM kullanicilar ORDER BY kullaniciadi DESC;
    +--------------+
    | kullaniciadi |
    +--------------+
    | tayfun |
    | serkan |
    | oktay |
    | memis |
    | hikmet |
    | ahmet |
    +--------------+
    6 rows in set (0.22 sec)

Birden fazla alana gore siralama ise su sekilde yapilabilir :

    mysql> SELECT kullaniciadi,gercekadi,milliyeti FROM kullanicilar WHERE milliyeti
    = 'Ingiltere' OR milliyeti = 'Amerika Birlesik Devletleri' ORDER BY milliyeti,k
    ullaniciadi DESC;
    +--------------+---------------------+-----------------------------+
    | kullaniciadi | gercekadi | milliyeti |
    +--------------+---------------------+-----------------------------+
    | serkan | Serkan Hadi Ceylani | Amerika Birlesik Devletleri |
    | oktay | Oktay Altunergil | Amerika Birlesik Devletleri |
    | memis | Memis Cetinkaya | Amerika Birlesik Devletleri |
    | ahmet | Ahmet Yazici | Ingiltere |
    +--------------+---------------------+-----------------------------+
    4 rows in set (0.22 sec)

Karekter Eslesmesi

LIKE ve NOT LIKE operatorleri ile veri uzerinde istenilen karekterlerin bulunup bulunmadigi kontrol edilebilir.Bu operatorler daha cok, web sitelerinin arama bolumlerinde kullanilmaktadir.

# % isareti ile verinin herhangi bir yerindeki eslesme (bos karekterler de dahil) daha cok DOS veya UNIX komut satirindaki * ile ayni gorevde,
# _ isareti ile tek bir karekter (daha cok DOS ve UNIX komut satirindaki ? ile ayni gorevde)

Ornegin "kullanicilar" tablosundaki "eposta" isimli alanda "turk-php.com" domain adina sahip eposta adreslerini listelemek istiyorum :

    mysql> SELECT kullaniciadi,gercekadi,milliyeti FROM kullanicilar WHERE eposta LI
    KE '%turk-php.com' ORDER BY gercekadi;
    +--------------+---------------------+-----------------------------+
    | kullaniciadi | gercekadi | milliyeti |
    +--------------+---------------------+-----------------------------+
    | oktay | Oktay Altunergil | Amerika Birlesik Devletleri |
    | serkan | Serkan Hadi Ceylani | Amerika Birlesik Devletleri |
    | tayfun | Tayfun Ulu | Turkiye Cumhuriyeti |
    +--------------+---------------------+-----------------------------+
    3 rows in set (0.06 sec)

Evet yukarida goruldugu gibi tabloda benim,oktayin ve tayfunun "turk-php.com" eposta adresi mevcuttur.Bu yazi yazildigi sirada gercekten de bu uc kullanici turk-php.com da admin olarak gorev yapmaktaydilar.Bu nedenle "kullanicilar" tablosunda email adresleri olarak turk-php.com adresleri gorunmekteydi...

Simdi de diger karekter olan "_" alt_cizgi ile ilgili bir ornek yapalim :

    mysql> SELECT kullaniciadi FROM kullanicilar WHERE kullaniciadi LIKE '___kan';
    +--------------+
    | kullaniciadi |
    +--------------+
    | serkan |
    +--------------+
    1 row in set (0.00 sec)

NOT LIKE operatoru LIKE ile tam zit olarak gorev yapar.Ornegin sorgu sonucunda belirli bir karkter grubunun gecmemesini istiyorsaniz :

    mysql> SELECT kullaniciadi FROM kullanicilar WHERE kullaniciadi NOT LIKE '___kan
    ';
    +--------------+
    | kullaniciadi |
    +--------------+
    | ahmet |
    | hikmet |
    | memis |
    | oktay |
    | tayfun |
    +--------------+
    5 rows in set (0.00 sec)

Tablo Alani Ile Ilgili Kisa Matematiksel Ozetler Almak
MySQL hazir fonksiyonlari kullanilarak bazen verinin kendisi degilde o alandaki veri ile ilgili hesaplanmis bazi ozet matematiksel sonuclarda dondurulebilir.Bunlar icin MySQL hazir fonksiyolari kullanilir :

# sum () sorgu sonucunda donen satirlarin tooplami
# max () verilen tablo alaninda yer alan en buyuk sayi
# min () verilen tablo alaninda yer alan en kucuk sayi
# avg () verilen tablo alaninda yer alan verilerin ortalamasi
# count () sorgu sonucunda donen satir sayisi

"sayi" (integer) veri tipinde veri saklayan bir alanda minumum ve maximum degerleri bulmak icin min () ve max () MySQL sunucu fonksiyonlari kullanilir :

    mysql> SELECT min(kullanicinumarasi), max(kullanicinumarasi) FROM kullanicilar;
    +------------------------+------------------------+
    | min(kullanicinumarasi) | max(kullanicinumarasi) |
    +------------------------+------------------------+
    | 1 | 6 |
    +------------------------+------------------------+
    1 row in set (0.05 sec)

Bir sorgu sonucunda donen satir sayisi count () fonksiyonu kullanilarak elde edilebilir :

# count(alanadi) olarak kullanilirsa verilen alandaki NULL olmayan satirlar,
# count(*) olarak kullanildiginda o alandaki butun satirlar sayilacaktir.

Ornegin 2000 yilindan once kayit yaptiran kullanicilari saymak icin soyle bir sorgu hazirlanabilir :

    mysql> SELECT count(*) FROM kullanicilar WHERE kayittarihi < '2000-01-01';
    +----------+
    | count(*) |
    +----------+
    | 4 |
    +----------+
    1 row in set (0.00 sec)