Ana içeriğe geç
Kesit SQL
İleri · SQL Türlerine Özgü

MySQL'e özgü yazımlar ve tuzaklar

LIMIT a,b, IFNULL, IF, DATE_FORMAT, GROUP_CONCAT, ON DUPLICATE KEY, WITH ROLLUP.

Uygulamada aç, 5 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

MySQL'in kendine has yazımları

SELECT `name`, IFNULL(stock, 0) AS stok,
       IF(price > 1000, 'Pahalı', 'Normal') AS sinif
FROM products
ORDER BY price DESC
LIMIT 5, 5;   -- 5 satır atla, 5 satır getir

Tarih ve metin

SELECT DATE_FORMAT(order_date, '%Y-%m') AS ay,
       COUNT(*) AS siparis,
       GROUP_CONCAT(DISTINCT channel ORDER BY channel SEPARATOR ' / ') AS kanallar
FROM orders
WHERE YEAR(order_date) = 2024
GROUP BY DATE_FORMAT(order_date, '%Y-%m')
ORDER BY ay;

Tuzaklar

Derinleş: MySQL'de veri temizliği ve upsert

MySQL'in kendine özgü fonksiyonları, özellikle ham veriyi temizlerken ve yükleme yaparken işe yarar. Üç tanesi çok sık kullanılır: STR_TO_DATE, TIMESTAMPDIFF ve INSERT ... ON DUPLICATE KEY UPDATE.

STR_TO_DATE: metinden tarihe

raw_signups tablosunda tarihler iki biçimde geliyor. STR_TO_DATE(metin, biçim) metni gerçek DATE tipine çevirir; biçim uymazsa NULL döndürür (katı SQL modunda uyarı/hata). DATE_FORMAT ise tersini yapar.

SELECT id, signup_date,
       CASE WHEN signup_date LIKE '__.__.____'
            THEN STR_TO_DATE(signup_date, '%d.%m.%Y')
            ELSE STR_TO_DATE(signup_date, '%Y-%m-%d') END AS kayit_tarihi
FROM raw_signups
ORDER BY id
LIMIT 6;

TIMESTAMPDIFF: süre hesabı

TIMESTAMPDIFF(birim, başlangıç, bitiş) iki zaman arasındaki farkı istenen birimde tam sayı (aşağı yuvarlanmış) olarak verir. DATEDIFF(a, b) ise yalnızca gün farkıdır ve argüman sırası terstir (bitiş önce).

SELECT r.city,
       COUNT(*) AS teslim,
       ROUND(AVG(TIMESTAMPDIFF(MINUTE, o.placed_at, o.delivered_at)), 1) AS ort_dk
FROM lk_orders o
JOIN lk_restaurants r ON r.restaurant_id = o.restaurant_id
WHERE o.status = 'teslim'
GROUP BY r.city
ORDER BY ort_dk DESC;

Upsert: ON DUPLICATE KEY UPDATE

Birincil veya benzersiz anahtar çakışırsa satırı güncelleyen bu yazım, MySQL'de idempotent yüklemenin en kısa yoludur:

CREATE TABLE gunluk_sayac (gun DATE PRIMARY KEY, siparis INT NOT NULL);

INSERT INTO gunluk_sayac (gun, siparis)
SELECT DATE(placed_at), COUNT(*) FROM lk_orders
WHERE placed_at >= '2024-12-30' AND placed_at < '2024-12-31'
GROUP BY DATE(placed_at)
ON DUPLICATE KEY UPDATE siparis = VALUES(siparis);

SELECT * FROM gunluk_sayac;

Aynı ifadeyi ikinci kez çalıştırmak satır eklemez, değeri günceller. MySQL 8.0.20+ VALUES() yerine takma adlı yazımı önerir: INSERT ... AS yeni ON DUPLICATE KEY UPDATE siparis = yeni.siparis.

Sık hata: Dönüşümden sonra NULL sayısını kontrol etmemek. Biçime uymayan bir metin (ör. 31/12/2024) STR_TO_DATE ile NULL'a döner ve kayıt sessizce “tarihsiz” kalır. Temizlik sorgusunun hemen ardından SUM(CASE WHEN yeni_tarih IS NULL THEN 1 ELSE 0 END) ile kaç kaydın dönüşemediğini say. Benzer şekilde TIMESTAMPDIFF aşağı yuvarladığı için 59 saniyelik bir fark 0 dakika görünür; hassas ortalamalarda SECOND biriminde hesaplayıp 60'a böl.

YazımDavranışDikkat
ON DUPLICATE KEY UPDATEÇakışmada güncellerBirden çok benzersiz anahtar varsa hangisinin çakıştığı belirsizleşir
REPLACE INTOÇakışan satırı siler, yenisini eklerSilme, yabancı anahtar CASCADE'lerini ve trigger'ları tetikler
INSERT IGNOREÇakışan satırı atlarBaşka hataları da sessizce yutar
Alıştırmalara geç (5)