SQLite3 Hakkında Sorular

Merhaba arkadaşlar,

SQLite3 konusuyla alakalı sormak istediğimiz soruları bu başlık altında sorabileceğimizi ve sorularımıza cevaplar alabileceğimizi düşünüyorum. İlk soruyu sormak bana kısmet olsun. Lafı uzatmadan hemen konuya geçiyorum.

Daha önceden oluşturulmuş bir veritabanında veriler bulunuyor olsun ve sonra bu veritabanına fazladan sütunlar eklemiş olalım. Sonra veritabanına tekrar veriler eklediğimizde eski sütunlarla birlikte bu boş sütunlara da verilerin eklenebildiğini gözlemlemiş olalım. Ancak sütunlar oluşturulmadan önce eklenmiş olan veri grubunda bu yeni sütunların değerleri boş görünüyor olsun. Biz bu boş sütunlara nasıl veri ekleyebiliriz?
Soruyu somutlaştırmak için sizlerle veritabanı kalıbını paylaşmak istiyorum:

from sqlite3 import *
import datetime


class Veritabanı:
    def __init__(self, veritabanı, tablo, sütun_sayısı):
        self.__bağlan = connect("{}.db".format(veritabanı))
        self.__imleç = self.__bağlan.cursor()
        self.__tablo = tablo
        self.__sütun_sayısı = sütun_sayısı
        self.__geçici_sütun_listesi = []
        self.__geçici_veri_listesi = ()
    @staticmethod
    def __metin_düzenle(metin, işaret, sayı):
        metin_düzenleyicisi = [işaret] * sayı
        metin = metin.replace(işaret, ", ".join(metin_düzenleyicisi))
        metin = metin.replace("[]", işaret)
        return metin
    def __sütun_oluştur(self):
        print("İlk sütun tarih verisine verilmiştir.")
        for i in range(self.__sütun_sayısı - 1):
            while True:
                sütun_ismi = input("{}. Sütun İsmi:".format(i + 2))
                if str(sütun_ismi).isnumeric() or str(sütun_ismi) == "":
                    print("Sütun ismi boş bırakılamaz ve sayı değeri alamaz.")
                else:
                    self.__geçici_sütun_listesi.append(sütun_ismi)
                    break
    def tablo_oluştur(self):
        self.__sütun_oluştur()
        metin = "CREATE TABLE IF NOT EXISTS [](tarih, {})"
        yeni_metin = self.__metin_düzenle(metin=metin, işaret="{}", sayı=self.__sütun_sayısı - 1)
        self.__imleç.execute(yeni_metin.format(self.__tablo, *self.__geçici_sütun_listesi))
    def veri_ekle(self):
        tarih = str(datetime.datetime.now())[:19]
        self.__geçici_veri_listesi += (tarih,)
        for i in range(self.__sütun_sayısı - 1):
            veri = input("{}. Veriyi Ekle:".format(i + 2))
            self.__geçici_veri_listesi += (veri,)
        metin = "INSERT INTO {} VALUES(?)".format(self.__tablo)
        yeni_metin = self.__metin_düzenle(metin=metin, işaret="?", sayı=self.__sütun_sayısı)
        self.__imleç.execute(yeni_metin, self.__geçici_veri_listesi)
        self.__bağlan.commit()
        print("{} verisi veritabanına eklendi.".format(repr(self.__geçici_veri_listesi)))
        self.__geçici_veri_listesi = ()
    def veri_görüntüle(self):
        print(*self.__imleç.execute("SELECT * FROM {}".format(self.__tablo)), sep="\n")
    def veri_güncelle(self):
        while True:
            veri_listesi = [j for i in self.__imleç.execute("SELECT * FROM {}".format(self.__tablo)) for j in i]
            verinin_bulunduğu_sütun = input("Değiştirilecek Verinin Bulunduğu Sütun:")
            while True:
                eski_veri = input("Eski Veri İsmi:")
                if eski_veri not in veri_listesi:
                    print("{} verisi veritabanında kayıtlı değil.".format(repr(eski_veri)))
                else:
                    break
            yeni_veri = input("Yeni Veri İsmi:")
            while True:
                kontrol_sütunu = "tarih"
                print("Kontrol Sütunu: {}".format(kontrol_sütunu))
                kontrol_verisi = input("Kontrol Sütunundaki Veri İsmi:")
                if kontrol_verisi not in veri_listesi:
                    print("{} verisi veritabanında kayıtlı değil.".format(repr(kontrol_verisi)))
                elif veri_listesi.index(eski_veri) - veri_listesi.index(kontrol_verisi) != 1:
                    print("{} bilgisi ile 'tarih' bilgisi eşleşmedi.".format(repr(verinin_bulunduğu_sütun)))
                else:
                    break
            try:
                self.__imleç.execute("UPDATE {0} SET {1} = replace({1}, ?, ?) WHERE {2} = ?".format
                                     (self.__tablo, verinin_bulunduğu_sütun, kontrol_sütunu),
                                     (eski_veri, yeni_veri, kontrol_verisi))
                self.__bağlan.commit()
                print("{0} bilgisi {1} olarak değiştirildi.".format(repr(verinin_bulunduğu_sütun), repr(yeni_veri)))
                break
            except OperationalError:
                print("Sütun bulunamadı, tekrar deneyin.")
    def veri_sil(self):
        while True:
            veri_listesi = [j for i in self.__imleç.execute("SELECT * FROM {}".format(self.__tablo)) for j in i]
            verinin_bulunduğu_sütun = input("Silinecek Verinin Bulunduğu Sütun:")
            while True:
                veri = input("Silinecek Veri İsmi:")
                if veri not in veri_listesi:
                    print("{} verisi veritabanında kayıtlı değil.".format(repr(veri)))
                else:
                    break
            try:
                self.__imleç.execute("DELETE FROM {} WHERE {} = ?"
                                     .format(self.__tablo, verinin_bulunduğu_sütun), (veri,))
                self.__bağlan.commit()
                print("{} veritabanından silindi.".format(repr(veri)))
                break
            except OperationalError:
                print("Sütun bulunamadı, tekrar deneyin.")


