Sql & Veritabanı İle Dinamik Veri Filtreleme Sorgusu Nasıl Yapılır?

Sql & Veritabanı İle Dinamik Veri Filtreleme Sorgusu Nasıl Yapılır?
Sql & Veritabanı İle Dinamik Veri Filtreleme Sorgusu Nasıl Yapılır?

Giriş: Dinamik Veri Filtreleme Nedir ve Neden Önemlidir?

Modern web uygulamalarında kullanıcılar, veritabanındaki kayıtları kendi belirledikleri kriterlere göre listelemek isterler. Sql & Veritabanı ile dinamik veri filtreleme sorgusu nasıl yapılır sorusu, özellikle e-ticaret siteleri, raporlama araçları ve dashboard panelleri geliştiren yazılımcıların en temel ihtiyaçlarından biridir. Dinamik filtreleme, sabit bir SQL sorgusu yerine, kullanıcının gönderdiği parametrelere göre çalışma anında (runtime) şekillenen sorgular oluşturma sürecidir.

Bu makalede, PHP ve PDO (PHP Data Objects) kullanarak, SQL Injection gibi güvenlik açıklarına karşı korumalı ve ölçeklenebilir bir dinamik filtreleme yapısının nasıl kurulacağını öğreneceksiniz. Statik "WHERE" koşullarından kurtulup, esnek ve güvenli sorgular yazmanın profesyonel yöntemlerini adım adım inceleyeceğiz.

Gereksinimler ve Ön Hazırlık

Bu rehberdeki örnekleri uygulayabilmeniz için sisteminizde aşağıdaki bileşenlerin yüklü ve yapılandırılmış olması gerekmektedir:

  • PHP 8.2 veya üzeri: Güncel dil özellikleri ve performans iyileştirmeleri için.
  • MySQL 8.0 veya MariaDB 10.6+: JSON veri tipleri ve gelişmiş sorgu optimizasyonları için.
  • PDO Sürücüsü: Veritabanı bağlantılarında güvenli sorgu hazırlama (prepared statements) için zorunludur.
  • Temel SQL Bilgisi: SELECT, WHERE, AND/OR operatörleri hakkında temel bilgiye sahip olmanız beklenir.

Adım 1: Temel Veritabanı Yapısını Oluşturma

Dinamik filtreleme yapabilmek için öncelikle üzerinde işlem yapacağımız bir tabloya ihtiyacımız var. Bir "ürünler" tablosu üzerinden ilerleyeceğiz. Bu tablo; isim, kategori, fiyat ve stok durumu gibi filtreleme kriterlerini içerecek.

CREATE TABLE urunler (
    id INT AUTO_INCREMENT PRIMARY KEY,
    ad VARCHAR(255) NOT NULL,
    kategori VARCHAR(100),
    fiyat DECIMAL(10, 2),
    stok_durumu TINYINT(1) DEFAULT 1,
    eklenme_tarihi TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Bu tablo yapısı, filtreleme senaryolarımız için yeterli çeşitliliği sunmaktadır. Kategoriye göre listeleme, fiyat aralığı belirleme veya stokta olanları filtreleme gibi işlemleri bu tablo üzerinde gerçekleştireceğiz.

Adım 2: Dinamik Sorgu Oluşturma Mantığı

Dinamik filtrelemede en büyük hata, kullanıcıdan gelen veriyi doğrudan sorgu metnine (string) eklemektir. Bunun yerine, sorgu parçalarını bir diziye ekleyip, daha sonra implode() fonksiyonu ile birleştirmek en temiz yöntemdir. Ayrıca güvenlik için "Prepared Statements" kullanmalıyız.

$sql = "SELECT * FROM urunler WHERE 1=1";
$params = [];

if (!empty($_GET['kategori'])) {
    $sql .= " AND kategori = :kategori";
    $params[':kategori'] = $_GET['kategori'];
}

if (!empty($_GET['min_fiyat'])) {
    $sql .= " AND fiyat >= :min_fiyat";
    $params[':min_fiyat'] = $_GET['min_fiyat'];
}

Burada WHERE 1=1 kullanımı, sonraki tüm koşulların AND ile başlamasını kolaylaştıran bir tekniktir. Bu sayede ilk koşulun var olup olmadığını kontrol etme zahmetinden kurtuluruz.

Adım 3: Güvenli Sorgu Çalıştırma ve Parametre Bağlama

Sorgumuzu oluşturduktan sonra, PDO kullanarak veritabanına göndermemiz gerekir. Parametreleri doğrudan sorguya yazmak yerine, onları execute() metoduna dizi olarak göndermek SQL Injection saldırılarını tamamen engeller.

$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$sonuclar = $stmt->fetchAll(PDO::FETCH_ASSOC);

foreach ($sonuclar as $urun) {
    echo $urun['ad'] . " - " . $urun['fiyat'] . " TL
"; }

Bu yöntem, veritabanı sürücüsünün veriyi "veri" olarak kabul etmesini sağlar; verinin içindeki SQL komutlarını (örneğin OR 1=1) çalıştırmasını engeller.

Adım 4: Gelişmiş Filtreleme (Fiyat Aralığı ve Sıralama)

Kullanıcılar genellikle fiyat aralığı ve sıralama (artan/azalan) gibi karmaşık filtreler isterler. Dinamik yapımızı genişleterek bu özellikleri ekleyelim.

$siralama = in_array($_GET['sort'], ['fiyat_asc', 'fiyat_desc']) ? $_GET['sort'] : 'id_desc';
$order = ($siralama == 'fiyat_asc') ? "fiyat ASC" : "fiyat DESC";

$sql .= " ORDER BY " . $order;
// Not: ORDER BY kısmında değişkeni doğrudan kullanırken 
// mutlaka beyaz liste (whitelist) kontrolü yapmalısınız.

Sıralama parametreleri (ORDER BY) prepared statement ile doğrudan bağlanamaz. Bu yüzden yukarıdaki örnekte olduğu gibi, beklenen değerler dışında bir değer gelip gelmediğini kontrol eden bir "beyaz liste" mekanizması kurmak güvenlik için kritiktir.

Dinamik Filtreleme Yöntemlerinin Karşılaştırılması

Yöntem Avantaj Dezavantaj
String Birleştirme Basit ve hızlı SQL Injection riski çok yüksek
PDO Prepared Statements Güvenli ve standart Biraz daha fazla kod yazımı gerektirir
Query Builder (ORM) Okunabilir ve esnek Ekstra kütüphane bağımlılığı

Adım 5: Hata Yönetimi ve Debug İpuçları

Dinamik sorgular yazarken en sık karşılaşılan sorun, yanlış parametre isimleri veya eksik AND operatörleridir. Geliştirme aşamasında sorgunuzu ekrana yazdırmak (sadece geliştirme ortamında!) hataları bulmanızı kolaylaştırır.

// Sadece geliştirme ortamında kullanın!
if ($debug) {
    echo "Çalışan Sorgu: " . $sql;
    print_r($params);
}
Kritik Güvenlik Uyarısı: Üretim (production) ortamında asla veritabanı sorgularını veya hata mesajlarını kullanıcıya göstermeyin. Bu, veritabanı yapınızın ifşa olmasına yol açar. Hataları log dosyalarına yazdırın.

Sıkça Sorulan Sorular

Dinamik sorgularda "LIKE" operatörü nasıl kullanılır?

Kullanıcıdan gelen bir metin içinde arama yapmak için LIKE operatörü kullanılır. Parametreyi bağlarken yüzde işaretlerini (wildcards) PHP tarafında eklemelisiniz: $params[':ad'] = '%' . $_GET['ad'] . '%';

Çok fazla filtre olduğunda kod karmaşıklaşmıyor mu?

Evet, bu yüzden filtreleme mantığını ayrı bir sınıf veya fonksiyon içerisinde toplamak (Repository Pattern) en iyi yaklaşımdır. Sorgu oluşturma işlemini bir "Query Builder" sınıfına devretmek kodun okunabilirliğini artırır.

SQL Injection nedir ve neden bu kadar tehlikeli?

SQL Injection, saldırganın giriş alanlarına kötü niyetli SQL kodları yazarak veritabanınızdaki tüm verileri silmesi veya çalmasıdır. Prepared statements kullanmak bu açığı kökten çözen profesyonel standarttır.

Performans için neye dikkat etmeliyim?

Filtreleme yaptığınız sütunlara (kategori, fiyat gibi) veritabanı üzerinde mutlaka INDEX (indeks) ekleyin. İndeksler, veritabanının veriyi taramak yerine doğrudan bulmasını sağlar.

Tarih aralığı filtrelemesi nasıl yapılır?

Tarih aralığı için BETWEEN operatörünü kullanabilirsiniz. WHERE tarih BETWEEN :baslangic AND :bitis şeklinde bir yapı ile başlangıç ve bitiş tarihlerini parametre olarak göndermek en güvenli yoldur.

Dinamik Filtreleme İçin Repository Pattern Kullanımı

Dinamik filtreleme mantığını doğrudan controller veya view dosyalarınızın içinde tutmak, projeniz büyüdükçe kodun okunabilirliğini ve yönetilebilirliğini zorlaştırır. Bu karmaşıklığı aşmak için Repository Pattern kullanarak veritabanı işlemlerini iş mantığından ayırmalısınız.

Aşağıdaki örnekte, filtreleme parametrelerini bir dizi olarak alan ve dinamik SQL sorgusunu güvenli bir şekilde oluşturan bir sınıf yapısını inceleyebilirsiniz:

class ProductRepository {
    private $db;

    public function __construct($pdo) {
        $this->db = $pdo;
    }

    public function getFilteredProducts(array $filters) {
        $sql = "SELECT * FROM products WHERE 1=1";
        $params = [];

        if (!empty($filters['category_id'])) {
            $sql .= " AND category_id = :cat_id";
            $params['cat_id'] = $filters['category_id'];
        }

        if (!empty($filters['min_price'])) {
            $sql .= " AND price >= :min_price";
            $params['min_price'] = $filters['min_price'];
        }

        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}

Dinamik Sorgularda Performans Optimizasyonu ve İndeksleme

Dinamik filtreleme, özellikle milyonlarca satırın bulunduğu tablolarda yanlış yapılandırıldığında ciddi performans sorunlarına yol açabilir. Dinamik sorgularınızın hızlı çalışması için veritabanı tarafında şu stratejileri uygulamalısınız:

  • Composite Index (Bileşik İndeksler): Sıkça birlikte filtreleme yaptığınız sütunlar için (örneğin: category_id ve price) bileşik indeksler oluşturun.
  • EXPLAIN Kullanımı: Yazdığınız dinamik sorgunun başına EXPLAIN ekleyerek veritabanının sorguyu nasıl işlediğini analiz edin.
  • Sınırlı Veri Çekme: Dinamik sorgularınızda mutlaka LIMIT ve OFFSET kullanarak sayfalama (pagination) yapın. Tüm veriyi tek seferde çekmek bellek tüketimini artırır.

İndeksleme Stratejisi Örneği

Eğer kullanıcılarınız sürekli olarak kategori bazlı fiyat araması yapıyorsa, aşağıdaki SQL komutu ile sorgu süresini milisaniyelere indirebilirsiniz:

-- İndeks oluşturma komutu
CREATE INDEX idx_category_price ON products(category_id, price);

-- Sorgu planını analiz etme
EXPLAIN SELECT * FROM products WHERE category_id = 5 AND price > 100;

Bu indeksleme sayesinde veritabanı motoru, tüm tabloyu taramak (Full Table Scan) yerine, doğrudan ilgili aralıktaki veriye erişim sağlayacaktır. Dinamik sorgu oluştururken WHERE 1=1 yapısının indeks kullanımını engellemediğinden emin olmanız, veritabanı optimizasyonunun en kritik parçasıdır.

Sonuç

Sql & veritabanı ile dinamik veri filtreleme sorgusu yapmak, sadece bir kod parçası yazmak değil, aynı zamanda güvenli ve ölçeklenebilir bir mimari kurmaktır. Bu rehberde öğrendiğiniz WHERE 1=1 tekniği, PDO ile parametre bağlama ve beyaz liste ile sıralama kontrolü, profesyonel projelerde standart olarak kabul edilen yaklaşımlardır.

Bir sonraki adım olarak, bu filtreleme yapısını bir "Repository" sınıfı içerisine taşıyarak kodunuzu modüler hale getirmeyi deneyebilirsiniz. Ayrıca, daha karmaşık filtreleme ihtiyaçları için veritabanı seviyesinde "Stored Procedure" (Saklı Yordam) kullanımını araştırmanız, performans açısından size büyük avantajlar sağlayacaktır.

Sorumluluk Reddi: Bu makalede paylaşılan kod örnekleri eğitim amaçlıdır. Veritabanı işlemleri yapmadan önce mutlaka yedek alınız. Uygulamalarınızın güvenliği için her zaman en güncel PHP ve veritabanı sürümlerini kullanın ve kullanıcı girişlerini (input sanitization) asla ihmal etmeyin.
Bu yazıya tepkinizi paylaşın:
Emre Cansever

Teknik rehberler ve kendin yap (DIY) projeleri üzerine yoğunlaşıyorum. Detaylı ve güvenilir içerikler hazırlayarak okuyucuların teknik sorunlarını çözmelerine yardımcı oluyorum.

Yorumlar (18)

18
okuyucu bu yazı hakkında yorum yaptı. Siz de deneyiminizi paylaşarak diğer okuyuculara yardımcı olabilirsiniz.
Tolga B.
Tolga B. 18 Temmuz 2026

PHP 8.x sürümleriyle bir uyumluluk sorunu yaşanır mı? Kullanan var mı?

Sarpcan
Sarpcan 19 Temmuz 2026

Ben PHP 8.2 üzerinde çalıştırıyorum, hiçbir problem yok gayet stabil.

Gamze Uysal
Gamze Uysal 20 Temmuz 2026

Bu yöntemi büyük verisetlerinde kullanmak sorgu süresini çok etkiler mi? İndeksleme yapmak şart mı bu durumda?

Emre Cansever
Emre Cansever 21 Temmuz 2026

Gamze, kesinlikle şart. Dinamik filtreleme ile veriyi kısıtlamaya çalışırken veritabanı tarafında indeksler hayati önem taşıyor.

Eren S.
Eren S. 23 Temmuz 2026

Çok temiz ve anlaşılır bir rehber olmuş. Başka platformlarda çok karışık anlatıyorlar, eline koluna sağlık.

Ayşegül Tekin
Ayşegül Tekin 24 Temmuz 2026

Kod bloklarını kopyalarken bazen tırnak işaretlerinde sorun çıkıyo, kontrol eder misin?

Emre Cansever
Emre Cansever 25 Temmuz 2026

Ayşegül, uyarın için teşekkürler. Hemen kontrol edip düzeltiyorum.

Fatih Yılmaz
Fatih Yılmaz 25 Temmuz 2026

Anlatım güzel de keşke biraz daha fazla örnek senaryo ekleseydin. Mesela çoklu tablodan veri çekerken nasıl yapıyoruz?

Deniz Kara
Deniz Kara 27 Temmuz 2026

Fatih, 'JOIN' kullanarak aynı mantıkla devam edebiliyorsun. Ben bugün denedim, çalışıyor.

Hakan K.
Hakan K. 27 Temmuz 2026

Burda anlatılan mantığı CodeIgniter üzerinde denemek istiyorum, bir fark olur mu acaba? Sonuçta PDO kullanıyoruz.

Emre Cansever
Emre Cansever 29 Temmuz 2026

Hakan, mantık tamamen aynı. Sadece CI'ın veritabanı kütüphanesine göre syntax'ı ufak düzenlemen yeterli olacaktır.

Selin Gök
Selin Gök 30 Temmuz 2026

Harika bir yazı olmuş, projeme hemen entegre ettim. Allah razı olsun valla çok uğraştırıyordu beni bu kısım.

Mertcan Özdemir
Mertcan Özdemir 01 Ağustos 2026

Dinamik filtreleme yaparken 'where 1=1' kullanmak yerine farklı bir yöntem önerir misin? Performans açısından daha iyisi var mı?

Emre Cansever
Emre Cansever 02 Ağustos 2026

Mertcan, 1=1 modern veritabanlarında optimize ediliyor aslında. Yine de query builder kullanmak daha temiz bir alternatif olabilir.

Zeynep Aksoy
Zeynep Aksoy 03 Ağustos 2026

Ya ben kodları denedim ama veritabanı bağlantısında hata alıyom sürekli. Nerde yanlış yapyo olabilirim?

Burak Şen
Burak Şen 04 Ağustos 2026

Zeynep, .env dosyanı kontrol ettin mi? Bazen port numarası veya şifre yanlış giriliyor, ondan kaynaklı olabilir.

Caner Yılmaz
Caner Yılmaz 05 Ağustos 2026

Eline sağlık hocam, uzun zamandır böyle temiz bir PDO anlatımı arıyordum. Özellikle SQL injection konusunda bu kadar detaylı durman çok iyi olmuş.

Emre Cansever
Emre Cansever 06 Ağustos 2026

Çok teşekkürler Caner, güvenlik her zaman önceliğimiz olmalı. Faydalı olmasına sevindim.

Yorum Yaz