Kapsamlı MySQL Eğitimi: Sıfırdan İleri Seviyeye SQL Veritabanı Yönetimi

1.1 SQL nedir?

1.1 SQL (Structured Query Language) Nedir?

SQL, veritabanlarını yönetmek, sorgulamak ve manipüle etmek için kullanılan standart bir dildir. İlişkisel Veritabanı Yönetim Sistemlerinin (RDBMS) temel iletişim aracıdır. SQL'in temel gücü, dilin **beyana dayalı (declarative)** olmasından gelir. Yani, kullanıcı veritabanına "ne istediğini" söyler (Örn: "Maaşı 15.000'den fazla olan personeli getir"), veritabanı motoru ise bu veriyi "nasıl" getireceğini (en verimli yolu) kendisi belirler. Bu, geliştiricilerin sadece mantıksal sonuca odaklanmasını sağlar.

SQL'in Tarihçesi ve Önemi

SQL, 1970'lerde IBM'de Edgar F. Codd'un yayınladığı İlişkisel Model teorisinin pratik uygulaması olarak geliştirilmiştir. Başlangıçta SEQUEL (Structured English Query Language) adıyla anılırdı. Günümüzde tüm büyük veritabanı sistemleri (MySQL, PostgreSQL, Oracle, MS SQL Server) ANSI ve ISO standartlarına büyük ölçüde uyan SQL lehçelerini kullanır. SQL, sadece bir veri çekme aracı değil; aynı zamanda veritabanı şemasını oluşturma, veri güvenliğini yönetme ve veriyi manipüle etme yeteneklerini barındıran kapsamlı bir dildir.

SQL'in Üç Temel İşlevi

  1. **Veri Tanımlama:** Veritabanı yapısını, tabloları, alanları ve ilişkileri tanımlar. (DDL)
  2. **Veri Manipülasyonu:** Tablolardaki verileri ekler, günceller ve siler. (DML)
  3. **Veri Kontrolü:** Kullanıcı izinlerini ve veri güvenliğini yönetir. (DCL)

Neden SQL Öğrenmelisiniz?

Modern yazılım dünyasında, veri her şeydir. Web uygulamaları, mobil uygulamalar, veri analizi, yapay zeka ve iş zekası (BI) araçları gibi tüm sistemler arka planda bir RDBMS ile çalışır. SQL bilgisi, sadece bir yazılımcı veya veritabanı yöneticisi için değil, aynı zamanda veri bilimcileri, iş analistleri ve hatta pazarlama uzmanları için temel bir yetkinlik haline gelmiştir. SQL, size büyük veri kümelerinden anlamlı bilgiyi süzme gücü verir.

SQL komutları basit görünse de, verimli ve güvenilir sistemler kurmak için iç işleyişini, optimizasyon tekniklerini ve özellikle büyük veri setlerinde doğru indeksleme stratejilerini anlamak zorunludur. İlerleyen bölümlerde, bu yapısal bileşenlerin her birini derinlemesine inceleyeceğiz. SQL'in karmaşık sorguları, JOIN ve Alt Sorgular gibi araçlarla birleştiğinde ortaya çıkan analitik gücü, veritabanı yönetimi ve programlamanın en tatmin edici yönlerinden biridir.

SQL, 50 yılı aşkın süredir ayakta kalan ve gelecekte de veri yönetiminin merkezinde yer alacak, zamana meydan okuyan bir dildir. Bu nedenle, bu dili öğrenmek, kariyerinize yapacağınız en değerli yatırımlardan biridir.

1.2 Veritabanı Kavramları (Database, Table, Record, Field)

İlişkisel veritabanı sistemini anlamak, birbiriyle hiyerarşik olarak ilişkili dört temel kavramı anlamaktan geçer. Bu kavramlar, verinin depolanma, organize edilme ve erişilme şeklini tanımlar.

1.2.1 Database (Veritabanı)

Veritabanı, verilerin mantıksal olarak bir araya getirildiği ve organize edildiği, birbiriyle ilişkili tablo ve diğer veritabanı nesnelerinin (View, Stored Procedure, Index vb.) topluluğudur. Bir veritabanı, genellikle tek bir uygulamanın veya iş biriminin tüm verisini tutar. Örneğin, bir E-ticaret sistemi için tüm ürün, müşteri, sipariş ve stok bilgilerini barındıran tek bir "E-TICARET_DB" veritabanı olabilir.

  • **Mantıksal Sınır:** Veritabanı, birbiriyle ilişkili verileri izole eden en üst düzey mantıksal kapsayıcıdır.
  • **Fiziksel Konum:** Fiziksel olarak, disk üzerindeki bir veya birden fazla dosyadan oluşur ve bu dosyalar, sunucu tarafından yönetilir.
  • **Erişim Noktası:** Uygulamalar, verilere erişmek için öncelikle bu veritabanına bağlanmalıdır.

1.2.2 Table (Tablo)

Tablolar, veritabanının temel depolama yapılarıdır. Veriyi, satırlar ve sütunlar halinde düzenlenmiş, iki boyutlu bir yapı (bir Excel tablosu gibi) içinde tutarlar. Her tablo, tek bir varlığa (entity) ait veriyi barındırmalıdır. Örneğin, `Musteriler`, `Urunler` veya `Calisanlar` tabloları.

  • **Yapısal Bütünlük:** Tablonun yapısı (sütunlar, veri tipleri, kısıtlamalar) CREATE TABLE komutu ile belirlenir.
  • **Varlık Temsili:** Her tablo, gerçek dünyadaki bir nesneyi veya bir ilişkiyi temsil eder.

1.2.3 Field / Column (Alan / Sütun)

Sütunlar, tablonun dikey bileşenleridir ve her bir varlık için saklanan tek bir bilgi türünü temsil eder. Bir sütun, tablodaki tüm kayıtlar (satırlar) için aynı veri tipini (örneğin hepsi metin, hepsi tamsayı) ve aynı kısıtlamaları (örneğin benzersizlik) uygular.

  • **Nitelik Temsili:** Bir müşterinin adı, bir ürünün fiyatı veya bir siparişin tarihi gibi nitelikleri (attribute) ifade eder.
  • **Veri Tipi Zorunluluğu:** Her sütun bir veri tipine sahip olmalıdır (VARCHAR, INT, DATE vb.).

Örnek: `Musteriler` tablosundaki sütunlar: `musteri_id`, `ad`, `soyad`, `telefon`.

1.2.4 Record / Row (Kayıt / Satır)

Satırlar, tablonun yatay bileşenleridir ve bir varlığın tek, eksiksiz bir örneğini temsil eder. Başka bir deyişle, bir satır, tablodaki her sütun için bir değer içerir.

  • **Varlık Örneği:** Bir `Musteriler` tablosundaki her bir satır, tek bir müşterinin tüm bilgilerini içerir.
  • **Benzersizlik:** İlişkisel modelde, her satırın benzersiz bir şekilde tanımlanabilmesi (PRIMARY KEY) önerilir.

Örnek: `Musteriler` tablosunda "musteri_id=101, ad=Ahmet, soyad=Yılmaz, telefon=555..." şeklinde bir satır, tek bir Ahmet Yılmaz'ı ifade eder.

Bu temel hiyerarşiyi (Database > Table > Column & Row) anlamak, SQL komutlarını yazarken ve veritabanı tasarlarken doğru mantığı kurmanın ilk adımıdır.

1.3 İlişkisel Veritabanı Nedir (RDBMS Kavramı)

İlişkisel Veritabanı Yönetim Sistemi (RDBMS - Relational Database Management System), verilerin Edgar F. Codd'un İlişkisel Model teorisine dayalı olarak organize edildiği, depolandığı ve yönetildiği bir yazılım sistemidir. Bu modelin kalbinde, verilerin önceden tanımlanmış ilişkilerle birleştirilebilen ayrı tablolarda depolanması fikri yatar. RDBMS'ler, tutarlı, güvenilir ve verimli veri yönetimi sağlamak için kritik özellikler sunar.

1.3.1 İlişkisel Modelin Özellikleri

  1. **Veri Yapısı (Tablolar):** Tüm veriler, satır ve sütunlardan oluşan iki boyutlu tablolar halinde düzenlenir.
  2. **İlişkiler (Relationships):** Tablolar, Birincil Anahtarlar (PRIMARY KEY) ve Yabancı Anahtarlar (FOREIGN KEY) aracılığıyla birbirine bağlanır. Bu, veri fazlalığını (redundancy) önler.
  3. **Veri Bütünlüğü (Integrity):** Model, verinin doğru ve tutarlı kalmasını sağlayan kısıtlamaları (constraints) zorunlu kılar.

1.3.2 RDBMS'nin Temel Prensipleri: ACID Özellikleri

RDBMS'leri diğer depolama çözümlerinden ayıran en önemli özellik, veritabanı işlemlerinin (Transaction) güvenilirliğini garanti eden **ACID** ilkeleridir:

  • **Atomicity (Bölünmezlik):** Bir işlem ya tamamen başarılı olur ve tüm değişiklikler veritabanına kaydedilir, ya da tamamen başarısız olur ve hiçbir değişiklik kaydedilmez (geri alınır/ROLLBACK).
  • **Consistency (Tutarlılık):** Bir işlem, veritabanını bir geçerli durumdan diğer geçerli duruma getirir. İşlem sırasında tanımlanan tüm kısıtlamalar (benzersizlik, veri tipi, referans bütünlüğü) ihlal edilemez.
  • **Isolation (İzolasyon):** Aynı anda gerçekleşen birden fazla işlem, sanki sırayla gerçekleşiyormuş gibi birbirinden izole edilir. Bir işlemin ara durumu, diğer işlemlere görünmez olmalıdır.
  • **Durability (Kalıcılık):** Başarıyla tamamlanan (COMMIT edilen) bir işlemden sonra yapılan değişiklikler, sistem hatası (elektrik kesintisi vb.) olsa bile kalıcıdır ve kaybolmaz.

1.3.3 Normalizasyonun Rolü (Kısa Tanım)

Normalizasyon, veri fazlalığını azaltmak ve veri anormalliklerini (ekleme, güncelleme, silme anomalileri) ortadan kaldırmak için tabloları ve sütunları organize etme sürecidir. RDBMS, normalleştirilmiş bir yapıda en verimli çalışır. Bu sürecin farklı seviyeleri (1NF, 2NF, 3NF vb.) bulunur ve 10. ünite bu konuyu detaylıca ele alacaktır.

1.3.4 RDBMS ve NoSQL Karşılaştırması

RDBMS, yapılandırılmış veriler, güçlü ilişkiler ve veri bütünlüğünün mutlak öncelik olduğu (örneğin bankacılık, envanter, muhasebe) sistemler için idealdir. NoSQL (Not Only SQL) veritabanları ise esnek şemaları, yüksek ölçeklenebilirliği ve BASE (Basic Availability, Soft state, Eventual consistency) ilkeleriyle karakterize edilir ve genellikle büyük hacimli yapılandırılmamış veya yarı yapılandırılmış veriler için kullanılır (örneğin sosyal medya, büyük ölçekli içerik yönetim sistemleri).

Günümüzde en popüler RDBMS örnekleri; Oracle, Microsoft SQL Server, MySQL ve PostgreSQL'dir.

1.4 SQL Sürümleri: MySQL, SQL Server, PostgreSQL, Oracle, SQLite

SQL, bir dil standardı olsa da, her RDBMS satıcısı bu standardı kendi yorumuyla uygular. Bu farklılıklar, bazen sözdizimsel ufak tefek değişiklikler (Örn: `LIMIT` yerine `TOP` kullanmak) bazen de mimarinin getirdiği büyük farklılıklar (Örn: Transaction/Commit yönetimi) olarak karşımıza çıkar. En popüler RDBMS platformlarının detaylı karşılaştırması aşağıdadır:

1.4.1 MySQL

**Mimarisi ve Kullanım Alanı:** Dünyanın en popüler açık kaynaklı veritabanı yönetim sistemidir. Başlangıçta basit ve hızlı olması için tasarlanmıştır. Genellikle PHP tabanlı web uygulamaları (özellikle LAMP/LEMP yığını) ve küçük-orta ölçekli projeler için idealdir. Basit yapısı nedeniyle kurulumu ve yönetimi kolaydır. InnoDB ve MyISAM gibi depolama motorlarını destekler. InnoDB, ACID uyumluluğu ve Foreign Key desteği sunarak modern uygulamalar için standart motor haline gelmiştir.

  • **Lisans:** Genellikle GPL (Community Edition) veya ticari lisans.
  • **Güçlü Yönleri:** Hız, kolaylık, geniş topluluk desteği, replikasyon ve ölçeklendirme seçenekleri.

1.4.2 PostgreSQL

**Mimarisi ve Kullanım Alanı:** Kurumsal düzeyde, nesne-ilişkisel (Object-Relational) bir veritabanı sistemidir. SQL standardına en uygun ve en gelişmiş özellik setine sahip olduğu kabul edilir. Özellikle karmaşık sorgular, büyük veri kümeleri, uzamsal veriler (PostGIS) ve tam metin araması gereken sistemler için tercih edilir. Güçlü bir açık kaynak alternatiftir.

  • **Lisans:** BSD (Açık kaynak, çok esnek).
  • **Güçlü Yönleri:** Gelişmiş veri tipleri (JSONB, diziler), yüksek güvenilirlik, güçlü Transaction ve güvenlik mekanizmaları.

1.4.3 Microsoft SQL Server

**Mimarisi ve Kullanım Alanı:** Microsoft tarafından geliştirilen ticari bir RDBMS'dir. Özellikle .NET tabanlı kurumsal uygulamalar, iş zekası (BI) ve yüksek erişilebilirliğin zorunlu olduğu finansal sistemler için standarttır. Güçlü GUI araçları (SSMS), gelişmiş güvenlik, veri ambarı ve analitik yetenekleriyle bilinir. Kendi SQL lehçesi T-SQL (Transact-SQL) olarak adlandırılır.

  • **Lisans:** Ticari (Çeşitli sürümleri mevcuttur: Express, Standard, Enterprise).
  • **Güçlü Yönleri:** Kurumsal düzeyde performans, entegre güvenlik, Microsoft ekosistemiyle tam uyum.

1.4.4 Oracle Database

**Mimarisi ve Kullanım Alanı:** Dünyanın en yaygın kullanılan kurumsal veritabanlarından biridir. Çoğunlukla finansal kurumlar, telekomünikasyon ve büyük hükümet sistemleri gibi en zorlu ve kritik uygulamalar için kullanılır. Çok büyük veri setlerini yönetme, yüksek işlem hacmi (OLTP) ve gelişmiş kurtarma/yedekleme yetenekleriyle tanınır. Kendi SQL lehçesi PL/SQL'dir.

  • **Lisans:** Ticari (Çok pahalı ve karmaşık lisanslama).
  • **Güçlü Yönleri:** Rakipsiz ölçeklenebilirlik, yüksek erişilebilirlik, en gelişmiş veri güvenliği ve kurtarma mekanizmaları.

