SQLite'a CSV dosyası aktarmak için sqlite3 komut satırı aracında .import --csv dosya.csv tablo komutunu, dışa aktarmak için ise çıktı biçimini .mode csv yapıp sonucu .once dosya.csv ile bir dosyaya yönlendirmeyi kullanırsınız. Ek bir araç gerekmez; ikisi de komut satırı aracının yerleşik özellikleridir.
Bu yazıda tablo yokken ve varken içe aktarmanın farkını, başlık satırının nasıl işlendiğini, boş alanların NULL değil boş metin olarak geldiğini, hatalı satırların davranışını, noktalı virgülle ayrılmış dosyaları, CSV ve TSV olarak dışa aktarmayı ve tek satırlık kabuk komutlarını örneklerle anlatıyoruz. Örnekler SQLite 3.50.6 komut satırı aracıyla çalıştırıldı; 3.53.0 ile değişen .mode sözdizimini ayrıca belirtiyoruz.
Örnek dosya
Bütün örneklerde aşağıdaki küçük ürün listesini kullanacağız. Dosyada RFC 4180 kurallarının üç önemli örneği var: virgül içeren bir alan çift tırnağa alınmış, alan içindeki çift tırnak iki kez yazılarak kaçırılmış ve son satırda fiyat ile açıklama boş bırakılmış.
cat urunler.csv
# çıktı:
# ad,fiyat,stok,aciklama
# Çay bardağı,45.5,120,"Cam, 6'lı set"
# Kahve fincanı,89,40,"Porselen ""el yapımı"""
# Şeker kabı,,15,.import: tablo yoksa
Belgelere göre .import komutunun ilk satırı nasıl işlediği hedef tablonun var olup olmadığına bağlıdır. Tablo yoksa komut onu otomatik olarak oluşturur ve ilk satırdaki değerleri sütun adı olarak kullanır; veri ikinci satırdan başlar. --csv seçeneği, girdinin o anki çıktı biçiminden bağımsız olarak virgülle ayrılmış CSV olarak okunmasını sağlar.
.import --csv urunler.csv urun
.schema urun
-- çıktı:
-- CREATE TABLE IF NOT EXISTS "urun"(
-- "ad" TEXT, "fiyat" TEXT, "stok" TEXT, "aciklama" TEXT);
SELECT ad, fiyat, typeof(fiyat) FROM urun;
-- çıktı:
-- Çay bardağı|45.5|text
-- Kahve fincanı|89|text
-- Şeker kabı||textOtomatik oluşturulan tablonun bütün sütunları TEXT tipindedir. Bu yüzden fiyat ve stok değerleri sayı gibi görünse de metin olarak saklanır. Bunun pratik sonucu sıralama ve karşılaştırmada ortaya çıkar: metin olarak saklanan "120" ile "40" karşılaştırıldığında sayısal değere değil karakter sırasına bakılır ve "120" önce gelir. Bu tablo hızlı bir göz atma için yeterlidir, ancak kalıcı veri için sütun tiplerini kendiniz belirlemeniz daha iyidir. Tiplerin ve sütun eğiliminin (affinity) ayrıntıları SQLite veri tipleri ve type affinity yazısında.
.import: tablo varsa

Hedef tablo zaten varsa ilk satır dahil bütün satırlar veri kabul edilir. Dosyanızda başlık satırı varsa onu --skip 1 ile atlamanız gerekir. Tabloyu önceden tiplerle oluşturduğunuzda, gelen metin değerleri sütunun eğilimine göre dönüştürülür:
CREATE TABLE urun2(ad TEXT NOT NULL, fiyat REAL, stok INTEGER, aciklama TEXT);
.import --csv --skip 1 urunler.csv urun2
SELECT ad, fiyat, typeof(fiyat), stok, typeof(stok), aciklama FROM urun2;
-- çıktı:
-- Çay bardağı|45.5|real|120|integer|Cam, 6'lı set
-- Kahve fincanı|89.0|real|40|integer|Porselen "el yapımı"
-- Şeker kabı||text|15|integer|REAL eğilimli sütuna gelen "89" değeri 89.0 olarak, INTEGER eğilimli sütuna gelen "120" ise tamsayı olarak saklandı. Tırnaklı alanlar da doğru ayrıştırıldı: virgül içeren açıklama tek bir değer olarak geldi ve kaçırılmış çift tırnaklar tek tırnağa döndü. Belgelere göre --ascii dışındaki modlarda alanlar her zaman RFC 4180'e göre tırnaklardan arındırılır.
Boş alanlar NULL değil boş metindir
Son satıra dikkat edin: fiyatı boş olan satırda değerin tipi null değil text. CSV biçiminde NULL ile boş metni ayıran bir gösterim olmadığı için içe aktarma boş alanı boş metin olarak ekler. REAL eğilimli bir sütun bile boş metni sayıya çeviremediği için metin olarak saklar. Hesaplamalarda ve IS NULL kontrollerinde sürpriz yaşamamak için içe aktarmadan hemen sonra bu değerleri NULLIF ile NULL'a çevirin:
UPDATE urun2 SET fiyat = NULLIF(fiyat, ''), aciklama = NULLIF(aciklama, '');
SELECT ad, typeof(fiyat), typeof(aciklama) FROM urun2;
-- çıktı:
-- Çay bardağı|real|text
-- Kahve fincanı|real|text
-- Şeker kabı|null|nullNULL değerlerin karşılaştırma ve toplama fonksiyonlarındaki davranışı SQLite NULL davranışı yazısında anlatılıyor. Sütunlara CHECK gibi kısıtlar koyarak hatalı veriyi daha içe aktarma sırasında yakalamak da mümkündür; kısıt ayrıntıları SQLite CREATE TABLE ve kısıtlamalar yazısında.
--skip 1 unutulursa
CREATE TABLE urun3(ad TEXT, fiyat REAL, stok INTEGER, aciklama TEXT);
.import --csv urunler.csv urun3
SELECT rowid, ad, typeof(fiyat) FROM urun3;
-- çıktı:
-- 1|ad|text
-- 2|Çay bardağı|real
-- 3|Kahve fincanı|real
-- 4|Şeker kabı|textBaşlık satırı sıradan bir veri satırı olarak eklendi; "fiyat" metni sayıya çevrilemediği için metin olarak kaldı. Bu tür hatalar tipleri esnek olan SQLite'ta sessizce gerçekleşir. Katı tip denetimi yapan STRICT tablolar sayıya çevrilemeyen bir değeri REAL sütununa kabul etmez.
Biçimi içe aktarmadan önce ayarlayın

Belgeler .import öncesinde biçimi ayarlamanın önemli olduğunu vurgular: --csv veya --ascii verilmezse ayırıcı olarak o anki çıktı biçiminin ayırıcıları kullanılır. Komut satırı aracının betiklerdeki varsayılan biçimi list, ayırıcısı da dikey çizgidir. Bu yüzden aşağıdaki komut dosyadaki her satırı tek bir sütun olarak okudu:
-- .mode list (betiklerdeki varsayılan) açıkken --csv vermeden:
.import urunler.csv u3
.schema u3
-- çıktı:
-- CREATE TABLE IF NOT EXISTS "u3"(
-- "ad,fiyat,stok,aciklama" TEXT);Bu durumdan korunmanın en kolay yolu her .import komutuna --csv eklemektir. Komutun diğer seçenekleri de belgelerde ve .help import çıktısında yer alır: --schema S tabloyu main dışındaki bir şemaya, örneğin bağlı bir veritabanına veya temp şemasına aktarır; -v ek bilgi yazdırır. Kaynak argümanı | karakteriyle başlıyorsa dosya yerine bir komut çalıştırılır ve onun çıktısı okunur; bu sayede sıkıştırılmış bir dosyayı önce açmadan aktarabilirsiniz.
Hatalı satırlar
Sütun sayısı tutmayan satırlar içe aktarmayı durdurmaz. Fazla sütunlar atılır, eksik sütunlar NULL ile doldurulur ve her satır için bir uyarı yazılır. Bu uyarılar standart hata akışına gider; betiklerde onları ayrı bir dosyaya yönlendirip kontrol etmenizi öneririz:
-- bozuk.csv içeriği:
-- a,b
-- 1,2,3
-- 4
CREATE TABLE ab(a, b);
.import --csv --skip 1 bozuk.csv ab
-- çıktı:
-- bozuk.csv:2: expected 2 columns but found 3 - extras ignored
-- bozuk.csv:3: expected 2 columns but found 1 - filling the rest with NULL
SELECT a, b, typeof(b) FROM ab;
-- çıktı:
-- 1|2|text
-- 4||nullBurada b sütununun tipi tanımlanmadığı için gelen "2" değeri metin olarak kaldı. Eksik sütunun gerçek NULL olarak geldiğine de dikkat edin; bu, boş bırakılmış bir alanın davranışından farklıdır.
Önce geçici tabloya, sonra asıl tabloya
Gerçek projelerde en güvenli yol, dosyayı önce dönüştürme yapmadan bir ara tabloya almak, ardından temizleyip asıl tabloya taşımaktır. --schema temp seçeneği ara tabloyu temp şemasında oluşturur; bu tablo yalnızca o bağlantı süresince yaşar ve veritabanı dosyasına yazılmaz. Ara tablonun bütün sütunları metin olduğu için dönüşümleri CAST, NULLIF veya trim() gibi ifadelerle kendiniz yaparsınız ve yalnızca istediğiniz sütunları seçersiniz:
.import --csv --schema temp urunler.csv ham
CREATE TABLE stok_ozet(ad TEXT NOT NULL, stok INTEGER NOT NULL);
INSERT INTO stok_ozet(ad, stok) SELECT ad, CAST(stok AS INTEGER) FROM temp.ham;
SELECT ad, stok, typeof(stok) FROM stok_ozet ORDER BY stok DESC;
-- çıktı:
-- Çay bardağı|120|integer
-- Kahve fincanı|40|integer
-- Şeker kabı|15|integerBu yaklaşımın iki faydası var. Birincisi, asıl tablonun kısıtları, örneğin buradaki NOT NULL, dönüştürülmüş veriye uygulanır; hatalı satır asıl tabloya hiç girmez. İkincisi, aynı dosyayı birden fazla kez denerken asıl tabloyu kirletmezsiniz: bir şey ters giderse bağlantıyı kapatmanız ara tabloyu silmeye yeter. Taşıma işlemini BEGIN ve COMMIT arasına almak, yarıda kalan bir aktarımın yarım veri bırakmasını da önler. Metin temizleme fonksiyonları için SQLite metin fonksiyonları yazısına bakabilirsiniz.
Noktalı virgülle ayrılmış dosyalar ve BOM
Bazı tablo programları, özellikle virgülü ondalık ayırıcı olarak kullanan bölge ayarlarında, CSV dosyalarını noktalı virgülle ayırabilir ve dosyanın başına UTF-8 bayt sırası işareti (BOM) ekleyebilir. 3.50.6 aracında ayırıcıyı .separator komutuyla değiştirip --csv vermeden içe aktardık. Denememizde BOM sütun adına karışmadı; ilk sütunun adı temiz biçimde kod olarak geldi:
-- il.csv: UTF-8 BOM ile başlayan, noktalı virgülle ayrılmış dosya
-- kod;sehir
-- 34;İstanbul
-- 35;İzmir
.mode csv
.separator ;
.import il.csv il
.mode list
SELECT name FROM pragma_table_info('il');
-- çıktı:
-- kod
-- sehir
SELECT kod, sehir FROM il;
-- çıktı:
-- 34|İstanbul
-- 35|İzmir3.53.0 sürüm notları .mode komutunda büyük değişiklikler yapıldığını belirtir. Güncel belgelerde içe aktarmanın alan ve satır ayırıcılarının .mode komutunun --colsep ve --rowsep seçenekleriyle belirlendiği yazar. Yeni bir araç kullanıyorsanız aynı işlemi şu biçimde yapabilirsiniz:
-- SQLite 3.53.0 ve sonrası (belgelerdeki .mode sözdizimi; çalıştırılmadı)
.mode csv --colsep ";"
.import il.csv ilAyırıcısı rastgele bir karakter olan ve hiç tırnak kullanmayan veriler için belgeler --ascii seçeneğini --colsep ve --rowsep ile birlikte kullanmayı önerir; bu modda tırnak kaldırma yapılmaz.
CSV olarak dışa aktarma

