CSV İçe Aktarma SQL'de Değil, CLI'da Yaşar
SQLite'ın SQL söz diziminde IMPORT diye bir komut yoktur. CSV yükleme işi tamamen sqlite3 komut satırı kabuğuna ait bir özelliktir; yani .import adında bir nokta komutuyla yapılır. MySQL'in LOAD DATA INFILE komutundan veya Postgres'in COPY komutundan geliyorsanız bu zihinsel ayrım önemli: o komutlar sunucu tarafında çalışır, ama .import istemci aracının kendisinin yaptığı bir iştir — dosyayı okur ve arka planda INSERT ifadelerini sizin yerinize çalıştırır.
Yani bu sayfadaki her şey, sqlite3 kabuğunun içinde olduğunuzu varsayar:
sqlite3 mydata.db
Eğer CSV'yi uygulama kodundan içeri almanız gerekiyorsa — Python, Node, Go gibi — CSV'yi kendi dilinizde okuyup parametreli INSERT ifadeleri kullanırsınız. Bu yaklaşımı uygulama entegrasyonu bölümünde ele alacağız. Burada odak noktamız CLI.
En Basit Haliyle .import Komutu
En kısa yol şu: SQLite'a dosyanın CSV olduğunu söyleyin, ardından .import komutunu dosya yoluna ve hedef tablo adına yönlendirin.
.mode csv
.import people.csv people
people tablosunun var olup olmamasına göre iki farklı senaryo yaşanır:
- Tablo yoksa — SQLite tabloyu kendisi oluşturur ve CSV'nin ilk satırını sütun adları olarak kullanır. Tüm sütunlar
TEXTtipinde olur. - Tablo zaten varsa — SQLite dosyadaki her satırı veri olarak ekler. Başlık satırı varsa, o da bir veri satırı olarak tabloya girer.
İşte çoğu kişinin ilk denemede tökezlediği nokta tam olarak bu ikinci durum. CSV dosyanızda başlık satırı varsa ve tablo da önceden oluşturulmuşsa, başlık satırını açıkça atlamanız gerekir.
Mevcut Tabloya CSV Aktarırken Başlık Satırını Atlama
.import komutuna ilk N satırı yok saymasını söylemek için --skip 1 parametresini kullanın:
CREATE TABLE people (
name TEXT,
age INTEGER,
city TEXT
);
.import --csv --skip 1 people.csv people
--csv, sadece bu komut için geçerli olan .mode csv ayarının kısa yoludur; yani modu ayrıca ayarlamak zorunda kalmazsın. --skip 1 ile başlık satırını atlarsınız. Geriye kalan satırlar da people tablosuna kolon sırasına göre eklenir.
İçe aktarma sonrası hızlı bir kontrol:
SELECT count(*) FROM people;
SELECT * FROM people LIMIT 5;
Dosyadaki sütun sırası, tablodaki sütun sırasıyla birebir aynı olmalı. Başlık adına göre eşleme diye bir şey yok — .import basitçe N'inci alanı N'inci sütuna yerleştirir.
Tabloyu SQLite'a oluşturtmak
Hızlıca bir şeyleri kurcalamak istediğinde en pratik yol, CREATE TABLE adımını tamamen atlayıp tabloyu başlık satırından .import komutuna oluşturtmaktır:
.mode csv
.import sales.csv sales
.schema sales
.schema sales komutu çalıştırıldığında şuna benzer bir çıktı görürsünüz:
CREATE TABLE sales(
"order_id" TEXT,
"amount" TEXT,
"ordered_at" TEXT
);
Dikkat ederseniz tüm sütunlar TEXT türünde. Bu bilinçli bir tercih — .import komutu tür çıkarımı yapmaya çalışmaz. Eğer amount alanını gerçek bir sayı, ordered_at alanını da düzgün bir zaman damgası olarak istiyorsanız, tabloyu önce kendiniz doğru türlerle oluşturup ardından --skip 1 ile içe aktarın. SQLite'ın type affinity özelliği, sayısal string değerleri ekleme sırasında integer ve real türlerine kendiliğinden dönüştürür.
Özel ayraçlar: TSV, pipe, noktalı virgül
.mode csv virgülü ayraç olarak kullanır. Tab ile ayrılmış dosyalar için modu değiştirmeniz yeterli:
.mode tabs
.import data.tsv events
Farklı ayırıcılar için, modu seçtikten sonra .separator komutunu kullanın:
.mode csv
.separator "|"
.import pipe_data.txt events
Şunu bilmekte fayda var: .mode csv RFC 4180 alıntı kurallarına uyar — yani içinde virgül veya satır sonu geçen alanlar, " ile düzgün biçimde alıntılandığı sürece sorunsuz çalışır. .mode tabs ise alıntılama desteği olmayan, sadece karaktere göre bölen daha basit bir moddur. Eğer dosyanızda ayraç içeren alıntılı alanlar varsa, .mode csv modunda kalıp ayraç karakterini değiştirmeniz daha doğru olur.
Gerçek Bir Örnek Üzerinden CSV Aktarma
Diyelim ki elimizdeki orders.csv dosyası şöyle görünüyor:
order_id,customer,amount,ordered_at
1001,Ada,49.99,2026-01-12
1002,Boris,12.50,2026-01-13
1003,"Chen, Wei",199.00,2026-01-14
- satırda tırnak içinde virgül geçen bir alan olduğuna dikkat edin. Tam oturum şöyle:
Gerçek bir shell'de INSERT bloğunun yerini tek bir .import --csv --skip 1 orders.csv orders komutu alır. CSV modu tırnakları koruduğu için "Chen, Wei" alanı bozulmadan gelir. Sütun tipleri sayesinde amount gerçek bir sayı, order_id ise tam sayı olarak kaydedilir.
CSV Aktarımını Transaction İçine Almak
.import her satır için ayrı bir INSERT çalıştırır. Birkaç bin satır için sorun yok, ama milyonluk verilerde SQLite her satırdan sonra commit yaptığı için iş çekilmez bir hâl alır. Çözüm, tüm aktarımı bir transaction'a sarmak:
BEGIN;
.import --csv --skip 1 big_file.csv events
COMMIT;
Tek bir değişiklikle dakikalar süren bir import işlemi birkaç saniyeye iner. İşlem ortasında bir şeyler ters giderse ROLLBACK yarıda kalan yüklemeyi geri alır; bu da tekrar denemelerde işinize yarar.
Daha da hızlandırmak isterseniz import'tan önce index'leri kaldırıp sonradan yeniden oluşturabilirsiniz — her satır için index güncellemesi ciddi yük bindiriyor.
Sık Karşılaşılan Hatalar ve Çözümleri
Error: expected N columns but found M — bir satırdaki alan sayısı tabloyla uyuşmuyor. Genelde sebebi şudur:
- Tırnaksız bir alanın içinde kaçak bir virgül vardır. Dosyayı düzgün CSV tırnaklamasıyla yeniden export edin ya da
.mode tabsyerine.mode csv(RFC 4180) kullanın. - Dosyanın sonunda boş bir satır kalmıştır. Dosyayı düzenleyin veya
--skipile yaratıcı olun. - Tabloda CSV'den daha fazla kolon vardır. Ya eksik kolonları dosyaya ekleyin ya da uygun şemada bir ara (staging) tablosuna yükleyip oradan asıl tabloya kopyalayın.
Başlık satırı veri olarak görünüyor — mevcut bir tabloya yazarken --skip 1 koymayı unutmuşsunuzdur. O satırı silip (DELETE FROM t WHERE rowid = 1) flag ile yeniden çalıştırın.
Sayılar string olarak saklanmış — tabloyu .import komutuna oluşturttuğunuzda her kolon TEXT olur. Tabloyu silin, INTEGER/REAL kolonlarıyla elle tanımlayın ve tekrar import edin.
Error: no such file — yol, veritabanı dosyasına göre değil, sqlite3'ü başlattığınız dizine göre çözülür. Mutlak yol kullanın ya da shell'i açmadan önce doğru dizine cd ile geçin.
CLI hatalarda satır numarasını yazdırır; büyük dosyalarda sorunlu satırı bulmanın en hızlı yolu budur.
Kısa Bir Özet
.importbir SQL komutu değil, CLI'ye özel bir nokta komutudur.sqlite3shell'i içinde çalıştırın.- Tırnakların doğru yorumlanması için
--csv, başlık satırını atlamak için--skip 1kullanın. - Tablo yoksa
.importbaşlık satırına bakıp tabloyu kendisi oluşturur — ama tüm kolonlarTEXTolur. Doğru tipler için tabloyu siz oluşturun. - Büyük import'ları
BEGIN/COMMITile sarmalayın; aksi halde her satır ayrı bir transaction olur. - Dosyadaki kolon sırası tablodaki kolon sırasıyla birebir aynı olmalı.
Sırada: Veriyi Geri Dışa Aktarma
İçe aktarma işin yarısı. Aynı shell sorgu sonuçlarını veya tüm tabloları CSV, JSON ya da SQL olarak geri dökebiliyor — yedekleme, veri pipeline'ları ve veriyi başka araçlara devretmek için birebir. Bunu veri dışa aktarma bölümünde göreceğiz.
Sıkça Sorulan Sorular
SQLite'a bir CSV dosyasını nasıl aktarırım?
Veritabanını sqlite3 CLI ile açın, .mode csv komutuyla CSV moduna geçin ve ardından .import data.csv tablo_adi komutunu çalıştırın. Tablo henüz yoksa, SQLite dosyanın ilk satırını sütun adı olarak kullanıp tabloyu sizin için oluşturur. Tablo zaten varsa, dosyadaki her satır veri olarak eklenir — yani başlık satırını atlamak için genellikle .import --skip 1 kullanmanız gerekir.
Başlık satırı içeren bir CSV'yi mevcut bir SQLite tablosuna nasıl aktarırım?
.import --csv --skip 1 data.csv tablo_adi komutunu kullanın. --skip 1 parametresi SQLite'a ilk satırı yok saymasını söyler, böylece başlık satırı veri olarak eklenmez. Bu parametre olmadan, tablonuzda sütun adlarının kelime kelime yazıldığı bir satırla karşılaşırsınız.
SQLite CSV import işlemim neden 'expected N columns but found M' hatasıyla başarısız oluyor?
Dosyada tablonun beklediğinden farklı sayıda sütuna sahip satırlar var — genelde sebep satır içindeki kaçışsız virgüller, kapatılmamış tırnaklar veya dosya sonundaki boş bir satırdır. .mode tabs yerine .mode csv (ya da --csv) kullanın ki SQLite tırnak işaretlerini RFC 4180'e göre yorumlasın; ayrıca dosyayı bir editörle açıp kaçak ayraçları kontrol edin. CLI sorunlu satırın numarasını yazdırır, bu da hatalı kaydı bulmanın en hızlı yoludur.