Bir projede kurulum yaparken tüm tabloları temizlemem gerekiyor. Tek tek elle yapsam olmaz, tablo adlarını bir diziye aktarıp truncate etsem saçma olur. Bunun için information_schema’ı kullanarak tabloları çektim ve döngüye sokarak temizleme işlemi yaptım. Yani sql sorgum şöyle;
SELECT CONCAT("TRUNCATE TABLE ", table_schema, ".", TABLE_NAME, ";") FROM INFORMATION_SCHEMA.TABLES WHERE table_schema IN("db_adi", "db_adi2")
Burada concat ile değerleri birleştirince tüm tablolarıma ait otomatik truncate kodu çıkmış oldu. Şimdi bunu php ile birleştirdiğimizde;
<?php // pdo db bağlantı işlemleri ..
$query = $db->query('SELECT CONCAT("TRUNCATE TABLE ", table_schema, ".", TABLE_NAME, ";") FROM INFORMATION_SCHEMA.TABLES WHERE table_schema IN("mvc")')->fetchAll(PDO::FETCH_ASSOC);
foreach ($query as $row){ echo $db->query(current($row))->fetch(); }
Not: Eğer SQLSTATE[42000]: Syntax error or access violation hatası alıyorsanız, foreach’den önce yani sorguları çalıştırmadan önce FOREIGN_KEY_CHECKS değerini 0’a eşitleyip deneyin. Yani;
<?php // pdo db bağlantı işlemleri ..
$query = $db->query('SELECT CONCAT("TRUNCATE TABLE ", table_schema, ".", TABLE_NAME, ";") FROM INFORMATION_SCHEMA.TABLES WHERE table_schema IN("mvc")')->fetchAll(PDO::FETCH_ASSOC); $db->query('SET FOREIGN_KEY_CHECKS=0')->fetch(); foreach ($query as $row){ echo $db->query(current($row))->fetch(); }
İşte bu kadar ???? Benim hazırladığım BasicDB sınıfında ise son versiyonunu indirdikten sonra şu şekilde kullanmak yeterli;
<?php // basicdb bağlantı işlemleri .. $db->truncateAll();
Bu metod içerisinde AUTO_INCREMENT değerleride 1’den başlayacak şekilde ayarlanıyor. Dilerseniz kendi şu sql sorgusu ile tablolarınızın başlangıç değerlerini de ayarlayabilirsiniz.
ALTER TABLE `db_adi`.`tablo_adi` AUTO_INCREMENT = 1; # 1 ya da kaçtan başlayacaksa o
Farkındayım başlık çok uzun oldu ???? Ancak benim işime yaradığı gibi bir gün sizinde işinize yarayabilir. Şimdi örnek vermek gerekirse, yorumlar tablonuz olsun. Yorumların bazıları onaylı, bazıları onaysız olarak kayıt edilmiş. Ve siz toplam yorum sayısını, onaylı yorum sayısını ve onay bekleyen yorum sayısını bir sorguda almak istiyorsunuz. Mantıken nasıl yaparsınız? Ya subquery kullanırsınız ya da bunun yerine SUM() fonksiyonun kullanırsınız. Hemen bir örnek verelim.
Eğer count() fonksiyonunu kullanırsak;
SELECT count(yorum_id) toplam FROM yorumlar;
Sonuç;
+--------+
| toplam |
+--------+
| 2052 |
+--------+
Şimdi SUM() fonksiyonu ile birlikte şöyle bir kullanım yapacağız. Örneğin onay 1 ise onaylı yorumları, 0 ise onaysız yorumları saydıracağız.
Son olarak, eğer birden fazla tabloyu join ile bağladıktan sonra count işlemi yaptığınızda rakamlar saçmalıyorsa DISTINCT ile benzersizleri toplamak gerekir. Ama onun kullanımı biraz daha karışık, şöyle bir kullanım gerektiriyor;
Bu makalede sizlerle MySQL’de trigger’ların nasıl kullanıldığını ve amacını konuşacağız. Eğer MySQL’de neden trigger kullanmalıyım sorusuna cevap arıyorsanız kendinize şu soruyu sormanız gerek. Herhangi bir insert, update ya da delete işleminden sonra bir işlem yaptırmak ister miydiniz? Benim anlatacağım senaryoda, posts adında bir tablom olsun. Bu tabloda makalelerimi tutuyorum. Ve makaleyi güncellediğimde, eski versiyonunu revisions tablosuna post id’si ile birlikte kaydetmek istiyorum.
İşte tam olarak bu aşamada bir trigger yazmamız gerek tabi eğer bu işlemi mysql’de çözmek istiyorsak. Yok arkadaş ben PHP’de if ($insert) ise o zaman şuraya $db->query() yazarım diyorsan o senin ameleliğin olur, bir şey diyemem ????
Şimdi gelelim bu trigger’ları oluşturmak nasıl oluyor. Temel anlamda bir trigger’ın ihtiyacı olan syntax şudur;
DELIMITER $$
CREATE TRIGGER [trigger_adi] [BEFORE|AFTER] [INSERT|UPDATE|DELETE] ON [tablo_adi]
FOR EACH ROW
BEGIN
-- işlemler
END$$
DELIMITER ;
Burada DELIMITER $$ ve kısımları, mevcut delimiter’ı $$ ile değiştirmemizi yarıyor. Çünkü defualt olarak ; (noktalı virgül) olduğundan biz trigger içinde herhangi bir noktalı virgül kullanınca kodlar patlıyor. Bu yüzdendir ki bir bütün olarak yorumlanması için delimiter’ı değiştirip $$ yapıyoruz ve END kısmının bitişine noktalı virgül yerine $$ koyuyoruz.
Şimdi gelelim bizim senaryoya. Tablomuz posts tablosuydu ve kolonlarımız id, title ve content olsun. Birde revisions diye bir tablom vardı aynı şekilde id, post_id, title, content, created_at kolonlarına sahip olsun. Şimdi ben posts tablosunda bir veri güncellendiğinde, eski halini revisions tablosuna kaydedecek bir trigger yazmak istiyorum. Nasıl yazarım?
DELIMITER $$
CREATE TRIGGER after_post_update AFTER UPDATE ON posts
FOR EACH ROW
BEGIN
IF NEW.title != OLD.title OR NEW.content != OLD.content THEN
INSERT INTO revisions SET post_id = OLD.id, title = OLD.title, content = OLD.content;
END IF;
END$$
DELIMITER ;
Burada OLD ve NEW diye anahtarlar gördünüz. Eğer INSERT için trigger yazıyorsak sadece NEW, UPDATE için yazıyorsak OLD ve NEW, DELETE için yazıyorsak sadece OLD anahtarlarını kullanarak eski ve yeni değerlere ulaşabiliyoruz. Yani trigger’daki OLD.title, update olmadan önceki title değerini, NEW.title update olduktan sonraki title değerini temsil ediyor. Dolayısı ile biz trigger’da şunu yaptık, eğer eski başlık yeni başlıktan farklı ise ya da eski içerik yeni içerikten farklı ise o zaman revisions tablosuna bunu kaydet.
Mevcut trigger’ları görmek isterseniz şu komutu kullanabilirsiniz;
Merhaba arkadaşlar, bu yazımda ve videomda sizlere LIKE dışında kullanabileceğiniz 2 alternatifi göstermek istiyorum. Öncelikle neden ne için kullanmamız gerek onu bir açıklayayım.
Örnek vermek gerekirse sizin bir e-ticaret siteniz olsun. Ve kullanıcı ürün aramak için arama input’une iphone yazıp arattı. Ama oda ne? Bir başka kullanıcı iphone yazmayı beceremedi ve “iphon” ya da “iphom” gibi kelimeler yazdı. Bu durumda sizin şu basit mysql sorgunuz ne döndürecektir sizce?
SELECT * FROM products
WHERE brand LIKE '%iphom%'
Ben söyleyeyim, hiçbir veri bulunamayacak. Eğer kullanıcı “ipho” yazıp bıraksaydı bulunabilirdi ama “iphom” yazınca “iphone” kelimesinden bağımsız bir hal aldı. Ama baktığınızda kulağa hala iphone gibi geliyor değil mi? İşte bu kulağa gelene göre arama yapmak istersek SOUNDS LIKE ve SOUNDEX kullanmamız gerekecek. Şimdi gelelim bu arkadaşlara..
SOUNDS LIKE
Bunu türkçede “.. gibi geliyor” olarak çevirebiliriz. Örnek bir sorgu yapalım.
SELECT * FROM products
WHERE brand SOUNDS LIKE 'iphome'
Bu sorgunun sonucunda iphone markası altında bir ürün var ise gelecektir. Ancak SOUNDS LIKE’ın bir dezavantajı var, eğer kullanıcı “ipho” yazıp aratırsa SOUNDS LIKE çalışmaz çünkü tam olarak kelime kadar yazıp kelimeleri yanlış yazarsanız çalışıyor. Yani mevcut kelimeyi bir şeye benzetemediği için bulamıyor. Bu bağlamda SOUNDS LIKE bize arifeyi gösterdi, ama bayramı göstermedi..
Ama durun! daha bitmedi. Sizin sorununuzu çözecek arkadaş, birkaç yardımcı fonksiyon kullanımıyla SOUNDEX olacak. Ama önce gelin bu SOUNDEX nedir bir anlayalım..
SOUNDEX
SOUNDEX sesin İngilizce telaffuzundan sonra isimleri endekslemek için kullanılan fonetik bir algoritmadır. Yani kelimeleri belli bir algoritmada aramamızı sağlıyor. Şimdi örnek vermek gerekirse;
SELECT SOUNDEX('iphone'), SOUNDEX('iph');
Bu sorguyu çalıştırdığımızda bize I150 ve I100 değerlerin verecek. O zaman “iphone” ifadesinin SOUNDEXdeğeri I150 imiş. Şimdi “iph” kelimesinin ise I100’müş. Aslında burada 0’ları kaldırdığımızda I1 kalıyor. Yani “iphone” kelimesinin I150 SOUNDEX değeriyle başlangıç değerleri aynı. Yani iki ifade birbiriyle uyuşuyor demek oluyor. O zaman sorguyu yazmadan önce mysql’de TRIM fonksiyonunu kullanarak 0 değerini kaldırmayı öğrenelim.
SELECT TRIM(TRAILING '0' FROM 'I100')
Bu sorgu bize sonuç olarak I1 değerini döndürecek. TRAILING ifadesi “sondaki” demektir. Yani sondaki “0” değerlerini kaldırmış olduk. Şimdi bunları toplayıp sorgumuzu yazalım.
SELECT * FROM products
WHERE SOUNDEX(brand) LIKE CONCAT(TRIM(TRAILING '0' FROM SOUNDEX('iphome')), '%');
Not: CONCAT() fonksiyonu 2 ifadeyi birleştirip tek ifade haline getirmek için kullanılıyor.
Sonuç olarak kullanıcınız “iphome” yazdığında iphone markasına ait ürünleri listeleyecek bu sorgumuz. Kullanıcı “iphone”,”ivhone”, “iphane”, “iphano” gibi ifadelerle arama yapsada yine de inatla “iphone” markasına ait ürünler listelenecektir.
Bu yazımda sizlere mysql’de json olarak depoladığımız veriler üzerinde listeleme, arama, düzenleme gibi işlemler nasıl yapılır bunlardan bahsetmek istiyorum. Eğer JSON ile uğraşıyorken aklınıza NoSQL veritabanları geliyorsa haklısınız, ancak mysql’de de bir takım işlemler yapabildiğimizi unutmamak lazım ????
Öncelikle neden JSON olarak veri depolarız? Ben kendi adıma konuşacak olursam, örneğin seo bilgilerini json formatında tutuyorum. Yani title, description, keywords ama yarın öbürgün ekstra bir bilgi daha ekleyebilirim örneğin noindex, canonical vb. Bunun için sürekli gidip kolon oluşturmak tamamen saçmalık olurdu. Bu yüzden tüm bu değerleri tek bir kolon altında json formatında tutuyorum. Ve yeri geldiğinde bunları filtrelemek, bunlar içinde arama yapmak gerekirse değiştirmek, listelerken ayrı ayrı göstermek isteyebilirim.
İşte bu noktada mysql’de bazı fonksiyonlar bize yardım edecek. Alışılmışın dışında bir sorgu yazıyormuşuz gibi görünsede, aslında ne kadar kolay olduklarını birazdan anlayacaksınız ????
JSON Veri Eklemek
Biz aslında PHP tarafında json_encode() fonksiyonu ile dizileri ya da objeleri json haline getirerek ekleyebiliyoruz. Örnek vermek gerekirse;
Bu iki fonksiyon json formatının doğruluğunu kontrol eder. JSON_TYPE’da geriye ARRAY, OBJECT ya da hata mesajı döner. JSON_VALID’de ise format doğru ise 1 değil ise 0 döner. Kullanımı ise;
-- dönen değer ARRAY:
SELECT JSON_TYPE('[5, 7, "erbilen.net"]');
-- dönen değer OBJECT:
SELECT JSON_TYPE('{"ad": "tayfun", "soyad": "erbilen"}');
-- dönen değer hata mesajı:
SELECT JSON_TYPE('{"ad": "tayfun", "soyad": "erbilen"');
-- dönen değer 1:
SELECT JSON_VALID('[5, 7, "erbilen.net"]');
-- dönen değer 1:
SELECT JSON_VALID('{"ad": "tayfun", "soyad": "erbilen"}');
-- dönen değer 0:
SELECT JSON_VALID('{"ad": "tayfun", "soyad": "erbilen"');
JSON içinde Arama
JSON verileri depoladıktan sonra önemli olan onlar içerisinde belli bir düzende arama yapıp onları listelemektir. Bunun için birkaç yararlı fonksiyonu inceleyeceğiz;
Bu fonksiyon ile JSON içerisinde istediğimiz şeyin olup olmadığını kontrol ediyoruz. Örneğin array’de bir değer ya da obje’de bir key value gibi. Hemen örneklendirelim;
# kolon_adi = {"ad":"tayfun","soyad":"erbilen"}
SELECT * FROM tablo_adi
WHERE JSON_CONTAINS(kolon_adi, '{"soyad": "erbilen"}');
Yukarıdaki örnekte kolon_adi kolonunda depolanan json değerler içerisinde soyad objesi olup değeri erbilen’e eşit olanlar listelenecektir.
SELECT * FROM tablo_adi
WHERE JSON_CONTAINS(kolon_adi, '[2]');
Yukarıdaki örnekte ise kolon_adi kolonunda depolanan array içerisinde 2 değeri olanlar listelenecektir.
Bu fonksiyon ile JSON olarak depoladığımız değerlerin path’leri bulmanızı sağlıyor. İlk parametresi JSON değeri, ikinci parametresi ise all ya da one olarak belirlenmeli. all derseniz eğer aradığınız değer birden fazla ise hepsini döndürür one derseniz sadece ilkini döndürür. 3. parametre ise aradığınız değer olarak belirlenmeli. Örneğin;
SELECT JSON_SEARCH(kolon_adi, 'all', 'soyad') FROM tablo_adi
# Örnek çıktı: ["$[0]", "$[1].deneme"]
JSON_EXTRACT()
Bu fonksiyon ile json pathlerini belirleyerek işlem yapabiliyoruz. Örneğin json veri içerisinde soyad’a sahip olanları listelemek istersek;
SELECT * FROM test_tablo
WHERE JSON_EXTRACT(test_kolon, '$.soyad')
Bu örnekte test_kolon içerisinde aşağıdaki gibi bir json saklandığını farz ediyoruz.
JSON Path’leri herhangi bir fonksiyon yardımı olmadan da sorgularda kullanabiliriz. Bunun için tablo_adi->’$.path’ şeklinde bir kullanım söz konusu. Yukarıdaki kullanım şekillerini baz alabilirsiniz.
SELECT kolon_adi->'$.ad' as ad FROM tablo_adi;
# ya da
SELECT * FROM tabo_adi
WHERE kolon_adi->'$.ad' = 'tayfun';
JSON Verilerini Düzenleme
Bu işlem için birkaç fonksiyon var.
JSON_REPLACE()
İlk parametresi json verisi, 2. parametresi path yani yolu, 3. parametresi ise yeni değeri. Daha sonrasında path, value, path, value şeklinde devam ederek kullanılabilir.
UPDATE tablo_adi
SET kolon_adi = JSON_REPLACE(kolon_adi, '$.uye.ad', 'Tayfun')
JSON_SET()
JSON_REPLACE ile aynıdır. Kullanımlarıda aynı şekildedir.
JSON_INSERT()
JSON verisine yeni değerler eklemek için kullanılıyor. Örneğin;
UPDATE tablo_adi
SET kolon_adi = JSON_INSERT(kolon_adi, '$.adsoyad', 'Tayfun Erbilen')
WHERE id = 2
JSON_REMOVE()
JSON verisinden değer silmek için kullanılıyor. Örneğin;
UPDATE tablo_adi
SET kolon_adi = JSON_REMOVE(kolon_adi, '$.adsoyad')
WHERE id = 2
Bu makalemizde buraya kadardı ????
Eğer daha fazla merak ettiyseniz mysql’in kendi döküman sayfasından devamını inceleyebilirsiniz.
Aslında bu komik bir soru, ancak bir çok kişi tarafından aratılmış ve bende şöyle bir aratıp sonuçlara baktığımda çok güzel sonuçlar göremediğim için ufak bir yazı yazmak istedim. İngilizce olarak “what’s difference between sql and mysql” diye arattığımda, çok güzel bir örnek karşıma çıktı. Bunu sizlerle paylaşmak istiyorum.
SQL uzun haliyle Structured Query Language yani Yapılandırılmış Sorgu Dili demektir. Basit tanımıyla, veritabanı içindeki depolanan verilere ulaşmak ve onlar üzerinde işlem yapmak için kullanabileceğimiz bir dildir.
MySQL ise, bir üründür ve (RDMS * Relational Database Management System) İlişkisel Veritabanı Yönetim Sistemlerinden biridir. MySQL haricinde Oracle, Informix, Postgres ve MSQL‘de aynı şekilde birer üründür ve veritabanı yönetim sistemidir.
Tüm bu ilişkisel veritabanı yönetim sistemleri dil olarak SQL’i kullanır. Her birinin kullandığı SQL dilinde küçük farklılıklar olsada temelde hepsi SQL’i kullanmaktadır.
Bunu gerçek hayattan bir örnekle açıklamak gerekirse, Türkiye’de konuşulan dil Türkçe’dir. Ancak bazı şehirlerde şive’ede değişiklikler olur. Yine de temelinde konuşulan dil Türkçe’dir.
Yani Türkçe’ye SQL dediğimizde, bazı şehirler ise veritabanı yönetim sistemleri olsun. Bütün RDMS’ler aynı dili konuşuyor sadece şiveleri farklı o kadar.
Umarım basitçe anlaşılır olmuştur ???? Sizinde bu konuda üstüne katmak istediğiniz bilgiler olursa lütfen çekinmeden yorum bırakın.
30 günden eski içerikleri silmek büyük projelerde işimize yarayacaktır. Ben genelde öyle yapıyorum, çok önemli içerik depolanmıyorsa anlık olarak kullanıcıyı ilgilendiren içerikler ise belli aralıklarla bu sorguyu çalıştırıp 30 günden eski içerikleri veritabanınızda boşu boşuna yer kaplamaması için silebilirsiniz.
DELETE FROM tablo_adiniz
WHERE tarih_alani_adiniz < DATE_SUB(NOW(), INTERVAL 1 MONTH);
Kırmızı yere tablo adınızı, yeşil yere de tabloda tarihi tuttuğunuz alanın adını yazıp çalıştırmanız yeterli sorguyu.
İsterseniz 10 günlük, 15 günlük.. x günlük şeklinde de içerik silebilirsiniz. O zamanda INTERVAL 1 MONTH yerine INTERVAL x DAY olacak.
Mesela 15 günlük içeriği silelim;
DELETE FROM tablo_adiniz
WHERE tarih_alani_adiniz < DATE_SUB(NOW(), INTERVAL 15 DAY);
Güncelleme: MySQL Event Scheduler (olay zamanlayıcısı) ile bu işlemi otomatikte yaptırabiliriz. Şu sorguyu çalıştırmamız yeterli;
SET GLOBAL event_scheduler = ON;
DELIMITER $$
CREATE EVENT clearLog
ON SCHEDULE EVERY ‘1’ MONTH
STARTS ‘2011-05-01 00:00:00′
DO
BEGIN
DELETE FROM tablo_adiniz WHERE tarih_alani_adiniz < DATE_SUB(NOW(), INTERVAL 1 MONTH);
END$$
DELIMITER ;
Sorgu yaparken koşulun yerine gelip verinin gösterilmesinde büyük-küçük harf duyarlılığı olmasını istiyorsanız BINARY operatörünü kullanmanız gerekiyor.
Örnek bir sorgu;
SELECT * FROM uyeler WHERE uye_ad = 'tayfun erbilen'
Aynı sorgunun büyük-küçük harfe karşı duyarlı olanı;
SELECT * FROM uyeler WHERE BINARY uye_ad = 'tayfun erbilen'