UPDATE — WHERE, Birden Fazla Sütun, Subquery
Giriş — Veri Değişir, Güncelleme Kaçınılmaz
Müşteri adresini değiştirdi, ürün fiyatı güncellendi, sipariş durumu "kargoya verildi" oldu, kullanıcı şifresini sıfırladı... Gerçek dünyada veri sürekli değişir. UPDATE komutu, tablolardaki mevcut verileri güncellemenin yoludur.
Bu komutu öğrenirken bir kuralı asla unutma: WHERE olmadan UPDATE yapmak, tüm satırları günceller. Bu, SQL dünyasının en tehlikeli hatalarından biridir ve production'da büyük felaketlere yol açabilir.
🎯 Analoji: Bir sınıfta öğretmensin ve yoklama kâğıdında bir öğrencinin ismini düzeltmen gerekiyor. "Ahmet Yılmaz" yerine "Ahmet Kaya" yazacaksın. Ama dikkatli olmazsan, tüm öğrencilerin soyadını "Kaya" yaparsın. İşte
WHEREkoşulu, "sadece bu öğrenciyi değiştir" demenin yolu.
Temel Sözdizimi
UPDATE tablo_adi
SET sutun1 = yeni_deger1,
sutun2 = yeni_deger2,
...
WHERE kosul;Üç ana bileşen:
Tablo adı — Hangi tablodaki veriler güncellenecek?
SET — Hangi sütunlar, hangi değerlerle güncellenecek?
WHERE — Hangi satırlar güncellenecek? (Bu olmadan TÜM satırlar güncellenir!)
Tek Sütun Güncelleme
Basit Güncelleme
-- Ahmet'in şehrini güncelle (customer_id = 1)
UPDATE customers
SET city = 'Bursa'
WHERE customer_id = 1;
-- Query OK, 1 row affected
-- Rows matched: 1 Changed: 1 Warnings: 0Çıktıdaki bilgiler:
Rows matched: 1 — WHERE koşuluna 1 satır uydu
Changed: 1 — 1 satır gerçekten değişti
Eğer zaten 'Bursa' olsaydı: Changed: 0 (değişiklik yok, hata da yok)
Koşullu Güncelleme
-- 1000 TL üstündeki ürünlere %10 zam yap
UPDATE products
SET price = price * 1.10
WHERE price > 1000;
-- Fiyatı 1000'den büyük olan tüm ürünlerin fiyatı %10 artar
-- Belirli bir kategorideki ürünlerin stokunu sıfırla
UPDATE products
SET stock_quantity = 0
WHERE category_id = 3;Birden Fazla Sütun Güncelleme
Tek bir UPDATE komutuyla birden fazla sütunu güncelleyebilirsin:
-- Müşterinin hem şehrini hem telefonunu güncelle
UPDATE customers
SET city = 'İzmir',
phone = '05559999999'
WHERE customer_id = 2;
-- Siparişin durumunu ve toplam tutarını güncelle
UPDATE orders
SET status = 'shipped',
shipping_address = 'İzmir, Karşıyaka, 35000',
updated_at = NOW()
WHERE order_id = 4;
-- Ürün bilgilerini toplu güncelle
UPDATE products
SET price = 52999.99,
stock_quantity = 20,
is_active = TRUE
WHERE product_id = 1;💡 İpucu: Birden fazla sütunu ayrı ayrı güncellemek yerine tek bir
UPDATE'te toplamak hem daha okunabilir hem daha performanslıdır. Veritabanı tek seferde tek bir yazma operasyonu yapar.
WHERE Koşulları ile Güncelleme
WHERE'da kullanabileceğin tüm operatörler UPDATE'te de geçerlidir:
-- Belirli şehirlerdeki müşterileri güncelle
UPDATE customers
SET is_active = FALSE
WHERE city IN ('Bursa', 'Antalya');
-- Tarih aralığındaki siparişleri güncelle
UPDATE orders
SET status = 'delivered'
WHERE order_date < '2024-02-01' AND status = 'shipped';
-- LIKE ile güncelleme
UPDATE customers
SET city = 'İstanbul'
WHERE email LIKE '%@gmail.com';
-- NULL olanları güncelle
UPDATE customers
SET phone = 'Belirtilmedi'
WHERE phone IS NULL;
-- BETWEEN ile güncelleme
UPDATE products
SET is_active = FALSE
WHERE stock_quantity BETWEEN 0 AND 5;Hesaplamalı Güncelleme (Mevcut Değere Göre)
-- Tüm ürünlere %5 zam yap (mevcut fiyata göre)
UPDATE products
SET price = price * 1.05
WHERE is_active = TRUE;
-- Stoktan düş
UPDATE products
SET stock_quantity = stock_quantity - 3
WHERE product_id = 5;
-- Stokta olanların stokunu artır
UPDATE products
SET stock_quantity = stock_quantity + 100
WHERE stock_quantity > 0 AND category_id = 1;⚠️ Dikkat:
stock_quantity = stock_quantity - 3negatife düşebilir! Eğer stoğu 2 olan ürünü 3 düşürürsen -1 olur. Bunu önlemek için:
-- Güvenli stok düşürme
UPDATE products
SET stock_quantity = stock_quantity - 3
WHERE product_id = 5 AND stock_quantity >= 3;
-- Eğer satır güncellenmezse (stock < 3), 0 rows affected döner
-- Uygulama katmanında bu durumu kontrol edebilirsinVeya GREATEST fonksiyonuyla:
UPDATE products
SET stock_quantity = GREATEST(stock_quantity - 3, 0)
WHERE product_id = 5;
-- Stok asla 0'ın altına düşmezSubquery ile UPDATE
Bir tablodaki veriyi, başka bir tablo veya sorgudan gelen değerle güncelleyebilirsin:
Tek Değer Döndüren Subquery (Scalar Subquery)
-- En pahalı ürünün fiyatını al ve başka bir ürünün fiyatını ona eşitle
UPDATE products
SET price = (SELECT MAX(price) FROM products WHERE category_id = 2)
WHERE product_id = 4;
-- Bir müşterinin sipariş sayısını güncelle
-- (Normalde böyle bir sütun tutulmaz ama örnek olarak)
ALTER TABLE customers ADD COLUMN order_count INT DEFAULT 0;
UPDATE customers
SET order_count = (
SELECT COUNT(*)
FROM orders
WHERE orders.customer_id = customers.customer_id
)
WHERE customer_id = 1;
-- Siparişin toplam tutarını order_items'tan hesaplayarak güncelle
UPDATE orders
SET total_amount = (
SELECT SUM(quantity * unit_price * (1 - discount_percent / 100))
FROM order_items
WHERE order_items.order_id = orders.order_id
)
WHERE order_id = 1;JOIN ile UPDATE (MySQL'e Özel)
MySQL'de UPDATE komutuyla doğrudan JOIN kullanabilirsin:
-- Stoku 0 olan ürünlerin siparişlerini iptal et
UPDATE orders o
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
SET o.status = 'cancelled'
WHERE p.stock_quantity = 0 AND o.status = 'pending';
-- Kategori adına göre ürün fiyatlarını güncelle
UPDATE products p
JOIN categories c ON p.category_id = c.category_id
SET p.price = p.price * 0.90 -- %10 indirim
WHERE c.category_name = 'Kitap';📝 PostgreSQL Notu: PostgreSQL'de JOIN ile UPDATE syntax'ı farklıdır: ``
sql -- PostgreSQL syntax UPDATE products SET price = price * 0.90 FROM categories WHERE products.category_id = categories.category_id AND categories.category_name = 'Kitap';``
WHERE Olmadan UPDATE — Tehlike!
-- ⚠️ TEHLİKE! WHERE yok — TÜM müşterilerin şehri değişir!
UPDATE customers SET city = 'Ankara';
-- Query OK, 10 rows affected — 10 müşterinin HEPSİ artık Ankara'da!
-- ⚠️ TEHLİKE! Tüm ürünlerin fiyatı 0 olur!
UPDATE products SET price = 0;
-- Tüm ürünler bedava oldu... 💀Bunları önlemenin yolları:
1. Safe Updates Mode
-- Safe mode'u aç
SET SQL_SAFE_UPDATES = 1;
-- Artık WHERE'siz veya WHERE'de index olmayan UPDATE'ler engellenir
UPDATE customers SET city = 'Ankara';
-- ERROR 1175: You are using safe update mode and you tried to update a table
-- without a WHERE that uses a KEY column.2. LIMIT ile Güvenlik
-- En fazla 1 satır güncelle
UPDATE customers
SET city = 'Ankara'
WHERE first_name = 'Ahmet'
LIMIT 1;3. Önce SELECT ile Kontrol
-- Önce hangi satırların etkileneceğini gör
SELECT customer_id, first_name, city
FROM customers
WHERE city = 'İstanbul';
-- 4 satır etkilenecek — tamam mı?
-- Sonra güncelle
UPDATE customers
SET is_active = FALSE
WHERE city = 'İstanbul';💡 İpucu: Production'da UPDATE çalıştırmadan önce her zaman aynı WHERE koşuluyla bir SELECT yap. Kaç satırın etkileneceğini gör, doğru satırlar mı kontrol et, sonra UPDATE'i çalıştır. Bu alışkanlık hayat kurtarır.
CASE WHEN ile Koşullu Güncelleme
Farklı koşullara göre farklı değerler atamak istediğinde:
-- Fiyat aralığına göre indirim uygula
UPDATE products
SET price = CASE
WHEN price > 50000 THEN price * 0.85 -- %15 indirim
WHEN price > 10000 THEN price * 0.90 -- %10 indirim
WHEN price > 1000 THEN price * 0.95 -- %5 indirim
ELSE price -- Değişiklik yok
END
WHERE is_active = TRUE;
-- Sipariş durumunu tarihe göre toplu güncelle
UPDATE orders
SET status = CASE
WHEN order_date < '2024-01-15' AND status = 'shipped' THEN 'delivered'
WHEN order_date < '2024-02-01' AND status = 'processing' THEN 'shipped'
ELSE status
END
WHERE status NOT IN ('delivered', 'cancelled');CASE WHEN ile birden fazla koşullu güncellemeyi tek bir UPDATE'te yapabilirsin — her koşul için ayrı UPDATE yazmana gerek kalmaz.
UPDATE ve Transaction
Kritik güncelleme işlemlerinde transaction kullan:
START TRANSACTION;
-- Fiyat güncelleme
UPDATE products SET price = 49999.99 WHERE product_id = 1;
-- Kontrol et
SELECT product_id, product_name, price FROM products WHERE product_id = 1;
-- 49999.99 — doğru mu?
-- Doğruysa kaydet
COMMIT;
-- Yanlışsa geri al
-- ROLLBACK;Gerçek Dünya Örneği — Sipariş Durumu Yönetimi
-- Senaryo: Kargo şirketi toplu teslimat bildirimi gönderdi
-- 2024-01-20'den önce kargolanan siparişler teslim edildi
START TRANSACTION;
-- Önce kontrol et
SELECT order_id, customer_id, order_date, status
FROM orders
WHERE status = 'shipped' AND order_date < '2024-02-01';
-- 1 satır: order_id = 4
-- Güncelle
UPDATE orders
SET status = 'delivered',
updated_at = NOW()
WHERE status = 'shipped' AND order_date < '2024-02-01';
-- Doğru mu kontrol et
SELECT order_id, status, updated_at FROM orders WHERE order_id = 4;
COMMIT;Performans İpuçları
WHERE'da indexli sütun kullan:
WHERE customer_id = 5hızlıdır çünkücustomer_idprimary key (indexli).WHERE city = 'İstanbul'index yoksa tüm tabloyu tarar.Toplu güncelle: 10.000 satırı tek tek güncellemek yerine tek bir
UPDATEile toplu güncelle.Gereksiz güncelleme yapma: Değer zaten aynıysa
UPDATEçalıştırma gereksizdir. MySQL fiziksel olarak yazmaz ama yine de bazı işlem maliyeti var.
-- Gereksiz güncellemeyi önle
UPDATE customers
SET city = 'Ankara'
WHERE customer_id = 2 AND city != 'Ankara';
-- Zaten Ankara ise hiçbir şey yapmazSıkça Yapılan Hatalar
WHERE unutmak: En büyük hata.
UPDATE products SET price = 0yazdığında tüm ürünlerin fiyatı sıfır olur. Production'da felaket. Safe updates mode'u aç.= yerine == yazmak: Python alışkanlığıyla
WHERE customer_id == 1yazmak MySQL'de hata vermez ama beklenmedik sonuç verebilir. SQL'de karşılaştırma operatörü=(tek eşittir).Subquery'de aynı tabloyu güncellemek: MySQL, güncellenen tabloyu doğrudan subquery'de kullanmana izin vermez:
-- ❌ HATA — aynı tablo hem güncelleniyor hem subquery'de
UPDATE products
SET price = (SELECT AVG(price) FROM products);
-- ERROR: You can't specify target table 'products' for update in FROM clause
-- ✅ Çözüm — iç içe subquery ile
UPDATE products
SET price = (SELECT avg_price FROM (SELECT AVG(price) AS avg_price FROM products) AS tmp)
WHERE product_id = 1;Transaction kullanmamak: Birbirine bağlı güncelleme işlemlerinde transaction kullanmamak veri tutarsızlığına yol açar.
Güncelleme öncesi kontrol yapmamak: UPDATE'ten önce SELECT ile kaç satırın etkileneceğini kontrol etmemek sürprizlere açıktır.
Özet
UPDATE tablo SET sütun = değer WHERE koşulmevcut veriyi güncellerWHERE koşulu olmazsa tüm satırlar güncellenir — en tehlikeli SQL hatası
Birden fazla sütun tek UPDATE'te güncellenebilir:
SET a = 1, b = 2Hesaplamalı güncelleme mümkün:
SET price = price * 1.10Subquery ile başka tablodan değer alarak güncelleme yapılabilir
MySQL'de
UPDATE ... JOINsyntax'ı desteklenirCASE WHENile koşullu güncelleme yapılabilirProduction'da UPDATE öncesi mutlaka SELECT ile kontrol et
SQL_SAFE_UPDATES = 1ile WHERE'siz güncellemeler engellenirKritik güncellemelerde transaction kullan
AI Asistan
Sorularını yanıtlamaya hazır