Menu
Playground'da Dene

SQLite RETURNING: INSERT, UPDATE, DELETE Sonuçlarını Alın

SQLite'ta RETURNING cümlesinin nasıl çalıştığını öğrenin: INSERT, UPDATE veya DELETE'in etkilediği satırları ikinci bir sorgu çekmeden tek seferde geri alın.

Bu sayfada çalıştırılabilir editörler var — düzenle, çalıştır ve sonucu anında gör.

Az Önce Ne Olduğunu Görmenin Bir Yolu

Bir INSERT, UPDATE ya da DELETE çalıştırdığınızda SQLite size kaç satırın etkilendiğini söyler — ama hangi satırların etkilendiğini ya da satırların son hâlinin nasıl göründüğünü söylemez. Klasik çözüm, hemen ardından bir SELECT çekmek. Bu da iki ayrı sorgu, iki gidiş-dönüş ve arada başka birinin satırı değiştirebileceği küçük bir yarış penceresi anlamına geliyor.

İşte RETURNING tam da bu sorunu çözüyor. Yazma sorgunuzun sonuna ekliyorsunuz, geri istediğiniz sütunları listeliyorsunuz ve SQLite size etkilenen satırları sanki üzerlerinde bir SELECT çalıştırmışsınız gibi geri veriyor:

Tek sorgu, tek gidiş-dönüş ve hem üretilen id'yi hem de veritabanının sizin için doldurduğu varsayılan created_at değerini geri alıyorsunuz.

RETURNING, SQLite 3.35.0 ile (Mart 2021) eklendi. Eğer sorgunuz sözdizimi hatası verip reddediliyorsa, SELECT sqlite_version(); çıktısına bakın — eski sürümler bu anahtar kelimeyi tanımıyor.

Üretilen ID'yi Geri Alma

RETURNING denildiğinde akla gelen ilk kullanım, kayıt eklerken otomatik üretilen birincil anahtarı anında yakalamaktır:

RETURNING ifadesi gelmeden önce, kayıt eklemek için önce INSERT çalıştırıp ardından aynı bağlantı üzerinde last_insert_rowid() (veya kullandığınız sürücünün karşılığını) çağırırdınız. Bu yöntem hâlâ çalışıyor ama bağlantı durumuna bağlı bir tür sihir; bağlantı havuzları ya da thread'ler işin içine girince kolayca yanlış sonuç verebiliyor. RETURNING id ise açık, doğrudan ifadenin kendisine bağlı ve bağlantıyı kim yönetirse yönetsin aynı şekilde çalışıyor.

Tablonuzda açıkça INTEGER PRIMARY KEY tanımlı değilse bile, örtük satır kimliğini şu şekilde alabilirsiniz:

Her standart SQLite tablosunun bir rowid değeri vardır ve RETURNING bu değeri sana geri verir.

Birden Fazla Sütun ve İfade

RETURNING ifadesi, bir SELECT sorgusundaki sütun listesiyle aynı yapıyı kabul eder. İsterseniz sütunları tek tek yazarsınız, isterseniz * kullanırsınız; ifade oluşturup bunlara takma ad da verebilirsiniz:

RETURNING *, veritabanının kendi doldurduğu varsayılanlar dahil her şeyi geri almak istediğinde işine yarar; üstelik kolonları tek tek yazmana da gerek kalmaz:

Yeni id'yi, ilettiğiniz name'i ve SQLite'ın hesapladığı timestamp değerini bir arada görürsünüz.

UPDATE ile RETURNING kullanımı

UPDATE ifadesinde RETURNING, satırın güncellenmiş halini döndürür — yani değişiklikler uygulandıktan sonraki değerleri elinize verir:

Aynı sorguda Ada'nın eski bakiyesi olan 100 değil, yeni bakiyesi olan 125 dönüyor. İşte tam da bu yüzden RETURNING, atomik sayaçlar ve borç/alacak işlemleri için biçilmiş kaftan — önce oku, hesapla, yaz, sonra tekrar oku gibi bir döngüye girmene gerek kalmıyor.

WHERE koşulu birden fazla satıra uyuyorsa, etkilenen her satır için bir satır geri dönüyor:

Üç satır girdi, üç satır çıktı. Ama sıraya güvenme — belirli bir sıralama lazımsa, sonucu istemci tarafında sırala.

DELETE ile RETURNING kullanımı