if __name__ == "__main__":
    a = Veritabanı(veritabanı="veritabanı", tablo="tablo", sütun_sayısı=3)

    

Yukarıdaki kodlarda henüz kolon ekleme fonksiyonu tanımlanmamış. Tespit edebildiğim kadarıyla yukarıdaki kodlar sorunsuz bir şekilde çalışıyor.

Aşağıdaki sütun ekleme fonksiyonunu veritabanı sınıfının altına yerleştirdiğimizde ve bu fonksiyonu çağırdığımızda, istediğimiz kadar sütun oluşturuyoruz.

    def sütun_oluştur(self):
        while True:
            try:
                boş_sütun_sayısı = int(input("Sütun Sayısı:"))
                for i in range(boş_sütun_sayısı):
                    while True:
                        boş_sütun_ismi = input("Sütun İsmi:")
                        if str(boş_sütun_ismi).isnumeric() or str(boş_sütun_ismi) == "":
                            print("Sütun ismi boş bırakılamaz ve sayı değeri alamaz.")
                        else:
                            self.__imleç.execute("ALTER TABLE {} ADD COLUMN {}".format(self.__tablo, boş_sütun_ismi))
                            self.__bağlan.commit()
                            break
                break
            except ValueError:
                print("Sayı girmediniz.")

Aşağıda gösterildiği gibi, tablo_oluştur() fonksiyonundan hemen sonra veri_ekle() fonksiyonunu çalıştırıp tabloya veri eklersek ve sonradan da sütun_oluştur() fonksiyonunu çalıştırırsak, ilk eklenmiş verilerin hemen yanlarındaki sütunların boş olduğunu görürüz:

if __name__ == "__main__":
    a = Veritabanı(veritabanı="veritabanı", tablo="tablo", sütun_sayısı=3)
    a.tablo_oluştur()
    a.veri_ekle()
    a.sütun_oluştur()

Boş sütunları ekledikten sonra sütun_sayısı değerini eklediğimiz boş sütunlar kadar arttırırsak bir sonraki veri_ekleme işleminde hatayla karşılaşmayız.

if __name__ == "__main__":
    a = Veritabanı(veritabanı="veritabanı", tablo="tablo", sütun_sayısı=5)

Varsayalım bu sütun_sayısını 2 arttırdık ve tekrar veri_ekle() fonksiyonunu çağırdık. Bu kez boş sütunlar için de veri girmemiz gerekecek. Peki, boş sütunları oluşturmadan önce, tabloya eklediğimiz verilerin boş sütun kısımlarına nasıl veri ekleyebiliriz?

Yukarıda anlatılan işlemlerden sonra veri_görüntüle() fonksiyonunu çağırdığımızda aşağıdaki gibi bir çıktı elde ediyoruz:

('2017-06-22 23:33:19', 'ali', 'güler', None, None)
('2017-06-22 23:34:19', 'veli', 'doğan', 'İstanbul', '05325332451')

Boş sütunların değerleri None olduğu için veri_güncelle() fonksiyonunu da kullanamıyoruz. Çünkü input() ile alacağımız bütün değerler string formatında olacaktır. Acaba bu sorunun bir çözümü var mıdır, ilgilenen arkadaşların önerilerini bekliyorum.

Sorun çözülmüştür. Sorunun çözümünde aşağıdaki yöntem izlenmiştir:
sütun_oluştur() fonksiyonumuza aşağıdaki kodu ekliyoruz:

