SQL'de Tablodan Tabloya Veri Kopyalama Yöntemleri
Bir tablodaki veriyi başka bir tabloya taşırken ya var olan tabloya eklersiniz ya da kopyayı yeni tablo olarak oluşturursunuz. Hangisini ne zaman seçeceğinizi, kopyanın nelerden yoksun kalacağını ve sonucu nasıl doğrulayacağınızı görürsünüz.
Bir bakışta
- INSERT INTO SELECT, var olan bir tabloya sorgu sonucunu ekler. Hedef tablo önceden vardır; kolon sayısı, sırası ve veri tipleri sorgunun çıktısıyla uyumlu olmalıdır.
- SELECT INTO, sorgu sonucundan yeni tablo yaratır. SQL Server'da hedef tablo zaten varsa komut hata verir; MySQL ve PostgreSQL'de benzer iş CREATE TABLE ... AS SELECT ile yapılır.
- Kopya tablo kaynağın indeks, kısıt ve tetikleyicilerini taşımaz. Birincil anahtar ve indeksler kopya üzerinde ayrıca tanımlanmalıdır.
- Toplu değişiklikten önce yedek tablo almak en ucuz sigortadır. Kopyanın satır sayısını kaynakla karşılaştırmadan bir sonraki adıma geçmeyin.
Var olan tabloya ekleme ya da yeni tablo yaratma
Kopyalama işlerinde ilk soru hedef tablonun var olup olmadığıdır. Var olan bir tabloya veri ekliyorsanız INSERT INTO SELECT kullanırsınız. Tablo henüz yoksa ve kopyayı sorgunun sonucundan yaratmak istiyorsanız SELECT INTO (SQL Server) ya da CREATE TABLE ... AS SELECT (MySQL ve PostgreSQL gibi sistemlerde) kullanılır.
Var olan tabloya ekleme:
INSERT INTO musteri_arsiv (ad, soyad, sehir) SELECT ad, soyad, sehir FROM musteri WHERE sehir = 'İzmir';
SQL Server'da yeni tablo olarak kopyalama:
SELECT ad, soyad, sehir INTO musteri_yedek FROM musteri;
INSERT INTO SELECT'te hedef tablonun yapısını siz belirlemişsinizdir; kolonlara ne yazılacağını kolon listesi ve SELECT'in sırası kontrol eder. SELECT INTO'da tabloyu sorgunun çıktısı tanımlar: kolon adları, veri tipleri ve boş bırakılabilirlik seçim listesindeki ifadelerden türetilir. Hızlı bir yedek ya da analiz için ara tablo gerektiğinde SELECT INTO pratiktir, kalıcı bir yapı kuruyorsanız tabloyu önce kendiniz tanımlayıp INSERT INTO SELECT ile doldurmak daha denetimlidir.
Hedef tablo varsa ekleme, yoksa yeni tablo yaratma yöntemi seçilir
SQL Server'daki iki kalıp
| INSERT INTO SELECT | SELECT INTO | |
|---|---|---|
| Hedef tablo | Önceden vardır | Komutla yaratılır, varsa hata verir |
| Kolon yapısı | Sizin tanımınızdır | Seçim listesinden türetilir |
| İndeks ve kısıtlar | Hedef tablodakiler geçerlidir | Kaynaktan taşınmaz |
| Tipik kullanım | Arşivleme, ara tablodan asıl tabloya yükleme | Hızlı yedek, analiz için geçici kopya |
INSERT INTO SELECT: kolon eşleme ve güvenli çalıştırma
INSERT INTO SELECT'te en sık hata kolon eşlemesidir. SELECT'in döndürdüğü kolonlar, hedefteki kolon listesiyle sayı, sıra ve uyumlu veri tipi bakımından eşleşmelidir. Kolon listesini yazmadığınızda eşleşme hedef tablonun kolon sırasına göre yapılır ve tablo değişince komut sessizce yanlış çalışabilir. Bu yüzden listeyi hem INSERT hem SELECT tarafında açıkça yazın.
Hedefte otomatik artan kimlik kolonu varsa onu listeye koymayın; veritabanı yeni değerleri kendisi üretir. Kaynak kimlikleri aynen taşımanız gerekiyorsa sistemler bunun için ayrı bir ayar ister ve bu özel bir durumdur.
Çalıştırmadan önceki alışkanlık: önce SELECT kısmını tek başına çalıştırıp kaç satır döndürdüğüne bakın. WHERE koşulu beklenenden geniş çıkıyorsa hedef tabloyu istemediğiniz veriyle doldurmuş olursunuz. Aynı komutu yanlışlıkla yeniden çalıştırırsanız satırlar yinelenir; arşiv tablolarında bunu benzersiz bir kısıtla ya da NOT EXISTS koşuluyla engelleyin:
INSERT INTO musteri_arsiv (ad, soyad, sehir) SELECT m.ad, m.soyad, m.sehir FROM musteri AS m WHERE NOT EXISTS ( SELECT 1 FROM musteri_arsiv AS a WHERE a.ad = m.ad AND a.soyad = m.soyad );
Bu kalıp mükerrer eklemeyi önler. Gerçek işte karşılaştırma için kimlik gibi kesin bir anahtar kullanın; ad ve soyad aynı olan farklı kişiler hatalı elenebilir.
Ara tablo (staging) deseni de bu komuta dayanır: dış kaynaktan gelen veri önce bir ara tabloya yüklenir, orada temizlenip kontrol edilir, ardından INSERT INTO SELECT ile asıl tabloya aktarılır. Hatalı satırlar asıl tabloya hiç girmediği için temizlik ucuzdur ve yük sırasında canlı sorgular etkilenmez.
SELECT INTO ve yedek tablo almak
Toplu bir güncelleme ya da silmeden önce etkilenecek satırların yedeğini almak, SELECT INTO'nun en yaygın kullanımıdır:
SELECT * INTO musteri_yedek FROM musteri WHERE sehir = 'İzmir';
SQL Server'ın belgesine göre komut yeni bir tablo yaratır ve satırları içine ekler; iki adımlı çalıştığı için ekleme sırasında hata olursa eklemeler geri alınır ama boş tablo kalır. Bütünlüğü tek parça istiyorsanız komutu açık bir transaction içinde çalıştırın.
Kopyanın neleri taşımadığı en kritik ayrıntıdır. Kaynak tablodaki indeksler, kısıtlar ve tetikleyiciler yeni tabloya aktarılmaz; gerekiyorsa sonradan tanımlanır. Kimlik (identity) özelliği ise yalnızca belirli koşullarda taşınır: sorguda birleştirme ya da UNION varsa, kimlik kolonu bir ifadenin parçasıysa özellik kaybolur. Yani yedek tablo veriyi kurtarır ama tablo tanımını kurtarmaz; geri yükleme gerektiğinde bu fark sürpriz olabilir.
Boş bir tablo iskeleti istiyorsanız koşulu hiçbir satırı getirmeyecek biçimde yazabilirsiniz:
SELECT * INTO musteri_bos FROM musteri WHERE 1 = 0;
Bu komut kolon yapısını kopyalar, satır getirmez. MySQL ve PostgreSQL'de aynı sonuç CREATE TABLE ... AS SELECT ile alınır; ayrıntısı sistemin belgesinde kontrol edilmelidir.
Kopyayı doğrulamak ve yaygın hatalar
Kopyalamadan sonra birkaç kontrol yapılmadan iş bitmiş sayılmaz. Biri satır sayısıdır: kaynakta aynı koşulla kaç satır varsa kopyada da o kadar olmalıdır. Diğeri içeriktir: uç değerleri, NULL içeren kolonları ve metin uzunluklarını birkaç örnek satırda gözle karşılaştırın.
Sık karşılaşılan sorunlar şunlardır.
- SELECT INTO yeniden çalıştırıldığında tablo zaten var olduğu için hata verir; tabloyu silmeden yeniden denemeyin.
- Kolon sırasının farklı olması: listesiz INSERT INTO SELECT veriyi kayık kolonlara yazar.
- Veri tipi uyuşmazlığı: hedefteki kolon daha kısadır ve uzun metin kesilir ya da hata verir.
- Yedek tabloyu sınırsız saklamak: yedek isimleri tarihli ve tablo yaşı belli olmalı, iş bitince silinmelidir.
- Canlı bir tablodan yapılan büyük kopyanın o sırada kilit ve yük oluşturabileceğini unutmak.
Büyük kopyalarda veriyi parçalara bölmek ve yoğun olmayan saatte çalıştırmak, canlı sistemi korur. Kopya bir kez doğrulandıktan sonra değişiklik sorgusunu çalıştırın; sorun çıkarsa yedekten ilgili satırları geri yükleyebilirsiniz.
Doğrulamayı gözle bırakmayıp sorguyla yapın. Önce satır sayılarını yan yana getirin:
SELECT COUNT(*) FROM musteri WHERE sehir = 'İzmir'; SELECT COUNT(*) FROM musteri_arsiv;
Sayılar tutuyorsa içerik farkını bulmak için EXCEPT işlecini destekleyen sistemlerde kaynaktan hedefi çıkarın:
SELECT ad, soyad, sehir FROM musteri WHERE sehir = 'İzmir' EXCEPT SELECT ad, soyad, sehir FROM musteri_arsiv;
Sonuç boşsa kaynaktaki her satır hedefte vardır. Sonuç doluysa eksik ya da farklı kalan satırlar gerçek bir fark gösterir. Ters yönde de çalıştırarak hedefte fazladan satır olup olmadığına bakın.
Riskli bir toplu işlemde komutu transaction içinde çalıştırıp kontrolü işlem açıkken yapmak en güvenlisidir (SQL Server söz dizimiyle):
BEGIN TRANSACTION; INSERT INTO musteri_arsiv (ad, soyad, sehir) SELECT ad, soyad, sehir FROM musteri WHERE sehir = 'İzmir'; SELECT COUNT(*) FROM musteri_arsiv; -- sayı beklenenle tutmuyorsa: ROLLBACK; -- tutuyorsa: COMMIT;
Böylece yanlış bir koşulun yol açtığı hasar kalıcı hale gelmeden geri alınır. Aynı yaklaşım üretim ortamına geçmeden önce deneme ortamında da prova edilmelidir.
Bu beceriyi Mindset programında nerede çalışırsınız?
Mindset'in SQL ile Programlama Eğitimi, Veri İşleme Dili ve Tablolarla Çalışma modüllerinde bu işlemleri bir örnek veritabanı üzerinde uygular. Veriyle çalışan analistler için pratik kazanım, her toplu değişiklikten önce yedeği alma disiplinidir.
Kendi işinizde sık güncellenen bir tablo varsa onu bir deneme ortamında kopyalayıp satır sayısını kaynakla karşılaştırmak iyi bir başlangıç alıştırmasıdır.
İlgili Mindset programı
SQL ile Programlama Eğitimi
Sık sorulan sorular
INSERT INTO SELECT ile SELECT INTO arasındaki asıl fark nedir?
INSERT INTO SELECT var olan bir tabloya satır ekler ve kolon yapısını siz belirlersiniz. SELECT INTO (SQL Server) ise sorgu sonucundan yeni tablo yaratır ve hedef varsa hata verir. İlki kalıcı yapılar, ikincisi hızlı yedek ve ara tablolar için uygundur.
SELECT INTO indeksleri ve kısıtları da kopyalar mı?
Hayır. SQL Server belgesine göre kaynak tablodaki indeksler, kısıtlar ve tetikleyiciler yeni tabloya aktarılmaz. Gerekiyorsa kopya oluşturulduktan sonra elle tanımlanırlar. Bu yüzden yedek tablo veriyi korur ama tablo tanımını korumaz.
MySQL ve PostgreSQL'de SELECT INTO ile tablo kopyalanır mı?
Bu sistemlerde yeni tablo yaratarak kopyalama genellikle CREATE TABLE ... AS SELECT ile yapılır; SELECT INTO başka anlamlar taşır. Kendi sürümünüzün belgesini kontrol edin ve önce deneme ortamında çalıştırın.
Kopyalama sırasında hata olursa ne olur?
INSERT INTO SELECT tek komut olarak çalıştığı için hata olursa eklenen satırlar geri alınır. SQL Server'daki SELECT INTO ise tabloyu önce yaratıp sonra satırları eklediğinden, hata sonrası boş tablo kalabilir. Bütünlük istiyorsanız komutu açık bir transaction içinde çalıştırın.
Bir tablonun yedeğini almak için en güvenli yol nedir?
Tablo kopyası hızlı bir geri dönüş noktası sağlar ama kalıcı yedek yerine geçmez. Veritabanı yedeklemesi ayrı bir işletim süreciyle yapılır; tablo kopyası yalnızca toplu değişiklik öncesi hızlı geri dönüş içindir.