DELETE işleminde RETURNING, sana satırları silinmeden hemen önceki hâliyle verir. Arşivleme, denetim kaydı tutma ya da neyin silindiğini teyit etmek için epey işe yarar:

Süresi dolmuş iki oturumu, tablodan silinmiş olmalarına rağmen tüm alanlarıyla birlikte geri alırsınız. Bunları başka bir yere taşımak istiyorsanız, bu bir arşiv tablosu için biçilmiş kaftandır — sonucu okuyup aynı işlem (transaction) içinde başka bir tabloya ekleyebilirsiniz.

UPSERT ile RETURNING kullanımı

RETURNING, INSERT ... ON CONFLICT ... DO UPDATE ile de sorunsuz çalışır. Dönen satır, hangi dal çalıştıysa onu yansıtır — yeni eklenen kayıt mı yoksa çakışma sonucu güncellenen kayıt mı:

Bu ifadeyi iki kez çalıştırın. İlkinde satır eklenir ve ('visits', 1) döner. İkincisinde çakışma tetiklenir, değer bir artırılır ve geriye ('visits', 2) gelir. Her iki durumda da tek bir ifade çalıştırırsınız ve tek bir satır geri alırsınız — devam etmeden önce "ekleme mi yapıldı yoksa güncelleme mi?" diye sormaya gerek kalmaz.

Bu, SQLite'ta "değer yoksa oluştur, varsa mevcut değeri ver" işlemini ekstra sorgu atmadan yapmanın en temiz yoludur.

Bilmeniz Gereken Birkaç Detay

İnsanları sıklıkla şaşırtan birkaç ince nokta var:

  • RETURNING, INSERT ve UPDATE için satırı her zaman değişiklik sonrası, DELETE için ise değişiklik öncesi haliyle gösterir. Tersini istemenin bir söz dizimi yok.
  • Dönen satırların sırası garanti değildir. Sıra önemliyse istemci tarafında ORDER BY ekleyin.
  • RETURNING'i bir alt sorgunun içine koyamazsınız. Bir ifade değil, yazma ifadesinin en üst düzey bir parçasıdır.
  • RETURNING, BEFORE tetikleyicilerinin değiştirdiği veriyi yansıtmaz — gerçekte yazılan değerleri döndürür. AFTER tetikleyicileri ise yazma ile satırın dönüşü arasında çalışır.
  • Generated (üretilmiş) sütunlar ve DEFAULT değerleri sonuçta görünür. Veritabanının sizin yerinize ne doldurduğunu anlamak için RETURNING * kullanmak tam da bu yüzden pratiktir.

Sırada: CSV Verisini İçe Aktarma

RETURNING, tek satır veya birkaç satır yazıp sonucu hemen görmek istediğinizde harikadır. Ama bir dosyadan binlerce satır yüklüyorsanız iş SQLite'ın CSV içe aktarma araçlarına düşer — bir sonraki sayfanın konusu da bu.

Sıkça Sorulan Sorular

SQLite RETURNING cümlesini destekliyor mu?

Evet, 3.35.0 sürümünden itibaren (Mart 2021) destekleniyor. INSERT, UPDATE ve DELETE ifadelerinin sonuna RETURNING ekleyerek etkilenen satırları geri alabilirsiniz. Daha eski bir SQLite sürümündeyseniz parser bunu reddeder; sürümünüzü SELECT sqlite_version(); ile kontrol edin.

SQLite'ta yeni eklediğim satırın ID'sini nasıl alırım?

INSERT ... RETURNING id kullanın (tabloda açık bir primary key yoksa RETURNING rowid da işe yarar). Üretilen değer, aynı ifadenin parçası olarak elinize geçer; yani last_insert_rowid() gibi ikinci bir sorguya gerek kalmaz.

RETURNING birden fazla kolon döndürebilir mi?

Döndürebilir. Tıpkı bir SELECT'te olduğu gibi istediğiniz kolonları virgülle ayırarak yazın: RETURNING id, name, created_at. Tüm kolonları almak için RETURNING * kullanabilir, hatta RETURNING id, price * quantity AS total gibi ifadeler de yazabilirsiniz.

RETURNING, UPSERT ve ON CONFLICT ile birlikte çalışır mı?

Evet. INSERT ... ON CONFLICT ... DO UPDATE ... RETURNING ... yapısı, satır ister yeni eklensin ister çakışma çözümüyle güncellensin sonucu döndürür. Bu yüzden tek seferde upsert yapıp ortaya çıkan satırı okumanın en temiz yolu budur.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA