SQLite'de bir tablonun olup olmadığını nasıl kontrol ederim?


893

Nasıl yapabilirim, güvenilir bir şekildeBelirli bir kullanıcı tablosunun var olup olmadığını SQLite'de kontrol edebilirim?

Tablodaki bir "select *" hata döndürüp döndürmediğini kontrol etmek gibi güvenilir olmayan yollar sormuyorum (bu bile iyi bir fikir mi?).

Nedeni şudur:

Programımda, henüz yoksa bazı tabloları oluşturup doldurmam gerekiyor.

Varsa, bazı tabloları güncellemem gerekiyor.

Bunun yerine, söz konusu tabloların önceden oluşturulduğunu belirtmek için başka bir yol izlemeli miyim - örneğin, diskteki program başlatma / ayarlar dosyamda belirli bir bayrağı oluşturarak / koyarak / ayarlayarak?

Yoksa yaklaşımım mantıklı mı?


Bir seçimdeki tablo yoksa SQLite bir istisna atar. Daha fazla süslü çalışmaya gerek yok.
NoChance

34
@NoChance olacak, ama diğer birçok şey de olacak. Bu, gözlerin
kapalıyken

@randomsock, güzel bir örnek, ama biraz korkutucu, özellikle araba arabam olsaydı ...
NoChance

@ randomsock, sqlite konvansiyonunun ne olduğunu bilmiyorum, ama izin almaktan daha affetmek istemek daha pitonik. yani bir koşullu kullanmak yerine istisnayı yakalamak.
Eric

1
@Eric Şimdilik, soru Python'u içermiyor, ancak öyle olduğunu varsayarsak, hata geneldir sqlite3.OperationalError, bu nedenle oluşturduğunuzda "tablo TABLE_NAME zaten var" mesajının olduğundan emin olmak için hata mesajını ayrıştırmanız gerekir. bir tablo ve değilse, hatayı yeniden yükseltin ve hatanın ifadesinin değişmeyeceğine dair bir garanti olmadığını düşünüyorum.
Markus von Broady

Yanıtlar:


1021

SSS girişini kaçırdım.

Her neyse, ileride başvurmak için sorgunun tamamı şöyledir:

SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}';

{table_name}Kontrol edilecek tablonun adı nerede .

Başvuru için belgeler bölümü: Veritabanı Dosya Biçimi. 2.6. SQL Veritabanı Şemasının Depolanması

  • Bu, adı belirtilen tabloların bir listesini döndürür; yani, imlecin sayımı 0 (yok) veya 1 sayısı (var)

7
SQLite belgelerinden hangisi bu sistem tablolarını kapsar?
Pawel Veselov

29
@Pawel Veselov: "SQLite Veritabanları İçin Dosya Biçimi" başlıklı bölüm: sqlite.org/fileformat2.html
Bryan Oakley

14
Ancak bu TEMP tablolarında çalışmaz. TEMP tabloları "sqlite_temp_master" konumundadır.
PatchyFog

11
Bu bir boole döndürüyor mu? Tablo yoksa veya yoksa ne döndürür?
Dagrooms

8
@Dagrooms Bu, adı belirtilen tabloların bir listesini döndürür; yani, imlecin sayımı 0 (yok) veya 1 sayısı (var) olacaktır.
Rein S

555

SQLite sürüm 3.3+ kullanıyorsanız, aşağıdakilerle kolayca bir tablo oluşturabilirsiniz:

create table if not exists TableName (col1 typ1, ..., colN typN)

Aynı şekilde, yalnızca aşağıdakileri kullanarak bir tabloyu kaldırabilirsiniz:

drop table if exists TableName

3
create tableİfadenin eksik olduğuna dikkat edin (tablo sütunları belirtimi eksik).
Eric Platon

11
dizinler için de benzer bir yapı vardır: yoksa dizin oluştur TableName (col1) üzerinde TableName_col1
lowtech

26
Bu kabul edilen cevap olmamalı, fakat soru farklı bir şekilde ifade edilmiş olsaydı olurdu. OP düşmeden veya oluşturmadan önce bir tabloyu nasıl kontrol edeceğini sormadı. Muhtemelen var olmayan bir tabloyu sorgulamak zorunda kalırsanız ne olur? Şu anda karşılaştığım sorun bu ve kabul edilen cevap bu genel problem bildiriminde en iyi sonucu veriyor. Bu iyi ve hızlı bir alternatif.
Dagrooms