Dışa aktarmak için çıktı biçimini CSV yapar, başlık satırını açar ve bir sonraki sorgunun çıktısını dosyaya yönlendirirsiniz. .once yalnızca bir sonraki komutun çıktısını dosyaya gönderir ve ardından konsola döner; kalıcı yönlendirme için .output dosya, konsola dönmek için argümansız .output kullanılır.
.headers on
.mode csv
.once disa.csv
SELECT ad, fiyat, stok, aciklama FROM urun2 ORDER BY rowid;cat disa.csv
# çıktı:
# ad,fiyat,stok,aciklama
# "Çay bardağı",45.5,120,"Cam, 6'lı set"
# "Kahve fincanı",89.0,40,"Porselen ""el yapımı"""
# "Şeker kabı",,15,Çıktı RFC 4180'e uygundur: virgül ve tırnak içeren alanlar tırnaklanmış, iç tırnaklar ikilenmiş, NULL değerler boş bırakılmıştır. Denememizdeki 3.50.6 aracı ASCII dışında harf içeren metinleri de tırnağa aldı; bu RFC açısından geçerlidir ve tırnaklar okunurken kaldırılır. Belgelere göre CSV çıktısında satır sonu, .crlf ayarından bağımsız olarak her zaman CRLF yani \r\n olur.
Güncel belgelerdeki örnek başlık satırını .headers on yerine .mode komutunun --titles on seçeneğiyle açar. Bu sözdizimi yeni .mode komutuyla geldiği için eski araçlarda çalışmayabilir:
-- SQLite 3.53.0 ve sonrası (belgelerdeki örnek; çalıştırılmadı)
.mode csv --titles on
.once disa.csv
SELECT * FROM urun2;Çıktı biçimlerinin tamamı ve 3.53.0 ile gelen yeni biçimlendirici SQLite .mode çıktı biçimleri yazısında anlatılıyor.
Kabukta tek satır
Betiklerde ve zamanlanmış görevlerde etkileşimli oturum açmadan da dışa aktarabilirsiniz. -csv ve -header komut satırı seçenekleri biçimi ayarlar, sorgu ikinci argüman olarak verilir ve çıktı kabuk yönlendirmesiyle dosyaya yazılır. 3.54.0 sürüm notlarına göre -csv seçeneği eski davranışla uyum için görüntüleme sınırlarını da otomatik olarak kapatır.
sqlite3 -csv -header magaza.db "SELECT ad, stok FROM urun2 ORDER BY stok DESC" > stok.csv
cat stok.csv
# çıktı:
# ad,stok
# "Çay bardağı",120
# "Kahve fincanı",40
# "Şeker kabı",15TSV ve tablo programına doğrudan gönderme
Sekmeyle ayrılmış çıktı için .mode tabs kullanılır. Belgelere göre bu mod CSV gibi çalışır, yalnızca ayırıcı olarak sekme karakterini kullanır; güncel belgelerde tırnaksız TSV için --quote off seçeneğinin eklenmesi önerilir.
.headers on
.mode tabs
SELECT ad, stok FROM urun2 ORDER BY rowid;
-- çıktı:
-- ad stok
-- Çay bardağı 120
-- Kahve fincanı 40
-- Şeker kabı 15Masaüstünde çalışıyorsanız .excel komutu bir sonraki sorgunun sonucunu geçici bir CSV dosyasına yazar, sistemin CSV dosyaları için varsayılan programını açar ve ardından geçici dosyayı siler. Belgelere göre bu komut .once -x için bir takma addır. Sunucuda grafik arayüz olmadığı için bu komut yerine dosyaya yazmayı kullanın.
CSV sanal tablosu
Bir CSV dosyasını içe aktarmadan doğrudan sorgulamak isterseniz belgelerde anlatılan CSV sanal tablosu kullanılabilir. Bu tablo SQLite'ın standart birleşik kaynak dosyasında bulunmaz; ayrı bir kaynak dosyadan yüklenebilir eklenti olarak derlenmesi gerekir. Belgeler tabloyu temp. önekiyle oluşturmayı önerir; böylece tablo yalnızca o bağlantı süresince var olur ve kalıcı şemaya eklenmez. header seçeneği ilk satırı başlık kabul eder, columns=N sütun sayısını, schema= ise sütun adlarını tanımlayan bir CREATE TABLE ifadesini belirtir. Deneme ortamımızda bu eklenti bulunmadığı için örnek çalıştırılmadı:
-- csv eklentisi derlenmiş ve bu dizinde ise (belgelerdeki örnek; çalıştırılmadı)
.load ./csv
CREATE VIRTUAL TABLE temp.t1 USING csv(filename='urunler.csv', header=1);
SELECT * FROM t1;Sık yapılan hatalar
- --csv vermemek: Varsayılan list modunda ayırıcı dikey çizgidir ve bütün satır tek sütuna yazılır.
- Var olan tabloya başlıkla aktarmak: Tablo varsa ilk satır da veri sayılır;
--skip 1ekleyin. - Otomatik tabloya güvenmek: Komutun oluşturduğu tabloda bütün sütunlar
TEXTolur; sayısal sıralama ve toplama beklediğiniz gibi çalışmayabilir. - Boş alanı NULL sanmak: Boş alanlar boş metin olarak gelir;
NULLIFile dönüştürün. - Uyarıları görmezden gelmek: Sütun sayısı tutmayan satırlar kırpılır veya NULL ile doldurulur; uyarıları yakalayın.
- Güvenilmeyen betikte .import çalıştırmak: Belgelere göre
--safeseçeneği.import,.once,.outputve.excelkomutlarını kapatır; dışarıdan gelen betikleri bu seçenekle inceleyin. Ayrıntılar SQLite güvenlik ayarları yazısında.
Sık Sorulan Sorular
Büyük bir CSV dosyasını aktarmak ne kadar sürer?
Süre dosyanın boyutuna, tablodaki indekslere ve diske bağlıdır; belgeler bir süre vermez. Yazma maliyetini düşürmenin genel yolları, örneğin işlemleri gruplamak, SQLite performans ayarları yazısında anlatılıyor.
Türkçe karakterler bozuk geliyor, ne yapmalıyım?
SQLite metni UTF-8 olarak saklar. Dosyanız başka bir kodlamayla kaydedildiyse önce UTF-8'e dönüştürün. Denememizde UTF-8 BOM içeren dosya sorunsuz aktarıldı.
Belirli sütunları içe aktarabilir miyim?
.import bütün sütunları sırayla aktarır. Seçerek almak için dosyayı önce geçici bir tabloya, örneğin --schema temp ile temp şemasına aktarıp ardından INSERT INTO ... SELECT ile istediğiniz sütunları asıl tabloya kopyalayın. Bu ifadenin ayrıntıları SQLite INSERT, UPDATE, DELETE yazısında.
Dışa aktarırken NULL değerleri nasıl ayırt ederim?
CSV çıktısında NULL varsayılan olarak boş alan olarak yazılır ve boş metinden ayırt edilemez. Karşı taraf bu ayrımı önemsiyorsa NULL için bir gösterim seçin. 3.50.6 aracında bunu .nullvalue komutu yapar; güncel belgelerde aynı ayar .mode komutunun --null seçeneğiyle verilir:
.mode csv
.nullvalue NULL
SELECT ad, fiyat FROM urun2 ORDER BY rowid;
-- çıktı:
-- "Çay bardağı",45.5
-- "Kahve fincanı",89.0
-- "Şeker kabı",NULLBu metin yeniden içe aktarıldığında "NULL" sıradan bir metin olarak gelir; geri dönüşte NULLIF(fiyat, 'NULL') ile tekrar NULL'a çevirmeniz gerekir.
Uygulama kodundan CSV aktarabilir miyim?
.import komut satırı aracına özgüdür, SQLite kütüphanesinde yoktur. Kod içinden aktarırken dosyayı dilinizin CSV okuyucusuyla okuyup parametreli INSERT ifadeleriyle eklersiniz; bağlayıcı kullanımı için Python sqlite3 yazısına bakabilirsiniz.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: SQLite öğrenme rehberi · SQLite .mode çıktı biçimleri · SQLite CLI nokta komutları · SQLite veri tipleri · SQLite ATTACH DATABASE