“SELECT forum_topics.*,COALESCE(threads_table.hits,’0′) as hits, COALESCE(posts_table.post_hits,’0′) as post_hits,last_thread.date_updated, last_thread.username as updater_usernameFROM forum_topicsLEFT JOIN (SELECT COUNT(*) AS hits, topic_idFROM forum_threads GROUP BY topic_id) AS threads_tableON threads_table.topic_id=forum_topics.idLEFT JOIN (SELECT SUM(posts_table_.hits) as post_hits, posts_table_.topic_idFROM (SELECT COUNT(*) AS hits, forum_posts.thread_id, forum_threads.topic_idFROM forum_postsLEFT JOIN forum_threadsON forum_threads.id=forum_posts.thread_idGROUP BY thread_id) AS posts_table_GROUP BY posts_table_.topic_id) AS posts_tableON posts_table.topic_id=forum_topics.idLEFT JOIN (SELECT last_thread_.topic_id, last_thread_.date_updated, users.usernameFROM(SELECT tt.topic_id, tt.date_updated, tt.last_updaterFROM (SELECT forum_threads.topic_id, forum_threads.date_updated, forum_threads.last_updaterFROM forum_threadsORDER BY date_updated DESC) AS ttGROUP BY tt.topic_id) as last_thread_LEFT JOIN usersON users.id=last_thread_.last_updater) as last_threadON last_thread.topic_id=forum_topics.idWHERE is_active=1 AND is_deleted=0 ORDER BY forum_topics.id”;
Yazının sonundaki sql sorgusunu üzerinde çalıştığımız projede yer alacak forum uygulamasını geliştirmekteyken yazdım.Benim için baya öğretici 1 – 2 saat sonunda bu uzun ve karmaşık görünen, sql sorgusunu anlatmak istedim. Paylaşma sebebim emin olmamakla birlikte böylebir sorgunun performans açısından faydalı olduğunu düşünmem. Konuyla ilgili olarak okuyanların geri dönüşlerini bekliyorum.Sorgunun ilk hali 1., 5. ve 36. satırlardan oluşmaktaydı ve ilk halinde yalnızca forum_topics adlı tablodaki forumların listesini getiriyordu.Sonra forum ana başlıklarını listelerken her bir başlığın altında kaç tane konu olduğunu basmamız gerekti. alt başlıklar forum_threads adlı tabloda bulunuyordu ve bağlı oldukları forumlar topic_id ile belirleniyordu . 7. ve 10. satırlar arasındaki sorgu bize bunu veriyor. Burada öncelikle 8.,9. satırlardaki topic_id lerine göre gruplandırılmış alt başlıkları (forum_threads) sayarak topluyor ve bunları threads_table ismi ile bir kenara koyuyoruz. Sonra da 10. satırda threads_table tablosundan ilgili datayı alıyoruz.Burada dikkat edilmesi gereken şey 8. satırda seçtiğimiz hücreler ve isimlerinin artık threads_table tablosuna atanmış olmalarıdır. Parantez içindeki sorgunun sonucu mysql tarafından bir tablo olarak görünür ve bu tablolar bir üst sorguya AS kullanılarak isimlendirilerek aktarılır. Yani 8. ve 9. satır daki sorgunun sonucu threads_table tablosu oldu. 10. satırda da threads_table tablosu ile temel tablomuz olan forum_topics tablosunu eşleştirdik.Diğer sorgularda da benzer durumlar söz konusu fakat daha fazla alt sorgu içermekteler. Hepsindeki ortak nokta her sorgu, üst sorguyla ilişkili olan hücreyi taşıyor olmalarıdır. 8., 13., 24. satırlarda topic_id hücresinin istendiğini görebilirsiniz. bu hücre forum_topics tablosundaki id hücresi ile LEFT JOIN … ON alanında eşleştirilecek olduğundan çekilmelidir (eğer select * kullansaydık belirtmeye gerek kalmazdı ama dikkat ederseniz count ve group öğeleri fazlası ile kullanılmış durumda).12. – 21. satırlar arasında ise ilgili forum altındaki toplam gönderim sayısı bulunmuştur. 15.-16. da her alt başlığın sahip olduğu gönderim sayısı bulunmuş 19. satırda bunlar başlıklara göre gruplandırılmıştır. 17. ve 18. satırlada forum_threads tablosunun left join ile taşınmasının sebebi topic_id bilgisinin forum_posts tablosunda bulunmamasıdır. her post’un thread ini oradan da topic ini bulduk. 20. de 13. de istenen bilgileri topic_id ye göre gruplayıp posts_table adı ile 1. seviyedeki sql sorgumuza taşıdık.Önemli bir nokta daha: tablo ve hücre isimleri yalnızca kendi seviyelerindeki sorgularda kullanılabilir!. bunu bir sonraki öbekte daha detaylı görebilirsiniz.23. – 34. satırlarda foruma son gönderim yapan kullanıcıyı bulmaya çalışıyoruz. Burada programcı arkadaşımız forum_threads tablosunda son gönderim yapan kullanıcıyı ve tarihi belirtmiş. bu yüzden işimiz biraz daha kolaylaşıyor. 28. – 30. satırlarda alt başlıkları tarihe göre sıralıyoruz çünkü bir üst sorgudaki GROUP BY öğesi gruplama yaparken beraberinde ilk rastladığı bilgileri taşımakta. Bu yüzden sorgumuzla son güncellenen alt başlığı ilk hücreye taşıyoruz (30. ORDER BY). sonrasında bu sorgumuzu bir üst sorguya tt adı ile aktarıyoruz. sonra tt tablomuzu 31. de topic_id ye göre grouplayıp bir üst sorguya last_thread_ adı ile aktarıyoruz. Şimdide 32. de users tablosu ile kullanıcı bilgilerini last_thread_ tablosuna ekleyip 34. satırda bütün bunları ana sorgumuza ekliyoruz.Böylelikle 4 farklı tablodaki bilgileri birinci tabloya aktara bildik.COALESCE nedir diye soran olursa diye belirteyim. COALESCE(deger1, deger2, …) şeklinde kullanılıyormuş. bende yeni öğrendim. NULL olmaya ilk değeri veriyor. Değerleri ekrana bastırırken boş yerine 0 basmak istemiştik. bu yüzden bunu kullandık.