1.4.5 SQLite

**Mimarisi ve Kullanım Alanı:** Sunucuya ihtiyaç duymayan, tam olarak bir dosyada saklanan gömülü bir veritabanıdır. Sunucusuz çalışır, kurulumu kolaydır ve tüm veritabanı işlemlerini tek bir dosya üzerinde gerçekleştirir. Web tarayıcıları, mobil uygulamalar (Android, iOS) ve küçük masaüstü uygulamaları için idealdir. Transaction desteği sunsa da, eşzamanlı yazma işlemlerinde performansı düşüktür.

  • **Lisans:** Public Domain.
  • **Güçlü Yönleri:** Gömülü, sıfır yapılandırma gereksinimi, küçük boyut, yüksek taşınabilirlik.

1.5 SQL Komut Türleri (DDL, DML, DCL, TCL)

SQL komutları, gerçekleştirdikleri işlevlere göre dört ana kategoriye ayrılır. Bu ayrım, veritabanı yöneticileri ve geliştiriciler için komutların amacını ve etkilerini anlamak açısından kritik öneme sahiptir.

1.5.1 DDL (Data Definition Language - Veri Tanımlama Dili)

DDL komutları, veritabanı nesnelerinin (tablolar, şemalar, indeksler, view'lar) yapısını (şemasını) tanımlamak, değiştirmek veya silmek için kullanılır. Bu komutlar, veritabanının meta verisini etkiler ve yürütüldüklerinde otomatik olarak **COMMIT** edilirler (kalıcıdırlar ve geri alınamazlar).

  • **CREATE:** Yeni bir veritabanı nesnesi oluşturur. CREATE TABLE Urunler (urun_id INT PRIMARY KEY, ad VARCHAR(255));
  • **ALTER:** Mevcut bir nesnenin yapısını değiştirir (Örn: yeni sütun ekleme). ALTER TABLE Urunler ADD COLUMN stok INT;
  • **DROP:** Bir nesneyi ve içindeki tüm veriyi kalıcı olarak siler. DROP TABLE Urunler;
  • **TRUNCATE:** Tablonun tüm satırlarını siler, ancak tablo yapısını (şemasını) korur. DDL olarak kabul edilir çünkü log kaydı daha az tutulur ve DML komutu olan DELETE'e göre daha hızlıdır. TRUNCATE TABLE GeciciKayitlar;

1.5.2 DML (Data Manipulation Language - Veri İşleme Dili)

DML komutları, veritabanı tablolarındaki gerçek veriyi (satırları) işlemek (çekmek, eklemek, değiştirmek veya silmek) için kullanılır. Bu komutların etkileri, bir işlem (Transaction) içinde gerçekleşir ve TCL komutlarıyla (COMMIT/ROLLBACK) kontrol edilebilir.

  • **SELECT:** Veritabanından veriyi çeker. Veritabanında bir değişiklik yapmaz. SELECT ad, fiyat FROM Urunler WHERE fiyat > 100;
  • **INSERT:** Bir tabloya yeni satırlar ekler. INSERT INTO Personel (ad, maas) VALUES ('Ali', 15000);
  • **UPDATE:** Mevcut satırlardaki veriyi değiştirir. UPDATE Urunler SET fiyat = 120 WHERE urun_id = 5;
  • **DELETE:** Mevcut satırları tablodan siler. DELETE FROM Musteriler WHERE sehir = 'İzmir';

1.5.3 DCL (Data Control Language - Veri Kontrol Dili)

DCL komutları, veritabanı kullanıcılarına nesneler üzerinde erişim hakları (izinler) vermek ve bu hakları geri almak için kullanılır. Veritabanının güvenliğini ve çok kullanıcılı ortamda yetkilendirmeyi yönetir.

  • **GRANT:** Bir kullanıcıya belirli bir yetki verir. GRANT SELECT ON Urunler TO 'raporlama_kullanicisi';
  • **REVOKE:** Bir kullanıcıdan daha önce verilen yetkiyi geri alır. REVOKE DELETE ON Personel FROM 'muhasebe_kullanicisi';

1.5.4 TCL (Transaction Control Language - İşlem Kontrol Dili)

TCL komutları, DML komutlarının (INSERT, UPDATE, DELETE) gruplandırıldığı işlemlerin (Transaction) yönetimini sağlar. ACID özelliklerinin, özellikle Atomicity ve Durability'nin uygulanması için hayati öneme sahiptir.

  • **COMMIT:** İşlem içindeki tüm değişiklikleri kalıcı olarak kaydeder. COMMIT;
  • **ROLLBACK:** İşlem başladığından beri yapılan tüm değişiklikleri geri alır. ROLLBACK;
  • **SAVEPOINT (Opsiyonel):** İşlem içinde belirli bir noktaya işaret koyar, böylece ROLLBACK sadece o noktaya kadar yapılabilir. SAVEPOINT A_noktasi;

2.1 CREATE DATABASE – Veritabanı Oluşturma (DDL)

Veritabanı oluşturma, tüm SQL yolculuğunun ilk adımıdır. `CREATE DATABASE` komutu, verilerinizi barındıracak mantıksal alanı ve bu alanın fiziksel özelliklerini tanımlar.

2.1.1 Temel Sözdizimi

Veritabanının adı genellikle benzersiz olmalıdır ve RDBMS'ye bağlı olarak bazı özel karakter kurallarına uymalıdır.

CREATE DATABASE [IF NOT EXISTS] veritabani_adi;

MySQL gibi sistemlerde `IF NOT EXISTS` anahtar kelimesi, aynı isimde bir veritabanı zaten varsa hata vermesini önler. Bu, betikleri (script) çalıştırırken sıklıkla kullanılan bir güvenlik önlemidir.

2.1.2 Karakter Seti ve Sıralama (COLLATION)

Veritabanı oluştururken, karakter setini ve sıralama (collation) ayarlarını belirtmek, özellikle Türkçe gibi Latin alfabesi dışındaki dilleri veya özel karakterleri kullanan dilleri desteklemek için zorunludur. Bu ayarlar, metin verisinin nasıl saklanacağını (bellekte) ve nasıl karşılaştırılacağını (sıralama, arama) belirler.

  • **Karakter Seti (CHARACTER SET):** Hangi karakterlerin saklanabileceğini tanımlar (Örn: `utf8mb4` veya `utf8` en yaygın olanlarıdır).
  • **Sıralama (COLLATION):** Metinlerin karşılaştırma kurallarını belirler (Örn: büyük/küçük harf duyarlılığı, aksan duyarlılığı).

Detaylı Sözdizimi Örneği (MySQL):

CREATE DATABASE Kurs_Otomasyonu CHARACTER SET utf8mb4 COLLATE utf8mb4_turkish_ci;
  • `utf8mb4`: Emoji ve diğer 4-baytlık karakterleri destekleyen, güncel ve önerilen karakter setidir.
  • `utf8mb4_turkish_ci`: Türkçe karakterler (ç, ğ, ı, ö, ş, ü) ve büyük/küçük harf duyarlılığını (Case-Insensitive) hesaba katan sıralama kuralıdır. `_ci` (Case Insensitive) harfleri büyük/küçük harf farkını göz ardı eder, `_cs` (Case Sensitive) ise dikkate alır.

Bu ayarların doğru yapılması, veri girişi, arama ve sıralama işlemlerinde beklenmeyen hataları (Örn: 'i' ve 'İ' harflerinin yanlış sıralanması) önler. Yanlış karakter seti seçimi, daha sonra veri kaybına veya bozulmasına yol açabilir.

2.1.3 Veritabanı Seçimi (USE)

Bir veritabanı oluşturulduktan sonra, üzerinde çalışmaya başlamadan önce o veritabanını aktif olarak seçmek gerekir. Bu işlem, sonraki tüm DDL ve DML komutlarının o veritabanı bağlamında çalışmasını sağlar.

USE Kurs_Otomasyonu; -- Artık oluşturacağımız tablolar bu veritabanının içinde olacaktır.

DDL komutları atomiktir ve başarılı olduktan sonra otomatik olarak kalıcı hale gelirler (Auto-Commit). Yani bu komutları `ROLLBACK` ile geri alamazsınız.

2.2 CREATE TABLE – Tablo Oluşturma (DDL)

Tablolar, veritabanının veriyi barındırdığı temel yapılardır. `CREATE TABLE` komutu, bu yapıların iskeletini tanımlar. Bu aşamada, veri tipleri, kısıtlamalar ve varsayılan değerler belirlenir.

2.2.1 Temel Sözdizimi

CREATE TABLE [IF NOT EXISTS] tablo_adi ( sutun_1 veri_tipi [kısıtlamalar], sutun_2 veri_tipi [kısıtlamalar], ... PRIMARY KEY (sutun_adi), FOREIGN KEY (sutun_adi) REFERENCES diger_tablo(diger_sutun) );

2.2.2 Kritik Veri Tipleri ve Kullanımı

Veri tipinin doğru seçimi, hem depolama verimliliği hem de sorgu performansı için hayati öneme sahiptir:

Veri Tipi Açıklama Kullanım Örneği
**INT** / **INTEGER** Tamsayılar için kullanılır. (Küçükten büyüğe: TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT) Ürün ID'si, Stok Adedi
**VARCHAR(n)** Değişken uzunlukta metinler için. (n: maksimum karakter sayısı) Ad, Soyad, E-posta adresi (Verimli depolama sağlar)
**CHAR(n)** Sabit uzunlukta metinler için. (n boyutu kadar yer ayırır) Posta kodu, 2 haneli Ülke kodu (TR, US)
**TEXT** / **MEDIUMTEXT** Çok uzun metinler (Blog içeriği, Detaylı açıklamalar) için. Makale İçeriği (Performansı düşürebilir)
**DECIMAL(p, s)** Kesin hassasiyet gerektiren ondalık sayılar (Para birimi, Faiz oranları). p: Toplam hane sayısı, s: Ondalıktan sonraki hane sayısı. Fiyat (DECIMAL(10, 2)), Para Miktarı
**DATE** / **DATETIME** Tarih bilgisi (YYYY-MM-DD) veya Tarih ve Saat bilgisi. Doğum Tarihi, Kayıt Tarihi (TIMESTAMP da alternatif olarak kullanılır)

2.2.3 Sütun Kısıtlamaları (Constraints)

Kısıtlamalar, tabloda depolanan verinin doğruluğunu ve tutarlılığını sağlamak için kullanılır. En temel kısıtlamalar şunlardır:

  • **NOT NULL:** Sütunun NULL (bilinmeyen) değer almasını engeller.
  • **PRIMARY KEY:** Bir satırı benzersiz olarak tanımlayan sütundur. Hızlı erişim için otomatik olarak indekslenir ve sadece tek birincil anahtar olabilir.
  • **UNIQUE:** Sütundaki tüm değerlerin benzersiz olmasını zorunlu kılar (NULL alabilir, Primary Key'den farkı budur).
  • **DEFAULT:** Bir değer belirtilmediğinde sütuna atanacak varsayılan değeri belirler.
  • **AUTO_INCREMENT:** (MySQL) Sütunun değerinin otomatik olarak artmasını sağlar (Genellikle Primary Key ile kullanılır).
  • **FOREIGN KEY:** Verilerin başka bir tablodaki geçerli değerlere referans vermesini zorunlu kılar (Bkz: 6.1).

Örnek Tablo Oluşturma:

CREATE TABLE Urunler ( urun_id INT AUTO_INCREMENT PRIMARY KEY, urun_adi VARCHAR(255) NOT NULL UNIQUE, kategori_id INT, fiyat DECIMAL(8, 2) DEFAULT 0.00, stok_adeti INT NOT NULL, FOREIGN KEY (kategori_id) REFERENCES Kategoriler(kategori_id) );

2.3 INSERT INTO – Veri Ekleme (DML)

Tablonun yapısı oluşturulduktan sonra, içine veri girişi yapmak için `INSERT INTO` komutu kullanılır. Bu, bir veritabanı uygulamasının en sık kullandığı DML komutlarından biridir.

2.3.1 Tek Bir Satır Ekleme (Sütunlar Belirtilerek)

Bu en güvenilir yöntemdir, çünkü sütun isimlerini açıkça belirtir ve tabloda bir değişiklik yapılsa bile (yeni bir sütun eklenmesi gibi) sorgunuzun bozulmasını engeller.

INSERT INTO tablo_adi (sutun_1, sutun_2, sutun_3) VALUES (deger_1, deger_2, deger_3);

Örnek:

INSERT INTO Personel (ad, soyad, maas, departman) VALUES ('Ayşe', 'Kara', 18000.00, 'Finans');

Notlar:

  • Sayısal değerler tırnak içinde kullanılmaz.
  • Metin ve tarih değerleri tek tırnak (`'`) içinde belirtilmelidir.
  • `AUTO_INCREMENT` kısıtlaması olan sütunlar için, değer ya hiç belirtilmez ya da `NULL` olarak verilir; sistem otomatik atama yapar.

2.3.2 Tüm Sütunlara Ekleme (Sütunlar Belirtilmeden)

Eğer tablodaki tüm sütunlara, tablo tanım sırasına göre veri ekleniyorsa, sütun isimleri parantez içinde belirtilmeyebilir. Ancak bu yöntem, tablo yapısı değiştiğinde kırılgan hale gelir.

INSERT INTO tablo_adi VALUES (deger_1, deger_2, deger_3, ...);

Örnek: (Personel tablosunda `personel_id` auto-increment ise ve ilk sütunsa)

INSERT INTO Personel VALUES (NULL, 'Mehmet', 'Yıldız', 14500.00, 'Satış');

2.3.3 Çoklu Satır Ekleme (Batch Insert)

Tek bir komutla birden fazla kayıt eklemek, veritabanı sunucusuna yapılan gidiş-dönüş sayısını azalttığı için çok daha verimli (daha hızlı) bir yöntemdir.

INSERT INTO Personel (ad, soyad, maas, departman) VALUES ('Büşra', 'Aydın', 16000.00, 'Pazarlama'), ('Can', 'Doğan', 22000.00, 'Yazılım'), ('Deniz', 'Öztürk', 13000.00, 'IK');

2.3.4 Başka Bir Tablodan Veri Ekleme (INSERT INTO SELECT)

Bu yöntem, bir tablodaki veriyi alıp, başka bir tabloya aktarmak (yedeklemek veya özetlemek) için kullanılır. Sütunların veri tipleri ve kısıtlamaları uyumlu olmalıdır.

INSERT INTO Eski_Personel (ad, soyad, cikis_tarihi) SELECT ad, soyad, '2024-01-01' FROM Personel WHERE durum = 'Ayrılan';

INSERT komutları, veritabanı Transaction (İşlem) mantığı içinde çalışır ve COMMIT edilmedikçe diğer kullanıcılar tarafından görülmez (İzolasyon ilkesi).

2.4 SELECT, UPDATE, DELETE Komutları (Temel CRUD)

Bu üç komut, DML'nin temelini oluşturur ve veritabanı yönetiminde en sık kullanılan işlemlerdir. CRUD (Create, Read, Update, Delete) operasyonlarının Read, Update ve Delete adımlarını karşılarlar.

2.4.1 SELECT (Read - Veri Okuma)

SELECT, bir tablodan veya tablolardan veriyi okumak için kullanılır ve veritabanı üzerinde hiçbir değişiklik yapmaz. En basit haliyle, tüm sütunları ve tüm kayıtları çeker.

SELECT * -- Tüm sütunlar FROM Musteriler;

Genellikle bir `WHERE` yan tümcesi (Bkz: 3.1) ile birlikte kullanılarak sonuç kümesi filtrelenir:

SELECT ad, soyad, eposta FROM Musteriler WHERE kayit_tarihi >= '2024-01-01' ORDER BY soyad ASC;

SELECT, SQL'in en karmaşık komutudur ve JOIN, GROUP BY, Alt Sorgular gibi birçok yan tümce ile birleştirilerek analitik gücünü gösterir.

2.4.2 UPDATE (Update - Veri Güncelleme)

UPDATE komutu, bir tablodaki mevcut bir veya birden fazla satırdaki sütun değerlerini değiştirmek için kullanılır. Bu komut, bir Transaction içinde çalışır ve `WHERE` koşulu olmadan çalıştırılırsa tablodaki **TÜM** kayıtları günceller.

Temel Sözdizimi:

UPDATE tablo_adi SET sutun_1 = yeni_deger_1, sutun_2 = yeni_deger_2 [WHERE koşul]; -- KRİTİK! Güncellenecek satırları belirler

Örnek: 'Yazılım' departmanındaki tüm personelin maaşına %10 zam yapma.

UPDATE Personel SET maas = maas * 1.10, son_guncelleme = NOW() -- Güncel zamanı atama (Opsiyonel) WHERE departman = 'Yazılım';

2.4.3 DELETE (Delete - Veri Silme)

DELETE komutu, bir tablodan belirli koşulları sağlayan bir veya birden fazla satırı silmek için kullanılır. Bu komut, UPDATE gibi, bir Transaction içinde çalışır ve `WHERE` koşulu olmadan çalıştırılırsa tablodaki **TÜM** kayıtları siler.

Temel Sözdizimi:

DELETE FROM tablo_adi [WHERE koşul]; -- KRİTİK! Silinecek satırları belirler

Örnek: 1 Ocak 2023'ten önce verilen tüm siparişleri silme.

DELETE FROM Siparisler WHERE siparis_tarihi < '2023-01-01';

⚠️ **Önemli Not (Güvenlik):** UPDATE ve DELETE komutlarını kullanırken **WHERE koşulunu kontrol etmek hayati önem taşır**. Yanlış bir koşul, tüm veritabanınızdaki veriyi geri dönülmez şekilde silebilir veya bozabilir. Bu komutları bir Transaction (İşlem) içinde başlatmak ve önce `SELECT` ile hangi satırların etkileneceğini kontrol etmek iyi bir pratik (Best Practice) olarak kabul edilir.

2.5 DROP ve TRUNCATE Farkı (DDL)

Hem `DROP TABLE` hem de `TRUNCATE TABLE`, tablodaki verileri silmek için kullanılır, ancak işlevleri, etkileri ve veri kurtarılabilirliği açısından temel farklılıklar gösterirler. Bu komutlar, Veri Tanımlama Dili (DDL) kategorisindedir ve genellikle geri alınamaz etkileri vardır.

2.5.1 DROP TABLE (Tabloyu Tamamen Silme)

`DROP TABLE`, tabloyu veritabanından tamamen kaldırır. Bu, sadece veriyi değil, tablonun tüm yapısını (şemasını), kısıtlamalarını, indekslerini ve trigger'larını da siler.

Sözdizimi:

DROP TABLE tablo_adi;

Özellikler:

  • **Kapsam:** Hem veri hem de tablo yapısı (şema) silinir.
  • **Geri Alınabilirlik:** Genellikle geri alınamaz. Bir `DROP` işlemi otomatik olarak kesinleşir (COMMIT).
  • **Kısıtlama:** Tablonun başka bir tabloya `FOREIGN KEY` referansı varsa, silinmeden önce bu kısıtlamaların kaldırılması gerekebilir.
  • **Kullanım Amacı:** Artık gerekmeyen tabloları kalıcı olarak kaldırmak.

2.5.2 TRUNCATE TABLE (Tüm Veriyi Silme, Yapıyı Koruma)

`TRUNCATE TABLE`, bir tablonun tüm satırlarını siler, ancak tablonun yapısını, sütunlarını ve kısıtlamalarını korur. DML komutu olan `DELETE`'ten farklı olarak, bu bir DDL işlemidir ve çok daha hızlı çalışır.

Sözdizimi:

TRUNCATE TABLE tablo_adi;

Özellikler:

  • **Kapsam:** Sadece tablonun içeriği silinir. Tablo yapısı, indeksler ve kısıtlamalar korunur.
  • **Performans:** Çok hızlıdır. Çünkü her satırı tek tek silmek yerine, veriyi tutan tüm veri sayfalarını (data pages) serbest bırakır ve işlem loguna daha az kayıt yazar.
  • **AUTO_INCREMENT Sıfırlama:** Genellikle `AUTO_INCREMENT` sayacını sıfırlar ve sayımı baştan başlatır.
  • **Geri Alınabilirlik:** Çoğu RDBMS'de (MySQL'de MyISAM motorunda, SQL Server'da) geri alınamaz (Auto-Commit). PostgreSQL gibi bazı RDBMS'lerde `TRUNCATE` bir Transaction içinde kullanılırsa geri alınabilir.

2.5.3 DELETE'ten Farkı (DML Komutu)

`DELETE FROM TabloAdi;` komutu da tüm satırları siler, ancak bir DML komutudur:

  • `DELETE`, her satırı tek tek siler, Transaction loga yazar ve bu nedenle `TRUNCATE`'ten çok daha yavaştır.
  • `DELETE`, bir Transaction içinde çalışır ve **ROLLBACK** ile geri alınabilir.
  • `DELETE`, `AUTO_INCREMENT` sayacını sıfırlamaz.
  • `DELETE`, bir `WHERE` koşulu alabilir, `TRUNCATE` alamaz.

Özetle: Tüm veriyi hızlıca silmek ve sayacı sıfırlamak istiyorsanız **TRUNCATE**; sadece belirli satırları silmek veya işlemi geri alma seçeneğini korumak istiyorsanız **DELETE** kullanın.

2.6 ALTER TABLE – Tabloyu Değiştirme (DDL)

`ALTER TABLE` komutu, mevcut bir tablonun yapısını (şemasını) değiştirmek için kullanılır. Bu, veritabanı tasarımında yapılan hataları düzeltmek veya iş gereksinimleri değiştikçe yeni sütunlar eklemek/mevcutları kaldırmak için esneklik sağlar.

2.6.1 Sütun Ekleme (ADD COLUMN)

Bir tabloya yeni bir sütun eklerken, sütunun adını, veri tipini ve kısıtlamalarını tanımlamanız gerekir. Yeni sütunlar, mevcut satırlarda varsayılan olarak `NULL` değerini alır, `DEFAULT` bir değer atanmadıkça.

Sözdizimi:

ALTER TABLE tablo_adi ADD COLUMN yeni_sutun_adi veri_tipi [kısıtlamalar] [pozisyon];

Örnekler:

-- En sona yeni bir sütun ekleme ALTER TABLE Musteriler ADD COLUMN kayit_tarihi DATE NOT NULL DEFAULT CURRENT_DATE(); -- Belirli bir sütundan sonra ekleme (MySQL'e özel) ALTER TABLE Urunler ADD COLUMN vergi_orani DECIMAL(5, 2) AFTER fiyat;

2.6.2 Sütun Veri Tipini Değiştirme (MODIFY COLUMN / ALTER COLUMN)

Mevcut bir sütunun veri tipini, boyutunu veya kısıtlamalarını değiştirmek için kullanılır. Farklı RDBMS'ler farklı anahtar kelimeler kullanabilir (`MODIFY` MySQL'de, `ALTER COLUMN` SQL Server/PostgreSQL'de).

⚠️ **Risk:** Sütunun boyutunu küçültmek veya veri tipini uyumsuz bir tipe değiştirmek (Örn: Metinden Tamsayıya), veri kaybına neden olabilir.

Örnek (MySQL):

ALTER TABLE Musteriler MODIFY COLUMN ad VARCHAR(150) NOT NULL; -- Boyutu 50'den 150'ye çıkarıp NOT NULL ekleme

2.6.3 Sütun Silme (DROP COLUMN)

Bir sütunu ve içindeki tüm veriyi kalıcı olarak tablodan kaldırır. Bu işlem geri alınamaz.

Sözdizimi:

ALTER TABLE tablo_adi DROP COLUMN silinecek_sutun_adi;

2.6.4 Kısıtlama Ekleme/Kaldırma

Tablo oluşturulduktan sonra da kısıtlamalar eklenebilir veya kaldırılabilir. `FOREIGN KEY` ve `PRIMARY KEY` en sık değiştirilenlerdir.

PRIMARY KEY Ekleme:

ALTER TABLE Personel ADD PRIMARY KEY (personel_id);

FOREIGN KEY Ekleme:

ALTER TABLE Siparisler ADD CONSTRAINT fk_musteri FOREIGN KEY (musteri_id) REFERENCES Musteriler(musteri_id);

ALTER TABLE komutları, canlı sistemlerde dikkatli kullanılmalıdır, çünkü büyük tablolarda yapısal değişiklikler ciddi kilitlemelere (locking) ve performansta yavaşlamalara neden olabilir (uzun süren DDL işlemleri).

3.1 SELECT * FROM Temelleri ve WHERE Koşulları

SQL'in kalbi, veritabanından veri çekme komutu olan **SELECT** ile atar. Bu komut, DML (Veri İşleme Dili) kategorisinin en kritik bileşenidir ve raporlama, analiz ve uygulama verisi sağlama gibi tüm işlemlerin temelini oluşturur. Etkili ve verimli sorgulama yapabilmek için SELECT ve yan tümcelerinin doğru anlaşılması şarttır.

3.1.1 SELECT Komutunun Temel Yapısı

SELECT ifadesinin temel amacı, veriyi sütunlar ve satırlar olarak tanımlanmış bir sonuç kümesi (result set) halinde döndürmektir.

SELECT [DISTINCT] sutun_1, sutun_2, ... FROM tablo_adi;
  • **SELECT:** Hangi sütunların (alanların) sonuç kümesine dahil edileceğini belirtir.
  • **FROM:** Verinin hangi tablodan veya tablolardan alınacağını belirtir.
  • **\*** (Yıldız): Tüm sütunları getirmek için kullanılan joker karakterdir. Geliştirmede pratik olsa da, performansı düşürebileceği ve gereksiz veri transferine yol açabileceği için üretim ortamında kaçınılması gereken bir pratiktir.

3.1.2 WHERE Yan Tümcesi: Satır Filtreleme

Bir tablodaki tüm veriyi çekmek yerine, sadece belirli koşulları sağlayan satırları filtrelemek için **WHERE** yan tümcesi kullanılır. WHERE, SELECT sorgu yapısının olmazsa olmazıdır ve veri manipülasyonu (UPDATE, DELETE) komutlarında da kullanılır.

Sözdizimi:

SELECT sutunlar FROM tablo_adi WHERE koşul;

3.1.3 Koşul Oluşturma Kuralları

WHERE ifadesindeki koşullar, genellikle üç ana kısımdan oluşur:

  1. **Sütun Adı:** Koşulun uygulanacağı alan (Örn: `maas`).
  2. **Operatör:** Karşılaştırma operatörü (Örn: `>`, `=` ).
  3. **Değer:** Karşılaştırma yapılacak hedef değer (Örn: `15000` veya `'Ankara'`).

Örnek Kullanım (Eşitlik ve Eşitsizlik):

Personel tablosunda departmanı 'IT' olan ve ID'si 10'dan büyük olanları getirme:

SELECT ad, soyad, maas FROM Personel WHERE departman = 'IT' AND personel_id > 10;

3.1.4 WHERE ve Performans

WHERE koşullarının verimli olması, sorgu performansını doğrudan etkiler. Veritabanı, uygun bir **indeks** bulursa, milyonlarca satırı tek tek taramak (Full Table Scan) yerine, indeksi kullanarak ilgili satırlara çok daha hızlı ulaşır. Bu nedenle, WHERE koşullarında sıkça kullanılan sütunlara (özellikle anahtarlara) indeks tanımlanması, en iyi performansı sağlar.

Kısıtlamalar ve Öncelikler:

  • **Koşul Önceliği:** Karmaşık koşullarda mantıksal operatörler (AND, OR) kullanılırken parante `()` kullanmak, koşulların doğru sırada değerlendirilmesini sağlar.
  • **Veri Tipi Uyumu:** Koşul değerlerinin sütun veri tipiyle eşleşmesi kritik öneme sahiptir. Metin değerleri tek tırnak (`'`) içinde, sayısal değerler tırnaksız yazılmalıdır. Tarih formatları da RDBMS standartlarına uygun olmalıdır (genellikle 'YYYY-MM-DD').

SELECT ve WHERE, tüm SQL yolculuğunuzun başlangıç noktasıdır. Bu temeli sağlam atmak, ileride göreceğimiz karmaşık JOIN'ler ve Alt Sorgular için zorunludur. Unutmayın, iyi bir sorgu, sadece doğru veriyi değil, aynı zamanda veriyi en hızlı şekilde getiren sorgudur.


Detaylı içeriğimizde bu konu ile ilgili daha fazla kod örneği ve performans ipuçları bulacaksınız. Özellikle karmaşık veri tiplerinde (tarih ve metin) filtreleme teknikleri, sonraki başlıklarda derinlemesine ele alınacaktır.

3.2 Karşılaştırma Operatörleri (=, <, >, BETWEEN, LIKE, IN)

Karşılaştırma operatörleri, SELECT, UPDATE ve DELETE komutlarındaki WHERE yan tümcesi içinde, bir sütun değerini sabit bir değerle veya başka bir sütun değeriyle kıyaslamak için kullanılır. Bu operatörler, sonuç kümesindeki satırları filtreleme gücünü sağlar.

3.2.1 Temel Aritmetik Karşılaştırmalar

Sayısal ve tarihsel verileri karşılaştırmak için kullanılırlar:

Operatör Anlamı Örnek Kullanım
= Eşittir WHERE fiyat = 50.00
> Büyüktür WHERE stok > 0
< Küçüktür WHERE tarih < '2024-01-01'
>= Büyük veya eşittir WHERE maas >= 15000
<= Küçük veya eşittir WHERE adet <= 5
<> veya != Eşit değildir WHERE durum <> 'İptal'

3.2.2 BETWEEN Operatörü (Aralık Kontrolü)

BETWEEN operatörü, bir değerin belirli bir aralık içinde olup olmadığını kontrol etmek için kullanılır. **Hem başlangıç hem de bitiş değerleri bu aralığa dahildir (inclusive).** Özellikle tarih ve sayı aralıklarında çok pratiktir.

Sözdizimi: sutun_adi BETWEEN deger_1 AND deger_2

Örnek: 100 ile 500 TL arasındaki ürünleri bulma:

SELECT urun_adi, fiyat FROM Urunler WHERE fiyat BETWEEN 100 AND 500;

Örnek: 2024'ün ilk çeyreğindeki siparişleri bulma:

SELECT * FROM Siparisler WHERE siparis_tarihi BETWEEN '2024-01-01' AND '2024-03-31';

3.2.3 IN Operatörü (Çoklu Eşitlik Kontrolü)

IN operatörü, bir sütun değerinin, parantez içinde belirtilen bir değer listesi (kümesi) içinde yer alıp almadığını kontrol etmek için kullanılır. Çok sayıda `OR` koşulunun kısaltılmış ve okunabilir bir alternatifidir.

Sözdizimi: sutun_adi IN (deger_1, deger_2, ...)

Örnek: Sadece İstanbul, Ankara veya İzmir'de yaşayan müşterileri getirme:

SELECT ad, soyad, sehir FROM Musteriler WHERE sehir IN ('İstanbul', 'Ankara', 'İzmir');

Bu sorgu, aşağıdaki uzun sorgu ile eşdeğerdir:

SELECT ad, soyad, sehir FROM Musteriler WHERE sehir = 'İstanbul' OR sehir = 'Ankara' OR sehir = 'İzmir';

**NOT:** IN operatörü, karmaşık alt sorgularla (Subqueries) birlikte kullanıldığında tam gücüne ulaşır (Bkz: 7. Bölüm).

3.2.4 LIKE Operatörü (Desen Eşleştirme)

LIKE operatörü, metin alanlarında tam eşleşme yerine, bir desen (pattern) ile eşleşen değerleri bulmak için kullanılır. Wildcard karakterler bu operatörle birlikte kullanılır (Bkz: 4.2).

Sözdizimi: sutun_adi LIKE 'desen'

Örnek: Adı 'A' harfi ile başlayan çalışanları bulma:

SELECT ad, soyad FROM Calisanlar WHERE ad LIKE 'A%'; -- % işareti, A'dan sonra herhangi bir karakter dizisinin gelebileceğini belirtir.

Karşılaştırma operatörlerinin doğru kullanımı, hem sorgularınızın hızını (indekslemeyle birleştiğinde) hem de okunabilirliğini artırır. Bu operatörler, SQL'deki tüm filtreleme işlemlerinin temel direğidir.

3.3 ORDER BY – Sıralama ve DISTINCT – Tekil Değerler

SELECT sorguları ile veri çekerken, verinin hangi sırada listeleneceği ve tekrar eden değerlerin dahil edilip edilmeyeceği kritik bir öneme sahiptir. Bu iki amaç için ORDER BY ve DISTINCT yan tümceleri kullanılır.

3.3.1 ORDER BY Yan Tümcesi: Sonuç Sıralaması

ORDER BY, sorgudan dönen sonuç kümesini (result set) belirli bir sütun veya sütunlara göre düzenlemek için kullanılır. Sorgunun en son uygulanan (yani, veriler filtrelendikten ve seçildikten sonra) mantıksal adımıdır.

Sözdizimi:

SELECT sutunlar FROM tablo_adi [WHERE koşul] ORDER BY sutun_1 [ASC | DESC], sutun_2 [ASC | DESC];

Sıralama Tipleri:

  • **ASC (Ascending - Artan):** En küçükten en büyüğe (varsayılan) veya A'dan Z'ye sıralar.
  • **DESC (Descending - Azalan):** En büyükten en küçüğe veya Z'den A'ya sıralar.

Çoklu Sütunla Sıralama (Multi-Level Sorting)

Birden fazla sütun belirterek karmaşık sıralamalar yapılabilir. Sıralama önceliği soldan sağa doğrudur.

Örnek: Önce departmana göre A-Z sırala, ardından aynı departman içindeki maaşları en yüksekten en düşüğe sırala.

SELECT departman, ad, soyad, maas FROM Personel ORDER BY departman ASC, maas DESC;

Sıralamada NULL Değerler

NULL değerlerin sıralamada nerede görüneceği RDBMS'ye bağlıdır. Çoğu sistemde (PostgreSQL, Oracle), NULL değerler `ASC` sıralamada en sonda, `DESC` sıralamada ise en başta yer alır. MySQL'de ise, NULL değerler en küçük değerler olarak kabul edilir ve `ASC` sıralamada başta, `DESC` sıralamada sonda çıkar. Bazı sistemlerde (`NULLS FIRST` veya `NULLS LAST`) komutlarıyla bu durum kontrol edilebilir.

Performans Notu: ORDER BY kullanılan sütunlarda indeks olması, veritabanının verileri hızlıca sıralamasına yardımcı olur ve sorgu performansını büyük ölçüde artırır.

3.3.2 DISTINCT Yan Tümcesi: Tekil Değerler

DISTINCT anahtar kelimesi, sorgu sonucunda tekrar eden tüm satırları kaldırarak sadece benzersiz (tekil) satırları döndürmek için kullanılır. SELECT ifadesinden hemen sonra yer alır.

Sözdizimi:

SELECT DISTINCT sutun_1, sutun_2, ... FROM tablo_adi;

Tekil Değer Örnekleri

1. Bir şirketteki tüm farklı departman isimlerini listeleme:

SELECT DISTINCT departman FROM Personel;

2. Birden fazla sütunda tekillik arama:

Eğer bir müşterinin adı ve soyadı aynı olsa bile, şehri farklıysa, bu kayıtlar DISTINCT tarafından farklı kabul edilir.

SELECT DISTINCT ad, soyad, sehir FROM Musteriler;

Bu sorgu, hem adı hem soyadı hem de şehri aynı olan kayıtları sonuç kümesinden eler. Eğer Ahmet Yılmaz Ankara'da ve başka bir Ahmet Yılmaz İstanbul'da yaşıyorsa, her ikisi de listeye dahil edilir.

Performans Notu: DISTINCT kullanımı, veritabanı motorunu sonuç kümesi üzerinde ek bir sıralama ve gruplama işlemi yapmaya zorlar. Büyük veri setlerinde, gereksiz kullanımdan kaçınılmalıdır, çünkü bu işlem performans kaybına neden olabilir.

Hem ORDER BY hem de DISTINCT, sonuç verisinin nihai sunumu ve analizi için hayati öneme sahiptir. Veri kümesini son kullanıcıya sunmadan önce temizlemek ve mantıksal bir düzene sokmak için bu komutlar vazgeçilmezdir.

3.4 LIMIT – Kayıt Sayısını Sınırlama (Pagination)

Veritabanı sorguları bazen milyonlarca satır döndürebilir. Ancak çoğu zaman, bir kullanıcıya veya uygulamaya bu verinin sadece bir kısmını göstermek (örneğin ilk 10 sonuç) veya sayfalama (pagination) yapmak gerekir. **LIMIT** yan tümcesi (MySQL, PostgreSQL, SQLite'ta kullanılır; SQL Server ve Oracle'da farklı sözdizimleri mevcuttur), bu ihtiyacı karşılamak için kullanılır.

3.4.1 LIMIT Kullanımı ve Sözdizimi

LIMIT, döndürülecek satır sayısını kısıtlamak için kullanılır ve sorgu yapısının en sonunda yer alır.

Temel Sözdizimi:

SELECT sutunlar FROM tablo_adi LIMIT sayi;

Örnek: Tablodaki en son eklenen 5 kaydı bulma (ID'ye göre azalan sırada sıralanmışsa):

SELECT * FROM Kayitlar ORDER BY kayit_id DESC LIMIT 5;

3.4.2 OFFSET Kullanımı: Sayfalama (Pagination)

LIMIT komutu, sadece en üstten değil, belirli bir satırdan başlayarak (atlayarak) veri çekmek için bir başlangıç noktası da belirleyebilir. Bu, web sitelerinde veya uygulamalarda sayfalama (pagination) yapmanın standart yoludur.

Genişletilmiş Sözdizimi:

SELECT sutunlar FROM tablo_adi LIMIT baslangic_satiri_atlana_sayi, gosterilecek_kayit_sayisi;

Veya bazı RDBMS'lerde (PostgreSQL):

SELECT sutunlar FROM tablo_adi LIMIT gosterilecek_kayit_sayisi OFFSET baslangic_satiri_atlana_sayi;

Burada **OFFSET** değeri, sıfırdan başlar. Yani, `OFFSET 10` derseniz, ilk 10 satırı atlar ve 11. satırdan itibaren sonuçları döndürmeye başlar.

Sayfalama Örnekleri (Sayfa başına 10 Kayıt)

  • **Sayfa 1:** İlk 10 kayıt. SELECT * FROM Urunler LIMIT 0, 10; Veya LIMIT 10 OFFSET 0;
  • **Sayfa 2:** 11. kayıttan 20. kayda kadar (İlk 10'u atla, sonraki 10'u getir). SELECT * FROM Urunler LIMIT 10, 10; Veya LIMIT 10 OFFSET 10;
  • **Sayfa 3:** 21. kayıttan 30. kayda kadar (İlk 20'yi atla, sonraki 10'u getir). SELECT * FROM Urunler LIMIT 20, 10; Veya LIMIT 10 OFFSET 20;

3.4.3 Performans ve Güvenlik Etkisi

LIMIT/OFFSET kullanmak, kullanıcıya büyük veri setlerini kademeli olarak gösterdiği için kullanıcı deneyimini artırır ve web sunucusunun aşırı yüklenmesini önler.

  • **Performans Riskleri:** `OFFSET` değeri çok büyük olduğunda (örneğin `OFFSET 1000000`), veritabanı motoru yine de ilk bir milyon satırı okumak ve ardından atmak zorundadır. Bu durum, büyük veri setlerinde sorgu performansını düşürebilir. İleri seviye sayfalama için bu tür durumlarda indekslenmiş sütunları kullanarak filtreleme (Keyset Pagination) yöntemleri tercih edilir.

3.4.4 SQL Server ve Oracle Alternatifleri

Tüm RDBMS'ler LIMIT/OFFSET yapısını desteklemez:

  • **SQL Server:** `OFFSET ... ROWS FETCH NEXT ... ROWS ONLY` yapısını kullanır. SELECT * FROM Urunler ORDER BY urun_id OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
  • **Oracle:** Benzer bir yapı sunar veya daha eski sürümlerde Pencere Fonksiyonları (ROWNUM) ile çözülür.

LIMIT yan tümcesi, hem hız hem de kaynak kullanımı açısından akıllıca sorgu yazmanın temel parçasıdır ve modern web uygulamalarının sayfalama (pagination) motorunun kalbidir.

3.5 AS – Takma Ad (Alias) Kullanımı

SQL'de **AS** anahtar kelimesi (ya da bazı durumlarda atlama), sütunlara veya tablolara geçici, daha okunabilir veya daha kısa isimler atamak için kullanılır. Bu geçici isimlere **Alias** (Takma Ad) denir. Alias'lar sadece sorgunun yürütülmesi sırasında geçerlidir ve veritabanındaki gerçek tablo veya sütun adlarını değiştirmez.

3.5.1 Sütun Alias'ları (Column Aliases)

Sütun alias'ları, özellikle hesaplanmış değerlerin veya karmaşık sütun isimlerinin son kullanıcıya daha anlaşılır bir şekilde sunulması gerektiğinde çok kullanışlıdır.

Sözdizimi:

SELECT sutun_adi AS yeni_sutun_adi, (sutun_A * sutun_B) AS hesaplanmis_sonuc FROM tablo_adi;

**AS** anahtar kelimesi çoğu RDBMS'de isteğe bağlıdır, ancak okunabilirliği artırdığı için kullanılması önerilir.

Örnekler:

1. Hesaplanan maaş artışını gösterme:

SELECT ad, maas, (maas * 0.10) AS zam_miktari, (maas * 1.10) AS yeni_maas FROM Personel;

2. Okunabilirliği artırma:

SELECT p_adi AS ProjeAdi, baslangic_tarihi AS Baslangic FROM Projeler;

**NOT:** Alias adları boşluk içeriyorsa (örneğin: `Yeni Maaş`), RDBMS'ye bağlı olarak çift tırnak (`"Yeni Maaş"` - PostgreSQL) veya ters tırnak (`` `Yeni Maaş` `` - MySQL) içine alınmalıdır.

3.5.2 Tablo Alias'ları (Table Aliases)

Tablo alias'ları, özellikle JOIN işlemlerinde ve alt sorgularda tablonun tam adını tekrar tekrar yazma ihtiyacını ortadan kaldırır. Bu, sorguları kısaltır ve okunabilirliği ciddi ölçüde artırır. Ayrıca, **SELF JOIN** (Tablonun kendi kendine birleştirilmesi) durumunda zorunludur.

Sözdizimi:

SELECT M.ad, S.siparis_tarihi FROM Musteriler AS M INNER JOIN Siparisler AS S ON M.musteri_id = S.musteri_id;

Burada, `Musteriler` tablosuna `M` ve `Siparisler` tablosuna `S` alias'ı verilmiştir. Sütunlara erişirken `M.ad` ve `S.siparis_tarihi` şeklinde kullanılır. Bu kullanım:

  • Hangi sütunun hangi tabloya ait olduğunu açıkça gösterir.
  • Uzun tablo adlarını tekrarlamayı engeller.
  • Sütun isimlerinin farklı tablolarda aynı olması durumunda (Örn: Hem Musteriler hem de Siparisler tablosunda `id` sütunu varsa) karmaşayı önler.

3.5.3 Alias Kullanımının Kısıtlamaları

Sütun alias'ları, aynı `SELECT` ifadesi içinde tanımlandıkları diğer yan tümcelerde (`WHERE`, `GROUP BY`, `HAVING`) hemen kullanılamazlar. Bunun nedeni, sorgu işleme sırasıdır. WHERE yan tümcesi, SELECT ifadesi işlenmeden önce değerlendirilir:

❌ **Hatalı Kullanım Örneği:**

SELECT maas, (maas * 1.10) AS yeni_maas FROM Personel WHERE yeni_maas > 10000; -- HATA: yeni_maas alias'ı WHERE'de henüz tanımlı değil.

✅ **Doğru Kullanım (Alt Sorgu Gerektirir):**

SELECT ad, yeni_maas FROM (SELECT ad, maas * 1.10 AS yeni_maas FROM Personel) AS AltSorgu WHERE yeni_maas > 10000;

Görüldüğü gibi, aynı sorguda `WHERE` ile filtreleme yapmak için, alias'ın tanımlandığı sorgunun bir **Alt Sorgu** olarak kullanılması ve filtrenin dış sorguda uygulanması gerekir. (Bu kural GROUP BY ve HAVING için geçerli değildir, çünkü onlar SELECT'ten sonra işlenir).

Alias kullanımı, karmaşık SQL sorgularını yönetilebilir, profesyonel ve son derece okunabilir hale getirmenin anahtarıdır.

4.1 AND, OR, NOT Kullanımı (Mantıksal Operatörler)

Mantıksal operatörler, WHERE yan tümcesi içinde birden fazla koşulu birleştirmek veya mevcut bir koşulu tersine çevirmek için kullanılır. Bu operatörler, sonuç kümesi üzerindeki kontrolünüzü katmanlı bir şekilde artırmanıza olanak tanır.

4.1.1 AND Operatörü (Tüm Koşullar Doğru Olmalı)

AND operatörü, iki koşulun da aynı anda doğru olması durumunda true (doğru) döndürür. Sonuç kümesini daraltmak ve çok özel kayıtları hedeflemek için kullanılır.

Örnek: 15000 TL'den fazla maaş alan ve aynı zamanda 'Yazılım' departmanında çalışan personeli bulma.

SELECT ad, soyad, maas, departman FROM Personel WHERE maas > 15000 AND departman = 'Yazılım';

4.1.2 OR Operatörü (Koşullardan Biri Doğru Olmalı)

OR operatörü, koşullardan **en az birinin** doğru olması durumunda true (doğru) döndürür. Sonuç kümesini genişletmek ve alternatif koşulları dahil etmek için kullanılır.

Örnek: Ya 'Satış' departmanında çalışanları ya da 'Yönetim' departmanında çalışanları bulma.

SELECT ad, soyad, departman FROM Personel WHERE departman = 'Satış' OR departman = 'Yönetim';

4.1.3 NOT Operatörü (Koşulun Tersi)

NOT operatörü, bir koşulun sonucunu tersine çevirir. True olanı False, False olanı True yapar. NOT, genellikle başka bir operatörle birlikte kullanılır (Örn: NOT IN, NOT LIKE).

Örnek: Departmanı 'IT' olmayan tüm personeli bulma.

SELECT ad, soyad, departman FROM Personel WHERE NOT departman = 'IT'; -- Veya daha yaygın: -- WHERE departman <> 'IT';

Örnek: Adresi NULL olmayan kayıtları bulma.

SELECT * FROM Musteriler WHERE NOT adres IS NULL; -- Veya daha yaygın: -- WHERE adres IS NOT NULL; (Bkz: 4.3)

4.1.4 Koşul Önceliği ve Parantez Kullanımı

Birden fazla mantıksal operatör bir arada kullanıldığında, SQL'de operatör önceliği kuralı geçerlidir:

**Öncelik Sırası: NOT > AND > OR**

Yani AND, OR'dan önce değerlendirilir. Bu, beklenmedik sonuçlara yol açabilir. Bu nedenle, koşulların değerlendirme sırasını açıkça belirtmek için **parante `()`** kullanılması şiddetle önerilir.

Senaryo: Departmanı 'Yazılım' olan VEYA 'Muhasebe' departmanında 10000 TL'den fazla maaş alanlar.

❌ **Yanlış Kullanım (AND önce işlenir):**

SELECT * FROM Personel WHERE departman = 'Yazılım' OR departman = 'Muhasebe' AND maas > 10000; -- Sonuç: Yazılım departmanının tümü VEYA Muhasebe departmanında maaşı 10000'den fazla olanlar.

✅ **Doğru Kullanım (Parantezle):**

SELECT * FROM Personel WHERE (departman = 'Yazılım' OR departman = 'Muhasebe') AND maas > 10000; -- Sonuç: SADECE Yazılım ve Muhasebe departmanlarında olup, maaşı 10000'den fazla olanlar.

Parantezler, SQL'de koşulları gruplandırarak istenen mantıksal yapının net bir şekilde uygulanmasını sağlar. Karmaşık filtreleme işlemleri yaparken parantez kullanımı bir zorunluluktur.

4.2 LIKE ve Wildcard Karakterleri (%, _)

LIKE operatörü, metin verilerinde kesin eşitlik yerine, belirli bir desen (pattern) ile eşleşen değerleri bulmak için kullanılır. Özellikle tam metin araması yapmanın mümkün olmadığı veya gerekli olmadığı durumlarda çok kullanışlıdır. LIKE ile birlikte kullanılan özel karakterlere **Wildcard** (Joker Karakter) denir.

4.2.1 Wildcard Karakterleri

SQL'de iki temel wildcard karakteri kullanılır:

Karakter Anlamı Kullanım Amacı
% (Yüzde) Sıfır, bir veya daha fazla karakter dizisini temsil eder. Metin parçasının başında, ortasında veya sonunda herhangi bir uzunlukta karakter dizisi olabileceği anlamına gelir.
_ (Alt Çizgi) Tam olarak tek bir karakteri temsil eder. Belirli bir pozisyonda herhangi bir karakter olabileceği, ancak sadece tek bir karakter olabileceği anlamına gelir.

4.2.2 LIKE Operatörü Örnekleri

Aşağıdaki örnekler, `urun_adi` sütunu üzerinde uygulanmaktadır:

  • **Başlangıç Eşleşmesi (StartsWith):** 'A' harfi ile başlayan ürünler. WHERE urun_adi LIKE 'A%'; (Örn: Armut, Araba, Akıl)
  • **Bitiş Eşleşmesi (EndsWith):** 'Masası' ile biten ürünler. WHERE urun_adi LIKE '%Masası'; (Örn: Yemek Masası, Çalışma Masası)
  • **İçerme Eşleşmesi (Contains):** 'Bilgisayar' kelimesini içeren ürünler. WHERE urun_adi LIKE '%Bilgisayar%'; (Örn: Laptop Bilgisayar, Bilgisayar Kablosu)
  • **Belirli Karakter Pozisyonu Eşleşmesi (Tek Karakter):** İkinci harfi 'a' olan ürünler. WHERE urun_adi LIKE '_a%'; (Örn: Masa, Kitap)
  • **Belirli Uzunluk Eşleşmesi:** Tam olarak 5 harften oluşan isimler. WHERE urun_adi LIKE '_____'; (Beş adet alt çizgi)

4.2.3 NOT LIKE Kullanımı

LIKE operatörü, NOT ile birleştirilerek belirli bir desene uymayan değerleri filtrelemek için kullanılır. Bu, desenin tersini bulmak için çok güçlü bir araçtır.

Örnek: Adında 'kablo' kelimesi geçmeyen tüm ürünleri getir.

SELECT urun_adi FROM Urunler WHERE urun_adi NOT LIKE '%kablo%';

4.2.4 LIKE ve Performans

LIKE operatörünün performansı, wildcard (`%`) karakterinin kullanım yerine bağlıdır:

  • **Hızlı (İndeks Kullanımı Mümkün):** Desen bir harfle başlıyorsa (Örn: `WHERE ad LIKE 'A%'`). Bu durumda veritabanı, sütunun indeksini kullanarak sadece 'A' ile başlayan kayıtlara hızla odaklanabilir.
  • **Yavaş (Full Scan Gerekli):** Desen bir wildcard ile başlıyorsa (Örn: `WHERE ad LIKE '%an'`). Bu durumda veritabanı, desenin nerede başlayacağını bilemediği için tablodaki tüm metin değerlerini tek tek okumak zorundadır. Bu, büyük tablolarda performansı önemli ölçüde düşürür.

Performansın kritik olduğu durumlarda, metin içeren arama işlemleri için LIKE yerine Full-Text Search (Tam Metin Arama) motorlarının kullanılması daha verimli bir çözümdür.

4.3 IS NULL, IS NOT NULL Kontrolleri

SQL'de **NULL**, "bilinmeyen" veya "tanımlanmamış" bir değeri ifade eder. Sıfır veya boş bir metin (`''`) anlamına gelmez. NULL değerler, özel bir karşılaştırma mekanizması gerektirir, çünkü bir değerin NULL olup olmadığını kontrol etmek için standart karşılaştırma operatörleri (`=`, `!=`) kullanılamaz.

4.3.1 NULL Değerinin Mantığı

SQL'de hiçbir şey NULL'a eşit değildir, hatta NULL'un kendisi bile! Çünkü iki bilinmeyen değerin birbirine eşit olup olmadığını bilemeyiz. Bu nedenle, aşağıdaki sorgu her zaman False döndürür (veya beklenen satırları döndürmez):

-- YANLIŞ KULLANIM! (Hata vermez ama beklenen sonucu getirmez) WHERE adres = NULL;

4.3.2 IS NULL Operatörü

Bir sütundaki değerin **NULL** olup olmadığını kontrol etmek için **IS NULL** operatörü kullanılır.

Örnek: Telefon numarası alanını doldurmamış müşterileri listeleme (Bilgisi bilinmiyor).

SELECT ad, soyad, telefon FROM Musteriler WHERE telefon IS NULL;

Bu, genellikle eksik veri setlerini bulmak veya formlarda doldurulması zorunlu olmayan alanları analiz etmek için kullanılır.

4.3.3 IS NOT NULL Operatörü

Bir sütundaki değerin NULL **olmadığını** kontrol etmek için **IS NOT NULL** operatörü kullanılır. Bu, bir değere sahip olan (yani bilgisi bilinen) tüm kayıtları döndürür.

Örnek: Bitiş tarihi girilmiş (yani tamamlanmış) projeleri listeleme.

SELECT proje_adi, bitis_tarihi FROM Projeler WHERE bitis_tarihi IS NOT NULL;

Bu sorgu, bitiş tarihi girilen tüm kayıtları döndürür. Bitiş tarihi alanında boş metin (`''`) veya sıfır (eğer sayısal bir alansa) varsa, bunlar da IS NOT NULL filtresinden geçer, çünkü bunlar NULL değildir, sadece içeriği sıfır veya boş metin olan değerlerdir.

4.3.4 COALESCE ve NULLIF Fonksiyonları

NULL değerleri yönetmek için kullanışlı iki standart fonksiyon mevcuttur:

  • **COALESCE:** Birden çok argüman alır ve NULL olmayan ilk ifadeyi döndürür. Genellikle bir NULL değeri, okunabilir bir varsayılan değerle değiştirmek için kullanılır. SELECT ad, COALESCE(telefon, 'Telefon Yok') AS Iletisim FROM Musteriler;
  • **NULLIF:** İki argüman alır. Eğer iki argüman birbirine eşitse NULL döndürür, aksi halde ilk argümanı döndürür. Bu, bir değerin özel bir anlama sahip olduğu (Örn: 0'ın bilinmeyen anlamına geldiği) durumlarda kullanışlıdır. SELECT NULLIF(stok_adet, 0) AS GercekStok FROM Urunler;

NULL değerlerin doğasını anlamak ve IS NULL/IS NOT NULL operatörlerini doğru kullanmak, veri bütünlüğünü korumak ve güvenilir raporlar hazırlamak için SQL'deki en temel ve önemli becerilerden biridir.

5.1 GROUP BY ve HAVING

Veritabanından çekilen bireysel satırları analiz etmek yerine, bu satırları belirli özelliklerine göre gruplandırmak ve her bir grup için özet bilgiler (toplam, ortalama, sayım) elde etmek için **GROUP BY** ve **HAVING** yan tümceleri kullanılır. Bu, SQL'de temel raporlama ve veri analizi işlemlerinin kalbidir.

5.1.1 GROUP BY Yan Tümcesi

GROUP BY, SELECT sorgusunun sonuç kümesini, belirtilen sütunlardaki aynı değerlere sahip satırları tek bir özet satırda toplayacak şekilde gruplandırır. Gruplama işlemi, genellikle toplama fonksiyonlarıyla (COUNT, SUM, AVG) birlikte anlam kazanır.

Sözdizimi ve Kuralı:

SELECT gruplama_sutunu, toplama_fonksiyonu(sutun_adi) FROM tablo_adi [WHERE koşul] GROUP BY gruplama_sutunu;

⚠️ **Temel Kural:** SELECT ifadesinde, toplama fonksiyonu içinde yer almayan her sütun, mutlaka GROUP BY yan tümcesinde de yer almalıdır. Aksi halde, veritabanı hangi bireysel satır değerini göstereceğine karar veremez.

Örnek: Her departmanda kaç personel olduğunu sayma.

SELECT departman, COUNT(personel_id) AS CalisanSayisi FROM Personel GROUP BY departman;

Bu sorgu, "Yazılım", "Satış", "IK" gibi her bir departman adı için, o departmana ait personel sayısını döndürür.

5.1.2 HAVING Yan Tümcesi

WHERE yan tümcesi, gruplama yapılmadan önce tek tek satırları filtreler. Ancak, bir toplama fonksiyonunun (SUM, COUNT vb.) sonucuna göre filtreleme yapmak için **HAVING** yan tümcesi kullanılır.

  • **WHERE:** Tek tek satırlara uygulanır. (Örn: Maaşı 10000'den büyük olan satırları bul).
  • **HAVING:** Gruplandırılmış satırlara uygulanır. (Örn: Çalışan sayısı 5'ten fazla olan grupları/departmanları bul).

Sözdizimi:

SELECT gruplama_sutunu, toplama_fonksiyonu(sutun) FROM tablo_adi GROUP BY gruplama_sutunu HAVING toplama_kosulu;

Örnek: Ortalama maaşı 12000 TL'den fazla olan departmanları bulma.

SELECT departman, AVG(maas) AS OrtalamaMaas FROM Personel GROUP BY departman HAVING OrtalamaMaas > 12000;

5.1.3 GROUP BY, WHERE ve HAVING'in Birlikte Kullanımı

Bu üç yan tümce, sorgunun akışında belirli bir sırayı takip eder ve birbirlerini tamamlarlar:

  1. **FROM:** Verinin alınacağı tablo belirlenir.
  2. **WHERE:** Tek tek satırlar gruplama başlamadan önce filtrelenir.
  3. **GROUP BY:** Geriye kalan satırlar gruplar halinde toplanır.
  4. **HAVING:** Oluşan bu gruplar, toplama fonksiyonu sonuçlarına göre filtrelenir.
  5. **SELECT:** Nihai sonuç kümesi ve formatı belirlenir.
  6. **ORDER BY:** Nihai sonuç kümesi sıralanır.

Kapsamlı Örnek:

Departmanı 'Yazılım' veya 'Analiz' olan personelden, çalışan sayısı 5'ten fazla olan grupları, ortalama maaşlarına göre azalan sırada listeleme.

SELECT departman, COUNT(personel_id) AS CalisanSayisi, AVG(maas) AS Ortalama FROM Personel WHERE departman IN ('Yazılım', 'Analiz') -- Grup öncesi filtre GROUP BY departman HAVING CalisanSayisi > 5 -- Grup sonrası filtre ORDER BY Ortalama DESC;

GROUP BY ve HAVING, karmaşık iş gereksinimlerini karşılayan, özetlenmiş ve filtrelenmiş raporlar oluşturmanın temel anahtarıdır.

5.2 COUNT(), SUM(), AVG(), MIN(), MAX() Fonksiyonları (Aggregate)

Toplama (Aggregate) fonksiyonları, bir dizi satır üzerinde bir hesaplama yapar ve tek bir özet değer döndürür. Bu fonksiyonlar, ister bir tablonun tamamına ister GROUP BY ile oluşturulan her bir gruba uygulansın, veri analizi ve özetleme için vazgeçilmezdir.

5.2.1 COUNT() - Sayım

Gruptaki satır sayısını döndürür.

  • **COUNT(\*):** NULL dahil olmak üzere tüm satırları sayar.
  • **COUNT(sutun_adi):** Yalnızca o sütunda NULL olmayan değerlere sahip satırları sayar.
  • **COUNT(DISTINCT sutun_adi):** Belirtilen sütundaki tekil ve NULL olmayan değerlerin sayısını döndürür.

Örnekler:

-- Tablodaki toplam kayıt sayısı (en hızlı yöntem) SELECT COUNT(*) FROM Musteriler; -- Farklı şehirlerin sayısı (tekrarsız) SELECT COUNT(DISTINCT sehir) FROM Musteriler;

5.2.2 SUM() - Toplam

Sayısal bir sütundaki tüm değerlerin toplamını döndürür. Metin veya tarih sütunlarında kullanılamaz. NULL değerler, toplam hesaplamasına dahil edilmez (göz ardı edilir).

Örnek: Tüm siparişlerin toplam tutarını hesaplama.

SELECT SUM(toplam_tutar) AS GenelCiro FROM Siparisler;

5.2.3 AVG() - Ortalama

Sayısal bir sütundaki değerlerin ortalamasını döndürür (Toplam / Sayı). Tıpkı SUM gibi, NULL değerleri göz ardı eder.

Örnek: Departman bazında ortalama maaş hesabı.

SELECT departman, AVG(maas) AS OrtalamaMaas FROM Personel GROUP BY departman;

Ortalama hesaplamasına sadece tekil değerleri dahil etmek isterseniz: `AVG(DISTINCT maas)` kullanabilirsiniz.

5.2.4 MIN() ve MAX() - Minimum ve Maksimum

Bir sütundaki en küçük (MIN) ve en büyük (MAX) değeri döndürür. Sayısal, metin ve tarih sütunlarında kullanılabilir.

  • Sayısalda: En küçük/büyük sayıyı bulur.
  • Metinde: Alfabetik olarak ilk/son değeri bulur.
  • Tarihte: En eski/en yeni tarihi bulur.

Örnekler:

-- En yüksek ve en düşük fiyatlı ürünleri bulma SELECT MIN(fiyat) AS EnDusuk, MAX(fiyat) AS EnYuksek FROM Urunler; -- En son sipariş tarihini bulma SELECT MAX(siparis_tarihi) AS SonSiparis FROM Siparisler;

5.2.5 Toplama Fonksiyonu Kullanım Kuralları

  1. **NULL İhmali:** Tüm toplama fonksiyonları, aksi belirtilmedikçe (Örn: `COUNT(*)`) NULL değerleri otomatik olarak göz ardı eder.
  2. **SELECT ve GROUP BY İlişkisi:** Bir toplama fonksiyonu kullanıldığında, `SELECT` listesindeki toplama fonksiyonu olmayan tüm diğer sütunlar `GROUP BY` yan tümcesinde yer almalıdır.
  3. **NESTED (İç İçe) Kullanım:** Toplama fonksiyonları birbiri içinde iç içe kullanılamaz (Örn: `AVG(SUM(sutun))`). Ancak bu durumlarda alt sorgular (Subqueries) kullanılmalıdır.

Toplama fonksiyonları, büyük veri setlerini saniyeler içinde özetleyebilen, iş kararları için kritik öneme sahip temel SQL araçlarıdır. GROUP BY ile birleştirilerek kullanıldığında, detaylı ve anlamlı iş raporları oluşturmanın önünü açar.

5.3 Toplu Rapor Oluşturma Örnekleri (Pratik Uygulamalar)

Toplama fonksiyonları, GROUP BY ve HAVING'i birleştirerek, gerçek dünya iş senaryolarında kullanılan karmaşık özet raporları oluşturabiliriz. Bu örnekler, öğrenilen konuların nasıl bir araya geldiğini göstermektedir.

5.3.1 Örnek 1: Müşteri Segmentasyon Raporu

Hangi şehirlerin şirkete en çok ciro getirdiğini ve bu cironun kaç siparişten oluştuğunu gösteren bir rapor. Sadece toplam cirosu 10000 TL'yi aşan şehirler listelenecektir.

Kullanılan Tablolar: `Musteriler (musteri_id, sehir)`, `Siparisler (musteri_id, toplam_tutar)`.

SELECT M.sehir, COUNT(S.siparis_id) AS ToplamSiparisAdedi, SUM(S.toplam_tutar) AS ToplamCiro FROM Musteriler M INNER JOIN Siparisler S ON M.musteri_id = S.musteri_id GROUP BY M.sehir HAVING ToplamCiro > 10000 ORDER BY ToplamCiro DESC;

Bu sorgu adımları:

  1. **INNER JOIN:** Müşteri ve Sipariş tablolarını birleştirir.
  2. **GROUP BY sehir:** Sonuçları her bir şehir için gruplar.
  3. **COUNT/SUM:** Her grup için sipariş adedi ve toplam ciroyu hesaplar.
  4. **HAVING:** Toplam cirosu 10000'den büyük olan grupları tutar.
  5. **ORDER BY:** En yüksek cirodan en düşüğe sıralar.

5.3.2 Örnek 2: En Başarılı Ürün Kategorileri

En az 5 farklı siparişte satılmış olan ve ortalama birim fiyatı 50 TL'nin altında kalan ürün kategorilerini listeleme.

Kullanılan Tablo: `Urunler (kategori, birim_fiyat)`.

SELECT kategori, COUNT(DISTINCT urun_id) AS FarkliUrunSayisi, AVG(birim_fiyat) AS OrtalamaFiyat FROM Urunler WHERE birim_fiyat > 0 -- Grup öncesi filtre (Fiyatı olmayanları ele) GROUP BY kategori HAVING COUNT(urun_id) >= 5 AND AVG(birim_fiyat) < 50 ORDER BY OrtalamaFiyat ASC;

Bu rapor, düşük fiyatlı ve popüler (en az 5 farklı ürün içeren) kategorileri hedefleyerek, stok ve pazarlama kararları için bilgi sağlar.

5.3.3 Örnek 3: Aylık İşlem Analizi

Belirli bir yıldaki aylık işlem sayısını ve aylık toplam işlem hacmini gösteren rapor.

Kullanılan Tablo: `Islemler (islem_tarihi, islem_tutari)`.

Bu örnek, tarih fonksiyonlarının `GROUP BY` ile nasıl kullanıldığını gösterir (Sözdizimi RDBMS'ye göre değişebilir. MySQL/PostgreSQL uyumlu kullanılmıştır).

SELECT YEAR(islem_tarihi) AS Yil, MONTH(islem_tarihi) AS Ay, COUNT(islem_id) AS AylikIslemSayisi, SUM(islem_tutari) AS AylikHacim FROM Islemler WHERE YEAR(islem_tarihi) = 2024 -- Sadece 2024 yılını filtrele (Grup öncesi) GROUP BY Yil, Ay ORDER BY Yil ASC, Ay ASC;

Tarihi yıl ve ay olarak gruplamak, zaman serisi analizi ve trend raporları için kritik öneme sahiptir. Bu tür toplu raporlar, bir iş zekası (Business Intelligence) aracının temelini oluşturur.

6.1 Birincil ve Yabancı Anahtarlar (PRIMARY / FOREIGN KEY)

İlişkisel Veritabanı Yönetim Sistemlerinin (RDBMS) temel taşı, verileri mantıksal olarak birbirine bağlayan ilişkilerdir. Bu ilişkiler, veri bütünlüğünü ve tutarlılığını sağlamak için kullanılan **Birincil (Primary)** ve **Yabancı (Foreign)** anahtarlar aracılığıyla kurulur.

6.1.1 Birincil Anahtar (PRIMARY KEY)

**PRIMARY KEY**, bir tablodaki her satırı benzersiz bir şekilde tanımlayan bir sütun (veya sütunlar kümesi) veya bir kısıtlamadır (Constraint). Veritabanı tasarımında, her tablonun mutlaka bir Birincil Anahtarı olmalıdır.

  • **Benzersizlik (Unique):** Birincil Anahtar sütunundaki her değer birbirinden farklı olmalıdır.
  • **NULL Olmama (NOT NULL):** Birincil Anahtar sütununda boş (NULL) değer bulunamaz.
  • **Otomatik İndeksleme:** Veritabanı sistemleri (MySQL, vb.), genellikle Primary Key için otomatik olarak bir İndeks oluşturur, bu da veri erişimini ve arama işlemlerini hızlandırır.

Tanımlama Örneği (Tablo Oluşturma sırasında):

CREATE TABLE Personel ( personel_id INT NOT NULL PRIMARY KEY, -- Personeli benzersiz kılar ad VARCHAR(50), soyad VARCHAR(50) );

6.2 INNER JOIN, LEFT JOIN ve RIGHT JOIN

Veritabanında JOIN (Birleştirme) işlemleri, birden fazla tablodaki verileri ilişkili sütunlar (genellikle Foreign Key) üzerinden bir araya getirmek için kullanılır. En temel ve yaygın kullanılan üç JOIN türü şunlardır:

  • INNER JOIN (İç Birleştirme): İki tablodaki sadece eşleşen satırları getirir. Yani, her iki tabloda da bir karşılığı olan kayıtlar sonuç kümesinde yer alır. Eşleşme olmayan satırlar tamamen dışarıda bırakılır.
    SELECT * FROM TabloA INNER JOIN TabloB ON TabloA.anahtar = TabloB.yabanci_anahtar;
  • LEFT JOIN (Sol Dış Birleştirme): Sol (birinci) tablodaki tüm satırları getirir. Sağ tablodan (ikinci) ise sadece sol tablodaki satırlarla eşleşenleri getirir. Sol tablodaki bir satırın sağ tabloda eşleşeni yoksa, sağ tablonun sütunları için NULL değeri döndürülür.
    SELECT * FROM TabloA LEFT JOIN TabloB ON TabloA.anahtar = TabloB.yabanci_anahtar;
  • RIGHT JOIN (Sağ Dış Birleştirme): Sağ (ikinci) tablodaki tüm satırları getirir. Sol tablodan (birinci) ise sadece sağ tablodaki satırlarla eşleşenleri getirir. Sağ tablodaki bir satırın sol tabloda eşleşeni yoksa, sol tablonun sütunları için NULL değeri döndürülür.
    SELECT * FROM TabloA RIGHT JOIN TabloB ON TabloA.anahtar = TabloB.yabanci_anahtar;

6.3 FULL OUTER JOIN ve SELF JOIN

Bu iki JOIN türü, özel veri birleştirme senaryolarında kullanılır:

  • FULL OUTER JOIN (Tüm Dış Birleştirme): İki tablodaki tüm satırları, eşleşme olsun veya olmasın, sonuç kümesine dahil eder. Eşleşmeyen satırlar için diğer tablonun sütunlarına NULL değeri atanır. MySQL doğrudan FULL OUTER JOIN komutunu desteklemez. Bunun yerine, LEFT JOIN ve RIGHT JOIN sonuçlarını UNION ile birleştirme yöntemi kullanılır.
    -- MySQL'de FULL OUTER JOIN Emülasyonu SELECT * FROM TabloA LEFT JOIN TabloB ON TabloA.id = TabloB.id UNION SELECT * FROM TabloA RIGHT JOIN TabloB ON TabloA.id = TabloB.id;
  • SELF JOIN (Öz Birleştirme): Bir tablonun kendi kendisiyle birleştirilmesi işlemidir. Genellikle bir tablodaki veriler arasında hiyerarşik ilişki (örneğin, çalışan-yönetici ilişkisi) olduğunda veya aynı tablodaki satırları belirli bir kritere göre karşılaştırmak gerektiğinde kullanılır. Bu işlem için tabloya farklı takma adlar (alias) verilmesi zorunludur.
    SELECT C.Ad AS CalisanAdi, Y.Ad AS YoneticiAdi FROM Calisanlar AS C INNER JOIN Calisanlar AS Y ON C.YoneticiID = Y.CalisanID;

6.4 UNION ve UNION ALL

UNION operatörleri, birden fazla SELECT sorgusunun sonuçlarını tek bir sonuç kümesinde birleştirmek için kullanılır. Bu operatörlerin kullanılabilmesi için birleştirilen sorguların:

  1. Aynı sayıda sütuna sahip olması,
  2. Karşılık gelen sütunların veri tiplerinin uyumlu olması gerekir.
  • UNION: Sonuç kümesindeki yinelenen (duplicate) satırları kaldırır ve sadece benzersiz satırları döndürür. Bu nedenle, sonuç kümesini oluştururken bir ek maliyet (tekilleştirme) gerektirir.
    SELECT Ad, Soyad FROM Calisanlar UNION SELECT Ad, Soyad FROM Musteriler;
  • UNION ALL: Sonuç kümesindeki tüm satırları olduğu gibi döndürür, yinelenenleri kontrol etmez ve kaldırmaz. Tekilleştirme maliyeti olmadığı için UNION'a göre genellikle daha hızlıdır ve performans kritik uygulamalarda tercih edilmelidir.
    SELECT UrunAdi, Fiyat FROM StokA UNION ALL SELECT UrunAdi, Fiyat FROM StokB;

7.1 Tek ve Çok Satırlı Alt Sorgular (Subqueries)

Alt sorgu (Subquery), başka bir SQL sorgusu (dış sorgu) içine yerleştirilmiş olan bir sorgudur. İç sorgu önce çalışır ve sonuçları dış sorgu tarafından kullanılır. Alt sorgular, sorguları daha modüler ve okunabilir hale getirir.

  • Tek Satırlı Alt Sorgular (Single-Row Subqueries): Alt sorgunun sadece tek bir değer (bir sütun ve bir satır) döndürdüğü durumlardır. Bu sorgular, dış sorguda tek değer karşılaştırma operatörleri (=, >, <, <=, >=, <>) ile kullanılır.
    -- Ortalama maaştan yüksek maaş alan çalışanları bulma SELECT Ad, Maas FROM Calisanlar WHERE Maas > (SELECT AVG(Maas) FROM Calisanlar);
  • Çok Satırlı Alt Sorgular (Multi-Row Subqueries): Alt sorgunun bir sütunda birden fazla değer döndürdüğü durumlardır. Bu sorgular, dış sorguda çoklu değer operatörleri (IN, NOT IN, ANY, ALL) ile kullanılır.
    -- Satış departmanındaki çalışanları bulma SELECT Ad, Soyad FROM Calisanlar WHERE DepartmanID IN (SELECT DepartmanID FROM Departmanlar WHERE DepartmanAdi = 'Satis');

7.2 EXISTS, IN, ANY, ALL ile Alt Sorgular

Çok satırlı alt sorgularla birlikte kullanılan önemli operatörler:

  • IN / NOT IN: * IN: Bir değerin, alt sorgu tarafından döndürülen değer kümesi içinde olup olmadığını kontrol eder. Eşleşme varsa TRUE döndürür. * NOT IN: Bir değerin, alt sorgu tarafından döndürülen değer kümesi içinde olmadığını kontrol eder.
    -- IN Örneği: En az bir sipariş vermiş olan müşteriler SELECT Ad FROM Musteriler WHERE MusteriID IN (SELECT DISTINCT MusteriID FROM Siparisler);
  • EXISTS / NOT EXISTS (Bağıntılı Alt Sorgu): * EXISTS: Alt sorgunun en az bir satır döndürüp döndürmediğini kontrol eder. Eğer alt sorgu bir satır döndürürse (içinde veri varsa), TRUE döndürür. EXISTS operatörü genellikle dış sorgudaki bir sütuna bağlı (bağıntılı) alt sorgularda kullanılır ve performans açısından IN'e göre daha avantajlı olabilir, çünkü sadece varlığını kontrol eder, tüm değerleri listelemez.
    -- EXISTS Örneği: Siparişi olan müşteriler SELECT Ad FROM Musteriler M WHERE EXISTS (SELECT 1 FROM Siparisler S WHERE S.MusteriID = M.MusteriID);
  • ANY / SOME: Tek bir sütunda yer alan değerlerden herhangi biriyle karşılaştırmayı doğru kılan satırları getirir. Örneğin, > ANY demek, alt sorgu sonuçlarındaki en küçük değerden bile büyük demektir.
    -- Fiyatı, herhangi bir 'Gıda' ürününün fiyatından daha yüksek olan ürünler SELECT UrunAdi FROM Urunler WHERE Fiyat > ANY (SELECT Fiyat FROM Urunler WHERE Kategori = 'Gida');
  • ALL: Tek bir sütunda yer alan değerlerden tümüyle karşılaştırmayı doğru kılan satırları getirir. Örneğin, > ALL demek, alt sorgu sonuçlarındaki en büyük değerden bile büyük demektir.
    -- Fiyatı, tüm 'Giyim' ürünlerinin fiyatından daha yüksek olan ürünler SELECT UrunAdi FROM Urunler WHERE Fiyat > ALL (SELECT Fiyat FROM Urunler WHERE Kategori = 'Giyim');

8.1 Görünümler (VIEW) ve İndeksler (INDEX)

Veritabanı nesneleri, temel tablo yapılarının ötesinde ek işlevsellik, güvenlik ve performans sağlayan yapılardır.

⭐ Görünümler (VIEW)

  • Tanım: Bir veya daha fazla tablodan veri çeken bir sanal tablodur. Görünümün kendisi fiziksel olarak veri depolamaz; yalnızca tanımlandığı sorgunun sonucunu saklar.
  • Kullanım Amaçları:
    • Güvenlik: Kullanıcıların tüm tabloya değil, yalnızca görünümün gösterdiği kısıtlı sütunlara ve satırlara erişimini sağlamak.
    • Karmaşıklığı Azaltma: Karmaşık JOIN işlemleri veya koşullu sorguları tek bir ad altında basitleştirmek.
    • Tutarlılık: Belirli iş mantığına göre filtre uygulanmış veya hesaplanmış verileri her zaman aynı şekilde sunmak.
  • Oluşturma (CREATE VIEW):
    CREATE VIEW YuksekMaasliCalisanlar AS SELECT Ad, Soyad, Unvan FROM Calisanlar WHERE Maas > 50000;
    
    -- Görünümü Kullanma SELECT * FROM YuksekMaasliCalisanlar WHERE Unvan = 'Yonetici';

⚡ İndeksler (INDEX)

  • Tanım: Bir tablodaki verilere daha hızlı erişim sağlamak için kullanılan özel arama yapılarıdır. Tıpkı bir kitabın dizini gibi, belirli değerlere karşılık gelen satırların fiziksel konumlarını tutarlar.
  • Performansa Etkisi: WHERE yan tümcesinde, JOIN koşullarında ve ORDER BY işlemlerinde kullanılan sütunlarda büyük ölçüde okuma (SELECT) performansını artırır.
  • Maliyet: INSERT, UPDATE ve DELETE işlemlerini yavaşlatır, çünkü her veri değişikliğinde indeksin de güncellenmesi gerekir. Aynı zamanda ek disk alanı kullanır.
  • Türler:
    • PRIMARY KEY Index: Tablonun birincil anahtarı otomatik olarak indekslenir.
    • UNIQUE Index: İndekslenen sütunlardaki değerlerin benzersizliğini garanti eder ve hızlı arama sağlar.
    • B-Tree Index: MySQL'de en yaygın indeks türüdür, sıralı arama ve aralık sorguları için optimize edilmiştir.
  • Oluşturma (CREATE INDEX):
    -- UrunAdi sütununda arama performansını artırmak için indeks oluşturma CREATE INDEX idx_urun_ad ON Urunler (UrunAdi);
    
    -- Birden fazla sütundan oluşan bileşik indeks CREATE INDEX idx_soyad_ad ON Calisanlar (Soyad, Ad);

8.2 Saklı Yordamlar (STORED PROCEDURE) ve Tetikleyiciler (TRIGGER)

Bu nesneler, karmaşık iş mantığını doğrudan veritabanı katmanında uygulamamızı sağlar.

⚙️ Saklı Yordamlar (STORED PROCEDURE)

  • Tanım: Tek bir komut gibi çalıştırılabilen, veritabanında saklanan, bir veya daha fazla SQL ifadesinden oluşan bir kod bloğudur.
  • Avantajları:
    • Performans: Yordamlar veritabanında derlenmiş olarak tutulur, bu da ağ trafiğini azaltır ve sorgu çalıştırma süresini hızlandırır.
    • Güvenlik: Kullanıcılar/uygulamalar, tabloları doğrudan değiştirmek yerine yalnızca yordamları çalıştırmak için yetkilendirilebilir.
    • Modülerlik: Tekrar eden görevleri merkezileştirir ve uygulama mantığını basitleştirir.
  • Kullanım: Giriş (IN) ve Çıkış (OUT) parametreleri alabilir.
  • Oluşturma ve Çağırma:
    -- Yordam Oluşturma DELIMITER // CREATE PROCEDURE UrunFiyatiGuncelle (IN urun_id INT, IN yeni_fiyat DECIMAL(10,2)) BEGIN UPDATE Urunler SET Fiyat = yeni_fiyat WHERE ID = urun_id; END // DELIMITER ;
    
    -- Yordamı Çağırma CALL UrunFiyatiGuncelle(101, 49.99);

💥 Tetikleyiciler (TRIGGER)

  • Tanım: Bir tablonun üzerinde belirli bir olay (INSERT, UPDATE veya DELETE işlemi) gerçekleştiğinde otomatik olarak çalışan özel bir yordam türüdür.
  • Zamanlama: Olaydan önce (BEFORE) veya olaydan sonra (AFTER) çalışacak şekilde tanımlanır.
  • Kullanım Alanları:
    • Denetim (Auditing): Veri değişikliklerini (kim, ne zaman, hangi değeri) bir günlük (log) tablosuna kaydetmek.
    • Veri Bütünlüğü: Otomatik olarak başka bir tablonun güncellenmesi (örneğin, sipariş eklendiğinde stok miktarını azaltmak).
    • İş Kurallarını Uygulama: Belirli koşullar altında işlemin engellenmesi veya veri formatının düzeltilmesi.
  • Oluşturma (CREATE TRIGGER):
    -- Sipariş eklendikten (AFTER INSERT) sonra ürünün stoğunu azaltan tetikleyici CREATE TRIGGER stok_azaltma AFTER INSERT ON SiparisDetay FOR EACH ROW BEGIN UPDATE Urunler SET Stok = Stok - NEW.Miktar -- NEW anahtar kelimesi yeni eklenen kaydı temsil eder WHERE UrunID = NEW.UrunID; END;

8.3 Fonksiyonlar (FUNCTION) ve Sekanslar (SEQUENCE)

Bu nesneler genellikle hesaplama ve otomatik sayı üretme işlevlerini üstlenir.

🔢 Fonksiyonlar (FUNCTION)

  • Tanım: Veritabanında depolanan ve her zaman tek bir değer döndüren bir programlama birimidir.
  • Saklı Yordamlardan Temel Farkı:
    • Fonksiyonlar, SELECT sorguları içinde, WHERE veya ORDER BY yan tümcelerinde kullanılabilir. Yordamlar sadece CALL ile çağrılır.
    • Fonksiyonlar zorunlu olarak bir değer döndürür.
    • Fonksiyonlar, veritabanının durumunu değiştiren (DML - INSERT, UPDATE, DELETE) komutları doğrudan çalıştıramazlar (salt okunur olmaları beklenir).
  • Kullanım: Karmaşık hesaplamaları veya formatlama işlemlerini SQL sorgusuna entegre etmek.
  • Oluşturma ve Kullanma:
    -- Fonksiyon Oluşturma (KDV dahil fiyatı hesaplar) DELIMITER // CREATE FUNCTION KDV_Ekle (fiyat DECIMAL(10,2)) RETURNS DECIMAL(10,2) DETERMINISTIC BEGIN RETURN fiyat * 1.20; END // DELIMITER ;
    
    -- Sorguda Kullanım SELECT UrunAdi, KDV_Ekle(Fiyat) AS KDVliFiyat FROM Urunler;

⛓️ Sekanslar (SEQUENCE)

  • Tanım: Sekanslar, veritabanı genelinde art arda (sıralı) benzersiz sayısal değerler (ID'ler) üretmek için kullanılan nesnelerdir.
  • MySQL'deki Durum: MySQL, PostgreSQL veya Oracle gibi veritabanlarının aksine, standart bir SEQUENCE nesnesini doğrudan desteklemez.
  • MySQL'de Karşılığı: Bu işlevsellik, birincil anahtar (Primary Key) olarak belirlenen bir sütuna AUTO_INCREMENT özelliği verilerek sağlanır. MySQL sunucusu, her yeni kayıt eklendiğinde bu sütuna otomatik olarak benzersiz bir artan sayı atar.
  • Kullanım Örneği (AUTO_INCREMENT):
    CREATE TABLE Kullanicilar ( KullaniciID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, -- Sekans işlevi görür Ad VARCHAR(100) );
    
    -- Yeni kayıtta ID otomatik atanır INSERT INTO Kullanicilar (Ad) VALUES ('Ayşe');

9.1 Kullanıcı Oluşturma (CREATE USER)

Veritabanı güvenliğinin temel adımı, her erişim ihtiyacı için ayrı bir kullanıcı oluşturmak ve bu kullanıcılara sadece ihtiyaç duydukları yetkileri vermektir.

👤 Kullanıcı ve Host (Ana Bilgisayar) Tanımı

  • Bir MySQL kullanıcısı, yalnızca bir kullanıcı adından ibaret değildir; aynı zamanda o kullanıcının veritabanına nereden (hangi host/ana bilgisayar) bağlanabileceği bilgisiyle tanımlanır.
  • Kullanıcı formatı: 'kullanici_adi'@'host_adi' şeklindedir.
    • '%' (Wildcard): Kullanıcının herhangi bir ana bilgisayardan (uzaktan) bağlanabileceği anlamına gelir.
    • 'localhost': Kullanıcının sadece veritabanı sunucusunun kendisinden bağlanabileceği anlamına gelir (en güvenli seçenek).
    • Belirli bir IP: Örneğin, '192.168.1.10' sadece o IP adresinden bağlantıya izin verir.

Oluşturma (CREATE USER) Sözdizimi

CREATE USER komutu, yeni bir veritabanı kullanıcı hesabı oluşturur ve ona bir parola atar.

-- Sadece sunucunun kendisinden (localhost) bağlanabilen bir kullanıcı CREATE USER 'yazilimci'@'localhost' IDENTIFIED BY 'GucluSifre123';

-- Her yerden (uzaktan) bağlanabilen bir raporlama kullanıcısı CREATE USER 'raporlama'@'%' IDENTIFIED BY 'Sifre456' DEFAULT ROLE NONE; -- MySQL 8.0 ve üzeri için parola ve rol atama 

Önemli Not: Kullanıcı oluşturulduktan hemen sonra, hiçbir yetkiye sahip değildir. Erişim için GRANT komutu kullanılmalıdır.

9.2 Yetki Verme ve Geri Alma (GRANT, REVOKE)

Veri güvenliğini sağlamanın en kritik adımı, kullanıcıların veritabanındaki hangi nesneler üzerinde hangi işlemleri yapabileceğini kesin olarak tanımlamaktır.

🔑 Yetki Verme (GRANT)

GRANT komutu, belirli bir kullanıcıya belirli bir veritabanı, tablo veya nesne üzerinde yetki tanımlamak için kullanılır.

  • Yetki Kapsamı: Yetkiler veritabanı (db_adi.*) veya tek bir tablo (db_adi.tablo_adi) düzeyinde verilebilir.
  • Temel Yetkiler:
    • SELECT: Veri okuma (sorgulama)
    • INSERT: Yeni veri ekleme
    • UPDATE: Mevcut veriyi değiştirme
    • DELETE: Veri silme
    • ALL PRIVILEGES: Tanımlı kapsamdakı tüm yetkiler
  • Sözdizimi:
    -- 'raporlama' kullanıcısına sadece 'muhasebe' veritabanındaki tüm tablolarda okuma yetkisi verme GRANT SELECT ON muhasebe.* TO 'raporlama'@'%';
    
    -- 'yazilimci' kullanıcısına 'proje_db' veritabanındaki 'urunler' tablosunda ekleme ve güncelleme yetkisi verme GRANT INSERT, UPDATE ON proje_db.urunler TO 'yazilimci'@'localhost';
    
    -- Yetkileri başka kullanıcılara aktarma izni verme (Çok nadir ve dikkatli kullanılır) GRANT SELECT ON urunler TO 'yazilimci'@'localhost' WITH GRANT OPTION;

⛔ Yetkiyi Geri Alma (REVOKE)

REVOKE komutu, daha önce GRANT ile verilmiş olan yetkileri geri almak için kullanılır.

-- 'raporlama' kullanıcısından güncelleme yetkisini geri alma REVOKE UPDATE ON muhasebe.* FROM 'raporlama'@'%';

-- 'yazilimci' kullanıcısından tüm DML yetkilerini geri alma REVOKE INSERT, UPDATE, DELETE ON proje_db.urunler FROM 'yazilimci'@'localhost';

9.3 Veri Bütünlüğü (Constraints)

Veri Bütünlüğü (Data Integrity), bir veritabanındaki verilerin doğruluğunu, tutarlılığını ve güvenilirliğini korumak için uygulanan kural ve mekanizmalardır. Bu mekanizmalar SQL'de kısıtlamalar (Constraints) olarak adlandırılır.

🛡️ Temel Kısıtlamalar (Constraints)

  • NOT NULL: Bir sütunun boş (NULL) değer içeremeyeceğini garanti eder. Bu kısıtlama, ilgili verinin her zaman mevcut olmasını sağlar.
    Ad VARCHAR(50) NOT NULL
  • UNIQUE: Bir sütundaki tüm değerlerin benzersiz olmasını garanti eder. İki farklı satır aynı değeri alamaz. Bir tabloda birden fazla UNIQUE kısıtlaması olabilir.
    Eposta VARCHAR(100) UNIQUE
  • PRIMARY KEY (Birincil Anahtar): Tablodaki her satırı benzersiz olarak tanımlayan bir sütun veya sütun kümesidir. NOT NULL ve UNIQUE kısıtlamalarının zorunlu birleşimidir. Her tabloda sadece bir tane olabilir.
    OgrenciID INT PRIMARY KEY
  • FOREIGN KEY (Yabancı Anahtar): İki tablo arasındaki ilişkisel bütünlüğü sağlar. Bir tablodaki sütunun (yabancı anahtar), başka bir tablonun PRIMARY KEY'indeki mevcut bir değere karşılık gelmesini zorunlu kılar.
    FOREIGN KEY (BolumID) REFERENCES Bolumler(BolumID)

    Referans Aksiyonları (Cascading Actions): Yabancı anahtarlar, ana tablodaki veriler silindiğinde veya güncellendiğinde ne olacağını kontrol eder:

    • ON DELETE CASCADE: Ana kaydın silinmesi durumunda, ilişkili tüm kayıtları da siler (Örn: Müşteri silinirse, siparişleri de silinir).
    • ON UPDATE CASCADE: Ana kaydın güncellenmesi durumunda, ilişkili tüm kayıtları da günceller.
    • ON DELETE SET NULL: Ana kaydın silinmesi durumunda, ilişkili tablodaki yabancı anahtar değerini NULL olarak ayarlar.

  • CHECK: Bir sütundaki tüm değerlerin belirli bir koşulu (mantıksal ifade) karşılamasını garanti eder.
    Maas DECIMAL(10, 2) CHECK (Maas > 0)

Oluşturma (CREATE TABLE Örneği)

CREATE TABLE Calisanlar ( CalisanID INT PRIMARY KEY, Ad VARCHAR(50) NOT NULL, Eposta VARCHAR(100) UNIQUE, DepartmanID INT, Maas DECIMAL(10, 2) CHECK (Maas > 0), FOREIGN KEY (DepartmanID) REFERENCES Departmanlar(ID) ON DELETE RESTRICT -- Ana kaydın silinmesine, ilişkili kayıtlar varsa izin vermez );

10.1 Normalizasyon ve Veri Yönetimi

Normalizasyon, ilişkisel veritabanı tasarımında veri fazlalığını (redundancy) en aza indirmek ve veri bütünlüğünü maksimize etmek amacıyla tabloları ve sütunları organize etme sürecidir. Amaç, her veriyi yalnızca tek bir yerde saklamaktır.

⚖️ Normal Formlar (NF)

Normalizasyon, belirlenen kurallara göre artan seviyelerde (Normal Formlar) uygulanır:

  • 1NF (Birinci Normal Form):
    • Her sütun atomik (bölünemez) olmalıdır. (Örn: Adres sütunu, Sokak, Şehir, Posta Kodu olarak ayrılmalıdır).
    • Tekrarlayan gruplar (bir hücrede birden fazla değer) olmamalıdır.
  • 2NF (İkinci Normal Form):
    • 1NF koşulunu sağlamalıdır.
    • Tablodaki tüm anahtar dışı sütunlar, birincil anahtarın tamamına bağımlı olmalıdır (Kısmi bağımlılık olmamalıdır).
  • 3NF (Üçüncü Normal Form):
    • 2NF koşulunu sağlamalıdır.
    • Anahtar dışı sütunlar arasında geçişli bağımlılık (transitive dependency) olmamalıdır (yani, bir anahtar dışı sütun başka bir anahtar dışı sütuna bağımlı olmamalıdır).

↔️ Denormalizasyon

Normalleştirilmiş bir veritabanında, okuma (SELECT) performansını artırmak amacıyla kasıtlı olarak veri fazlalığı ekleme işlemidir. Özellikle raporlama (OLAP) sistemlerinde, çok fazla JOIN işleminden kaçınmak için kullanılır. Denormalizasyon, performansı artırırken, veri tutarlılığını sağlamanın maliyetini artırır.

10.2 Performans Optimizasyonu ve İndeksleme Stratejileri

Veritabanı optimizasyonu, özellikle büyük ve yoğun sistemlerde sorguların hızını artırmak ve sistem kaynaklarını (CPU, RAM, Disk I/O) verimli kullanmak için hayati öneme sahiptir.

🚀 Performans Optimizasyon Yöntemleri

  • İndeksleme Stratejileri:
    • WHERE koşullarında sık kullanılan sütunları indeksleyin.
    • JOIN işlemlerinde kullanılan FOREIGN KEY sütunlarını mutlaka indeksleyin.
    • ORDER BY ve GROUP BY yan tümcelerinde kullanılan sütunları dikkate alın.
    • Birden fazla sütun içeren sorgular için Bileşik İndeksler oluşturmayı düşünün. (Örn: WHERE Soyad = 'X' AND Ad = 'Y' için (Soyad, Ad) bileşik indeksi).
    • İndeks sayısını gereksiz yere artırmaktan kaçının; çok fazla indeks, INSERT/UPDATE/DELETE işlemlerini yavaşlatır.
  • Sorgu Optimizasyonu:
    • SELECT * yerine sadece gerekli sütunları seçin.
    • LIKE '%deger' (önce yüzde işareti) kullanımından kaçının; bu, indeks kullanımını engeller ve tam tablo taramasına neden olur.
    • Gereksiz Alt Sorgular yerine mümkünse JOIN kullanın.
  • Veritabanı Yapılandırması: InnoDB motoru için innodb_buffer_pool_size ayarının optimize edilmesi (genellikle sunucu RAM'inin %50-70'i) en kritik faktördür.

10.3 Sorgu Planı ve SQL Injection Güvenlik Önlemleri

Performansın analizi ve güvenliğin sağlanması, ileri düzey veritabanı yönetiminin ayrılmaz parçalarıdır.

🔬 Sorgu Planı (Execution Plan)

  • Tanım: Bir SQL sorgusu çalıştırılmadan önce, veritabanı motoru tarafından oluşturulan ve sorgunun çalıştırılacağı adım adım yol haritasını gösteren plandır.
  • Kullanım: Performans sorunlarının kaynağını tespit etmek için kullanılır. Plan incelenerek tam tablo taramaları (Full Table Scan) veya yanlış indeks kullanımları belirlenir.
  • MySQL Komutu:
    EXPLAIN SELECT Ad, Soyad FROM Calisanlar WHERE Maas > 50000;
  • Çıktı Analizi: type sütunu (ALL tam taramadır, ref veya const hızlı indeksten erişimdir) ve rows sütunu (taranan tahmini satır sayısı) gibi değerler incelenir.

🔒 SQL Injection Güvenlik Önlemleri

  • SQL Injection (SQL Enjeksiyonu), kullanıcı giriş alanlarına kötü amaçlı SQL kodları enjekte edilerek veritabanını ele geçirme veya manipüle etme girişimidir.
  • En Etkili Önlem: Hazırlanmış İfadeler (Prepared Statements):

    Kullanıcıdan gelen veri ile SQL sorgusunun yapısı birbirinden ayrılır. Kullanıcı girdisi, sorgu tarafından sadece bir veri değeri olarak işlenir, SQL kodu olarak değil. Bu, tüm modern programlama dillerinde (PHP, Python, Java vb.) kullanılmalıdır.

    -- Güvensiz Yöntem (Kullanıcı girdisi doğrudan sorguya ekleniyor) sorgu = "SELECT * FROM Kullanicilar WHERE Ad = '" + kullanici_girisi + "'"
    
    -- Güvenli Yöntem (Prepared Statement / Parametreli Sorgu) sorgu = "SELECT * FROM Kullanicilar WHERE Ad = ?" calistir(sorgu, [kullanici_girisi])
  • Diğer Önlemler: En az yetki ilkesini uygulama (uygulama kullanıcısının DROP TABLE yetkisi olmamalıdır) ve sıkı girdi doğrulaması yapmaktır.

11.1 Gerçek Veritabanı Oluşturma Örneği (Öğrenci Otomasyonu)

Pratik uygulamada veritabanı tasarımı, teorik bilgilerin gerçek bir senaryoya dönüştürülmesini sağlar. Öğrenci Otomasyonu, temel ilişkisel veritabanı kavramlarını uygulamak için iyi bir örnektir.

📐 Temel Tablo Yapıları ve İlişkiler

  • Bolumler: (BolumID PRIMARY KEY)
  • Ogrenciler: (OgrenciID PRIMARY KEY, BolumID FOREIGN KEY)
  • Dersler: (DersID PRIMARY KEY, OgretmenID FOREIGN KEY)
  • Ogretmenler: (OgretmenID PRIMARY KEY)
  • Ders_Kayit: (OgrenciID, DersID) -> Çoka-çok ilişkiyi çözen bir ara tablo. (Composite PRIMARY KEY: OgrenciID, DersID)

Oluşturma (CREATE TABLE Örnekleri)

-- 1. Bolumler Tablosu (Ana Tablo) CREATE TABLE Bolumler ( BolumID INT PRIMARY KEY, BolumAdi VARCHAR(100) NOT NULL UNIQUE );

-- 2. Ogrenciler Tablosu (Yabancı Anahtar İlişkisi) CREATE TABLE Ogrenciler ( OgrenciID INT AUTO_INCREMENT PRIMARY KEY, Ad VARCHAR(50) NOT NULL, Soyad VARCHAR(50) NOT NULL, KayitTarihi DATE, BolumID INT, FOREIGN KEY (BolumID) REFERENCES Bolumler(BolumID) );

-- 3. Ders_Kayit Tablosu (Çoka-Çok İlişki) CREATE TABLE Ders_Kayit ( OgrenciID INT, DersID INT, VizeNotu INT, FinalNotu INT, PRIMARY KEY (OgrenciID, DersID), -- Bileşik Anahtar FOREIGN KEY (OgrenciID) REFERENCES Ogrenciler(OgrenciID) ON DELETE CASCADE -- FOREIGN KEY (DersID) REFERENCES Dersler(DersID) );

11.2 Veri Analizi, Raporlama ve Dashboard İçin SQL Sorguları

Veri Analizi ve Raporlama, toplanan ham verilerden iş kararlarını destekleyecek anlamlı bilgiler çıkarmayı amaçlar.

📊 Temel Analitik Sorgular

  • Agregasyon ve Gruplama (GROUP BY / HAVING): Belirli gruplara ait özet bilgileri (toplam, ortalama, sayım) elde etmek.
    -- Her bölümdeki öğrenci sayısını bulma SELECT B.BolumAdi, COUNT(O.OgrenciID) AS ToplamOgrenci FROM Bolumler B LEFT JOIN Ogrenciler O ON B.BolumID = O.BolumID GROUP BY B.BolumAdi HAVING COUNT(O.OgrenciID) > 50; -- Sadece 50'den fazla öğrencisi olanları göster
  • Tarih Fonksiyonları: Zaman serisi analizleri yapmak (Aylık/Yıllık trendler).
    -- Yıllara göre kayıt olan öğrenci sayısını bulma SELECT YEAR(KayitTarihi) AS KayitYili, COUNT(OgrenciID) FROM Ogrenciler GROUP BY KayitYili ORDER BY KayitYili;
  • Pencere Fonksiyonları (Window Functions - MySQL 8.0+): RANK(), ROW_NUMBER(), AVG() OVER() gibi fonksiyonlarla, veriyi bölümler halinde analiz etmek (Örn: Her bölümde en yüksek notu alan öğrenciyi bulmak).
    -- Her bölümdeki not ortalamasını kendi bölümündeki ortalamaya göre sıralama SELECT OgrenciID, FinalNotu, RANK() OVER (PARTITION BY BolumID ORDER BY FinalNotu DESC) AS BolumSirasi FROM Ders_Kayit;

11.3 Programlama Dilleri ile SQL Bağlantısı ve Mini Projeler

SQL ve veritabanları, kullanıcı arayüzleri ve iş mantığı (programlama dilleri) ile entegre olduğunda gerçek bir uygulama haline gelir.

🔗 Programlama Dili Bağlantı Akışı

  1. Bağlayıcı (Driver/Connector) Yükleme: Kullanılan dile özel MySQL sürücüsünü kurmak (Örn: Python için mysql.connector veya psycopg2).
  2. Bağlantı Kurma: Veritabanı sunucusuna bağlantı açmak (host, kullanıcı adı, parola, veritabanı adı).
  3. Sorgu Oluşturma: İhtiyaca uygun SQL sorgusunu hazırlamak (Tercihen Prepared Statements kullanarak).
  4. Sorguyu Çalıştırma (Execute): Sorguyu veritabanına göndermek.
  5. Sonuçları İşleme (Fetch): SELECT sorgularından dönen veri kümesini program içinde kullanmak (döngü, listeler, nesneler).
  6. Bağlantıyı Kapatma: Kaynakların serbest bırakılması için bağlantıyı kapatmak.

🛠️ Mini Proje Örnekleri

  • CRUD (Create, Read, Update, Delete) Envanter Uygulaması: Ürünlerin eklenebildiği, listelenebildiği, düzenlenebildiği ve silinebildiği basit bir masaüstü veya web uygulaması.
  • Kullanıcı Kayıt ve Giriş Sistemi: Kullanıcı kimlik doğrulama ve yetkilendirme işlemlerini SQL ile yöneten güvenli bir sistem.
  • Veri Analiz Dashboard'u: Veritabanındaki verileri çekip (11.2'deki sorguları kullanarak) grafiğe döken basit bir raporlama aracı.