@Dagrooms, haklı olabilirsin. OP bunu
sormasa da

169

Bir varyasyon, SELECT NAME yerine SELECT COUNT (*) kullanmak, yani

SELECT count(*) FROM sqlite_master WHERE type='table' AND name='table_name';

Bu, tablo yoksa 0, varsa 1 döndürür. Sayısal bir sonucun işlenmesi daha hızlı / kolay olduğundan, bu muhtemelen programlamanız için yararlıdır. Aşağıda, SQLiteDatabase, Cursor, rawQuery parametrelerini kullanarak Android'de bunu nasıl yapacağınız gösterilmektedir.

boolean tableExists(SQLiteDatabase db, String tableName)
{
    if (tableName == null || db == null || !db.isOpen())
    {
        return false;
    }
    Cursor cursor = db.rawQuery("SELECT COUNT(*) FROM sqlite_master WHERE type = ? AND name = ?", new String[] {"table", tableName});
    if (!cursor.moveToFirst())
    {
        cursor.close();
        return false;
    }
    int count = cursor.getInt(0);
    cursor.close();
    return count > 0;
}

33
"SEÇ 1" in daha da hızlı olacağına inanıyorum.
PatchyFog

Cursor.getInt (0) neden veritabanındaki kayıt sayısına eşittir?
Semyon Danilov

1
TABLO'nun sqlite şemasında kaç kez göründüğünü sayıyoruz. 0 sayısı tablonun mevcut olmadığı anlamına gelir. 1 sayısı tablonun var olduğu anlamına gelir. Bunlar sayılan beklenen iki değerdir.
Stephen Quan

1
Sayının (from COUNT(*)) işlenmesi kolay olsa da, bir satırın varlığını geri döndürmek ya da döndürmemek daha da kolaydır; orada bir satır varsa, o zaman var, eğer hiçbir satır yoksa. (MoveToFirst'teki başarısızlığı zaten kontrol ediyorsunuz, bu yüzden iş o noktada yapılacaktı.)
dash-tom-bang

Yanlış döndürmeden önce lütfen imleci kapatmak için kodunuzu güncelleyin.
Dave Thomas

43

Deneyebilirsiniz:

SELECT name FROM sqlite_master WHERE name='table_name'

4
type = tablo tho
mafu

C # kullanıyorsanız, bu komutu a'da kullanmayın SQLiteReader reader = cmd.ExecuteReader();ve bir dt.Load(reader)(nerede dta DataTable) yapın. Tablo bulunamadı eğer bu Object reference is not an instance of an objectistisna verir .Load()bulundu. Bunun yerine, kullanmak SQLiteDataAdapter adapter = new SQLiteDataAdapter(cmd); ve yapmak adapter.Fill(ds), nereye dsbir olduğunu DataSet. Ardından olup olmadığını ds.Tables.Count > 0ve return ds.Tables[0];(veya else return null) görebilirsiniz. Sonra , eğer ve eğer DataTableolmak için kontrol edebilirsiniznulldt.Rows != nulldt.Rows.Count>0
vapcguy

34

kullanın:

PRAGMA table_info(your_table_name)

Ortaya çıkan tablo boşsa your_table_name, mevcut değildir.

Belgeler:

PRAGMA schema.table_info (tablo adı);

Bu pragma, adlandırılmış tablodaki her sütun için bir satır döndürür. Sonuç kümesindeki sütunlar, sütun adını, veri türünü, sütunun NULL olup olmadığını ve sütunun varsayılan değerini içerir. Sonuç kümesindeki "pk" sütunu, birincil anahtarın parçası olmayan sütunlar için sıfırdır ve birincil anahtarın bir parçası olan sütunlar için birincil anahtardaki sütunun dizinidir.

Table_info pragma adlı tablo da bir görünüm olabilir.

Örnek çıktı:

cid|name|type|notnull|dflt_value|pk
0|id|INTEGER|0||1
1|json|JSON|0||0
2|name|TEXT|0||0

Bu, Python'da bir tablonun olup olmadığını belirlemenin harika bir yoludur.
Michael Murphy

veya Xamarin Formları
SerenityNow

4
Bu, programlama yoluyla sütun tanımlarına ulaşmak için harika bir yoldur
w00t

33

SQLite tablo adları büyük / küçük harfe duyarlı değildir, ancak karşılaştırma varsayılan olarak büyük / küçük harfe duyarlıdır. Bunu her durumda düzgün çalışması için eklemeniz gerekir COLLATE NOCASE.

SELECT name FROM sqlite_master WHERE type='table' AND name='table_name' COLLATE NOCASE

33

"Tablo zaten var" hatası alıyorsanız, SQL dizesinde aşağıdaki gibi değişiklikler yapın:

CREATE table IF NOT EXISTS table_name (para1,para2);

Bu şekilde istisnaları önleyebilirsiniz.



23

Fmdb kullanıyorsanız , sadece FMDatabaseAdditions'ı içe aktarabilir ve bool işlevini kullanabilirsiniz:

[yourfmdbDatabase tableExists:tableName].

1
Bu yöntemi kullanmak için "FMDatabaseAdditions.h" dosyasını içe aktardığınızdan emin olun, aksi takdirde neden kaldırdıklarını merak edersiniz! :)
Will

Bu doğru bir cevap olsa da, soru belirli bir dilde belirli bir kütüphane değil sqlite ile ilgilidir. Ben cevap sql kodu sağlamak için olmalı, kütüphane yöntemlerinden birine bir çağrı değil
nacho4d

13

Aşağıdaki kod, tablo varsa 1 değerini veya tablo yoksa 0 değerini döndürür.

SELECT CASE WHEN tbl_name = "name" THEN 1 ELSE 0 END FROM sqlite_master WHERE tbl_name = "name" AND type = "table"

1
Tablo yoksa, yine de hiçbir şey döndürmez, çünkü where koşulu herhangi bir sonucu engeller.
David Gausmann

10

TEMP veritabanında bir tablonun olup olmadığını kontrol etmek için aşağıdakiler sqlite_temp_masteryerine kullanmanız gerektiğini unutmayın sqlite_master:

SELECT name FROM sqlite_temp_master WHERE type='table' AND name='table_name';

9

İşte kullandığım fonksiyon:

Bir SQLDatabase Nesnesi = db verildi

public boolean exists(String table) {
    try {
         db.query("SELECT * FROM " + table);
         return true;
    } catch (SQLException e) {
         return false;
    }
}

1
Samsung cihazlarının, herkesin birlikte çalıştığı standart sqlite_master tablo yapısını kullanmadığını bulduğum için bunu Android uygulamamda kullanmak zorunda kaldım.
Anthony Chuinard

7

Bu kodu kullanın:

SELECT name FROM sqlite_master WHERE type='table' AND name='yourTableName';

Döndürülen dizi sayısı 1'e eşitse, tablonun var olduğu anlamına gelir. Aksi takdirde mevcut değildir.


4
class CPhoenixDatabase():
    def __init__(self, dbname):
        self.dbname = dbname
        self.conn = sqlite3.connect(dbname)

    def is_table(self, table_name):
        """ This method seems to be working now"""
        query = "SELECT name from sqlite_master WHERE type='table' AND name='{" + table_name + "}';"
        cursor = self.conn.execute(query)
        result = cursor.fetchone()
        if result == None:
            return False
        else:
            return True

Not: Bu artık Mac'imde Python 3.7.1 ile çalışıyor


Bu diğer tüm cevaplardan daha temiz görünüyor .. Teşekkürler !!
Harsha Vardhan

Benim için çalışmıyor: table_name çevresindeki {} parantezlerini, ardından para cezasını silmek zorunda.
Muz

1
table_nameGüvenilmeyen kaynaktan (kullanıcı girişi gibi) sağlanmadığından emin olun , aksi takdirde SQL enjeksiyonuna karşı savunmasız olacaktır. Metin manipülasyon teknikleri yerine parametreleri kullanmak her zaman daha iyidir
astef

3

kullanım

SELECT 1 FROM table LIMIT 1;

tüm kayıtların okunmasını önlemek için.


Tablonun mevcut olması ancak kaydın olmaması durumunda NULL döndürür.
radiospiel

Tablo yoksa, bir hata verir. Yakalayın ve var olmadığını biliyorsunuz.
luckydonald

hata kontrolünü akış kontrolü olarak kullanmak genellikle en iyi uygulama olarak değerlendirilmez. Bundan muhtemelen kaçınılmalıdır.
Jeff Woodard

3

Tablo varlığını kontrol etmek için aşağıdaki sorguyu yazabilirsiniz.

SELECT name FROM sqlite_master WHERE name='table_name'

Burada 'table_name' sizin oluşturduğunuz tablo adınızdır. Örneğin

 CREATE TABLE IF NOT EXISTS country(country_id INTEGER PRIMARY KEY AUTOINCREMENT, country_code TEXT, country_name TEXT)"

ve kontrol et

  SELECT name FROM sqlite_master WHERE name='country'

6
Bu, daha önce kabul edilmiş ve 9 yıl önceki cevaptan nasıl farklı?
Kevin Van Dyck

3

SQLite 3 kullanan en son sqlite-net-pcl nuget paketini (1.5.231) kullanarak şu anda C #'da bulduğum en güvenilir yol şöyledir:

var result = database.GetTableInfo(tableName);
if ((result == null) || (result.Count == 0))
{
    database.CreateTable<T>(CreateFlags.AllImplicit);
}

2

Basit bir SELECT sorgusu kullanmak - bence - oldukça güvenilir. En önemlisi birçok farklı veritabanı türünde (SQLite / MySQL) tablo varlığını kontrol edebilir.

SELECT 1 FROM table;

Sorgunun başarılı olup olmadığını belirlemek için diğer güvenilir mekanizmaları kullanabileceğiniz zaman mantıklıdır (örneğin, Qt içinde QSqlQuery aracılığıyla bir veritabanını sorgulayın ).


1

c ++ işlevi, tablo ve (isteğe bağlı) sütun varlığı için db ve tüm bağlı veritabanlarını denetler.

bool exists(sqlite3 *db, string tbl, string col="1")
{
    sqlite3_stmt *stmt;
    bool b = sqlite3_prepare_v2(db, ("select "+col+" from "+tbl).c_str(),
    -1, &stmt, 0) == SQLITE_OK;
    sqlite3_finalize(stmt);
    return b;
}

Düzenleme: Son zamanlarda sqlite3_table_column_metadata işlevini keşfetti. bundan dolayı

bool exists(sqlite3* db,const char *tbl,const char *col=0)
{return sqlite3_table_column_metadata(db,0,tbl,col,0,0,0,0,0)==SQLITE_OK;}

public static boolean tableExists (SQLiteDatabase veritabanı, String tableName) {return database.rawQuery ("sqlite_master'dan isim seçin WHERE type = 'table' AND name = '" + tableName + "'", null) .moveToFirst (); }
nick

Dize birleştirme gibi çok verimsiz ve riskli bir yol her şeye yol açabilir.
Andrea Moro

0

Bu benim SQLite Cordova için benim kod:

get_columnNames('LastUpdate', function (data) {
    if (data.length > 0) { // In data you also have columnNames
        console.log("Table full");
    }
    else {
        console.log("Table empty");
    }
});

Ve diğeri:

function get_columnNames(tableName, callback) {
    myDb.transaction(function (transaction) {
        var query_exec = "SELECT name, sql FROM sqlite_master WHERE type='table' AND name ='" + tableName + "'";
        transaction.executeSql(query_exec, [], function (tx, results) {
            var columnNames = [];
            var len = results.rows.length;
            if (len>0){
                var columnParts = results.rows.item(0).sql.replace(/^[^\(]+\(([^\)]+)\)/g, '$1').split(','); ///// RegEx
                for (i in columnParts) {
                    if (typeof columnParts[i] === 'string')
                        columnNames.push(columnParts[i].split(" ")[0]);
                };
                callback(columnNames);
            }
            else callback(columnNames);
        });
    });
}

0

Oldukça eski olsa bile, ben bu tartışmaya benim 2 sent koymak düşündüm .. Tablo varsa, bu sorgu skaler 1 ve aksi takdirde 0 döndürür.

select 
    case when exists 
        (select 1 from sqlite_master WHERE type='table' and name = 'your_table') 
        then 1 
        else 0 
    end as TableExists

0

Tablo hızlı bir şekilde veritabanında var veya yok

func tableExists(_ tableName:String) -> Bool {
        sqlStatement = "SELECT name FROM sqlite_master WHERE type='table' AND name='\(tableName)'"
        if sqlite3_prepare_v2(database, sqlStatement,-1, &compiledStatement, nil) == SQLITE_OK {
            if sqlite3_step(compiledStatement) == SQLITE_ROW {
                return true
            }
            else {
                return false
            }
        }
        else {
            return false
        }
            sqlite3_finalize(compiledStatement)
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.