self.__imleç.execute("UPDATE {0} SET {1}=0 WHERE {1} is NULL".format(self.__tablo, boş_sütun_ismi))

sütun_oluştur() fonksiyonun son hali aşağıdaki gibi oluyor:

    def sütun_oluştur(self):
        while True:
            try:
                boş_sütun_sayısı = int(input("Sütun Sayısı:"))
                for i in range(boş_sütun_sayısı):
                    while True:
                        boş_sütun_ismi = input("Sütun İsmi:")
                        if str(boş_sütun_ismi).isnumeric() or str(boş_sütun_ismi) == "":
                            print("Sütun ismi boş bırakılamaz ve sayı değeri alamaz.")
                        else:
                            self.__imleç.execute("ALTER TABLE {} ADD COLUMN {}".format(self.__tablo, boş_sütun_ismi))
                            self.__imleç.execute("UPDATE {0} SET {1}=0 WHERE {1} is NULL".format(self.__tablo, boş_sütun_ismi))
                            self.__bağlan.commit()
                            break
                break
            except ValueError:
                print("Sayı girmediniz.")

Yukarıda, sütunlar oluşur oluşmaz, daha önceden eklenmiş olan veri satırlarının, az önce oluşmuş olan boş sütunlarına NULL yerine ‘0’ veya başka bir değer eklemimizi sağlayan bir kod ekledik. Böylece veri_güncelle() fonksiyonunu çalıştırarak bu ‘0’ değerini istediğimiz değere dönüştürebiliriz artık.

öncelikle harcamış olduğunuz emek için teşekkürler.SQLite3 ile ilgili bir-iki sorum olacak:
1-SQLite3 ile oluşturulmuş bir veritabanından yine SQLite3 ile oluşturulmuş başka bir veri tabanına nasıl tablo taşıyabilirim?Yani bunun olanağı var mıdır?
2-Sadece deneme amaçlı oluşturduğum veri tabanında bir değişiklik yapmak istediğimde SQLCipher penceresinde şifre soruyor.Oysa ben şifreleme yapmadığım gibi şifrelemenin nasıl yapılacağını da bilmiyorum…Zaman ayırıp cevaplayabilirsiniz diye umut ediyorum.Şimdiden teşekkürler.

Merhaba,

Evet, bahsettiğiniz işlem yapılabilir. Öncelikle şu başlıktaki sqlite3 komutlarını da incelemenizi öneririm. Komutlar o başlıkta daha derli toplu bir şekilde yazılmış.

Bahsettiğiniz işlem nasıl yapılabilir, teorik olarak ondan bahsedeyim.

Mevcut veritabanı dosyasındaki bütün satır ve sütunlardaki veriler değişkenlere kaydedilir, daha sonra da bu değişkenler yeni veritabanına aktarılır.

SQLCipher nedir bilmiyorum. Veritabanı ile işlem yaparken, her zaman değil ama bazen lock isimli bir dosya daha oluşur. Bu dosyanın oluşma gerekçesi, veritabanı açıkken, bu veritabanı ile başka bir programda işlem yapmanız olabilir, başka bir neden de olabilir. Ama her zaman veritabanı dosyası kitlenmez. Şayet kitlenirse, bu lock dosyası silinebilir ve veritabanı işlemlerine kaldığınız yerden devam edebilirsiniz.

Siz SQLCipher adlı bir şifreleme eklentisi kullanıyorsunuz sanırım. Bu eklentiyi kullanmadan veritabanı işlemleri yapmaya çalışırsanız bir sorunla karşılaşmazsınız diye düşünüyorum. Eğer bu eklentiyi kullanmak istiyorsanız eklentinin belgelerinde öntanımlı şifre ile ilgili bir şeyler yazıyor olmalı.

İyi çalışmalar.

Sqlite3 ile az önce çalışmaya başladım daha önce veritabanı ile hiç işim olmamıştı.Sadece local olarak mı kullanılıyor?veritabanımı servera bağlayıp güncelleme yapamaz mıyım?Eğer olmuyorsa kullanım olarak benzer bir server tabanlı veritabanı öneriniz var mıdır?
Resim eklemek için encode edip ardından okuyacağımız zaman decode etmekten bahsedilmiş.Resimleri sqlite3 veritabanına atmak iyi bir fikir midir?
@dildeolupbiten @ismailarilik

Merhabalar,

Biraz araştırdım fakat sanırım böyle bir şey sunmuyor SQLite3. Yine de, siz kendiniz server ve client yazabilirsiniz. Server, clientden çalıştıracağı SQL komutları bekler, client istenen veriyi gönderince server da çalıştırır. Bu sayede, uzaktan kontrol etmiş olursunuz databaseyi.

Hayır, databasede resim saklamak iyi bir fikir değildir. Resimlerin konumlarını saklamanız daha mantıklıdır.