ฉันจะตรวจสอบ SQLite ว่ามีตารางอยู่ได้อย่างไร?


893

ฉันจะตรวจสอบใน SQLite อย่างเชื่อถือได้อย่างไรว่ามีตารางผู้ใช้อยู่หรือไม่

ฉันไม่ได้ขอวิธีที่ไม่น่าเชื่อถือเช่นตรวจสอบว่า "select *" บนตารางส่งคืนข้อผิดพลาดหรือไม่ (นี่เป็นความคิดที่ดีใช่หรือไม่)

เหตุผลเป็นเช่นนี้

ในโปรแกรมของฉันฉันต้องสร้างและเติมตารางบางอย่างถ้าไม่มีอยู่แล้ว

หากมีอยู่แล้วฉันต้องอัปเดตบางตาราง

ฉันควรใช้เส้นทางอื่นแทนสัญญาณว่าตารางที่มีปัญหาได้ถูกสร้างขึ้นแล้ว - ตัวอย่างเช่นโดยการสร้าง / วาง / การตั้งค่าสถานะที่แน่นอนในไฟล์การเริ่มต้นโปรแกรม / การตั้งค่าโปรแกรมของฉันบนดิสก์หรืออะไร?

หรือแนวทางของฉันเข้าท่าไหม?


SQLite จะส่งข้อยกเว้นถ้าตารางในตัวเลือกไม่มีอยู่ ไม่จำเป็นต้องมีงานแฟนซีอีกต่อไป
NoChance

34
@ ไม่มีโอกาสมันจะทำ แต่จะมีสิ่งอื่นใดอีกบ้าง มันเหมือนกับการเห็นว่าต้นไม้นั้นอยู่ที่นั่นจริงหรือไม่โดยการขับรถไปข้างหน้าโดยที่คุณหลับตาคุณจะพบทางเดียวหรืออย่างอื่น :)
randomsock

@ Randomsock เป็นตัวอย่างที่ดี แต่น่ากลัวนิดหน่อยโดยเฉพาะอย่างยิ่งถ้ารถเป็นรถของฉัน ...
NoChance

@ Randomsock ฉันไม่ทราบว่าสิ่งที่ประชุม sqlite แต่มันยิ่งใหญ่กว่าที่จะขอการอภัยมากกว่าการอนุญาต นั่นคือจับข้อยกเว้นแทนที่จะใช้เงื่อนไข
Eric

1
@Eric ณ ตอนนี้คำถามไม่เกี่ยวข้องกับ Python แต่ถ้าเป็นเช่นนั้นข้อผิดพลาดเป็นแบบทั่วไปsqlite3.OperationalErrorดังนั้นคุณต้องแยกวิเคราะห์ข้อความแสดงข้อผิดพลาดเพื่อให้แน่ใจว่าเป็นเช่น "table TABLE_NAME มีอยู่แล้ว" เมื่อคุณสร้าง ตารางและหากไม่เป็นเช่นนั้นให้อ่านข้อผิดพลาดซ้ำอีกครั้งและฉันคิดว่าไม่มีการรับประกันว่าการใช้ถ้อยคำของข้อผิดพลาดจะไม่เปลี่ยนแปลง
Markus von Broady

คำตอบ:


1021

ฉันพลาดคำถามที่พบบ่อย

อย่างไรก็ตามสำหรับการอ้างอิงในอนาคตแบบสอบถามที่สมบูรณ์คือ:

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

ในกรณีที่{table_name}เป็นชื่อของตารางในการตรวจสอบ

ส่วนเอกสารสำหรับการอ้างอิง: รูปแบบไฟล์ฐานข้อมูล 2.6 ที่เก็บข้อมูลของสคีมาฐานข้อมูล SQL

  • นี่จะส่งคืนรายการตารางที่มีชื่อที่ระบุ นั่นคือเคอร์เซอร์จะมีจำนวน 0 (ไม่มีอยู่) หรือนับเป็น 1 (ไม่มีอยู่)

7
เอกสาร SQLite ใดครอบคลุมตารางระบบเหล่านี้
Pawel Veselov

29
@Pawel Veselov: ส่วนที่ชื่อ "รูปแบบไฟล์สำหรับฐานข้อมูล SQLite": sqlite.org/fileformat2.html
Bryan Oakley

14
อย่างไรก็ตามวิธีนี้ใช้ไม่ได้กับตาราง TEMP ตาราง TEMP อยู่ใน "sqlite_temp_master"
PatchyFog

11
สิ่งนี้ส่งคืนบูลีนหรือไม่? มันจะเกิดอะไรขึ้นถ้าตารางไม่มีหรือไม่มี?
Dagrooms

8
@Dagrooms นี่จะส่งคืนรายการตารางที่มีชื่อที่ระบุ นั่นคือเคอร์เซอร์จะมีจำนวน 0 (ไม่มีอยู่) หรือนับเป็น 1 (ไม่มีอยู่)
Rein S

555

หากคุณใช้ SQLite เวอร์ชั่น 3.3+ คุณสามารถสร้างตารางได้อย่างง่ายดายด้วย:

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

ในทำนองเดียวกันคุณสามารถลบตารางได้หากมีอยู่โดยใช้:

drop table if exists TableName

3
โปรดทราบว่าcreate tableคำสั่งไม่สมบูรณ์ (ไม่มีข้อมูลจำเพาะคอลัมน์คอลัมน์)
Eric Platon

11
นอกจากนี้ยังมีโครงสร้างที่คล้ายกันสำหรับดัชนี: สร้างดัชนีหากไม่มี TableName_col1 บน TableName (col1)
lowtech

26
นี่ไม่ควรเป็นคำตอบที่ยอมรับได้ แต่หากคำถามนั้นถูกใช้คำแตกต่างกัน OP ไม่ได้ถามวิธีตรวจสอบตารางก่อนที่จะดรอปหรือสร้าง ถ้าคุณต้องค้นหาตารางที่อาจไม่มีอยู่ นี่คือปัญหาที่ฉันเผชิญอยู่ในตอนนี้และคำตอบที่ยอมรับได้ดีที่สุดในคำแถลงปัญหาทั่วไปนี้ นี่เป็นทางเลือกที่ดีอย่างรวดเร็ว
Dagrooms

@Dagrooms คุณอาจพูดถูก แม้ว่า OP ไม่ได้ถามเรื่องนี้ผมกำลังมองหาคำตอบนี้ :)
earik87

169

รูปแบบจะใช้ SELECT COUNT (*) แทน SELECT NAME เช่น

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

สิ่งนี้จะส่งกลับค่า 0 หากตารางไม่มีอยู่ 1 ถ้าเป็นไปได้ นี่อาจเป็นประโยชน์ในการเขียนโปรแกรมของคุณเนื่องจากผลลัพธ์ที่เป็นตัวเลขนั้นเร็วกว่า / ง่ายกว่าในการประมวลผล ต่อไปนี้แสดงวิธีที่คุณจะทำสิ่งนี้ใน Android โดยใช้ SQLiteDatabase, Cursor, rawQuery พร้อมพารามิเตอร์

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
ฉันเชื่อว่า "SELECT 1" จะเร็วขึ้นกว่านี้
PatchyFog

ทำไม cursor.getInt (0) จึงเท่ากับจำนวนระเบียนในฐานข้อมูล
Semyon Danilov

1
เรากำลังนับจำนวนครั้งที่ตารางปรากฏใน sqlite schema จำนวน 0 หมายถึงไม่มีตารางอยู่ การนับ 1 หมายถึงตารางมีอยู่ นี่เป็นค่าที่คาดหวังเพียงสองค่าเท่านั้น
Stephen Quan

1
ในขณะที่จำนวน (จากCOUNT(*)) นั้นง่ายต่อการดำเนินการมันง่ายยิ่งกว่าที่จะคืนค่าการมีอยู่ของแถวหรือไม่ หากมีแถวก็มีอยู่ถ้าไม่มีแถวก็ไม่ได้ (คุณแล้วตรวจสอบความล้มเหลวใน moveToFirst ดังนั้นการทำงานจะทำที่จุดที่.)
รีบทอมปัง

โปรดอัปเดตรหัสของคุณเพื่อปิดเคอร์เซอร์ก่อนที่คุณจะคืนค่าเท็จ
Dave Thomas

43

คุณสามารถลอง:

SELECT name FROM sqlite_master WHERE name='table_name'

4
type = table น่าจะมีประโยชน์ tho
mafu

หากใช้ C # ห้ามใช้คำสั่งนี้ใน a SQLiteReader reader = cmd.ExecuteReader();และ a dt.Load(reader)(โดยที่dta DataTable) ฉันพบว่ามันให้Object reference is not an instance of an objectข้อยกเว้นนี้กับ.Load()หากไม่พบตาราง แต่ให้ใช้SQLiteDataAdapter adapter = new SQLiteDataAdapter(cmd); และทำadapter.Fill(ds)ที่เป็นds DataSetจากนั้นคุณสามารถดูว่าds.Tables.Count > 0และreturn ds.Tables[0];ถ้าเป็นเช่นนั้น (หรือelse return null) จากนั้นคุณสามารถตรวจสอบว่าDataTableเป็นnullถ้าdt.Rows != nullและถ้าdt.Rows.Count>0
vapcguy

34

ใช้:

PRAGMA table_info(your_table_name)

หากตารางผลลัพธ์ว่างเปล่าแสดงว่าyour_table_nameไม่มีอยู่

เอกสารอ้างอิง:

PRAGMA schema.table_info (ชื่อตาราง);

pragma นี้ส่งคืนหนึ่งแถวสำหรับแต่ละคอลัมน์ในตารางที่มีชื่อ คอลัมน์ในชุดผลลัพธ์ประกอบด้วยชื่อคอลัมน์ชนิดข้อมูลไม่ว่าคอลัมน์นั้นจะเป็น NULL หรือไม่และค่าเริ่มต้นสำหรับคอลัมน์นั้น คอลัมน์ "pk" ในชุดผลลัพธ์เป็นศูนย์สำหรับคอลัมน์ที่ไม่ได้เป็นส่วนหนึ่งของคีย์หลักและเป็นดัชนีของคอลัมน์ในคีย์หลักสำหรับคอลัมน์ที่เป็นส่วนหนึ่งของคีย์หลัก

ตารางที่มีชื่อใน pragma table_info สามารถเป็นมุมมองได้

ตัวอย่างผลลัพธ์:

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

นี่เป็นวิธีที่ดีในการพิจารณาว่ามีตารางอยู่ใน Python หรือไม่
Michael Murphy

หรือแบบฟอร์ม Xamarin
SerenityNow

4
นี่เป็นวิธีที่ยอดเยี่ยมในการหาคำจำกัดความของคอลัมน์โดยทางโปรแกรม
w00t

33

ชื่อตาราง SQLite ไม่คำนึงถึงขนาดตัวพิมพ์ แต่การเปรียบเทียบจะคำนึงถึงขนาดตัวพิมพ์ COLLATE NOCASEเพื่อให้งานนี้อย่างถูกต้องในทุกกรณีคุณจะต้องเพิ่ม

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

33

หากคุณได้รับข้อผิดพลาด "ตารางมีอยู่แล้ว" ให้ทำการเปลี่ยนแปลงในสตริง SQL ดังต่อไปนี้:

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

วิธีนี้คุณสามารถหลีกเลี่ยงข้อยกเว้น



23

หากคุณใช้fmdbฉันคิดว่าคุณสามารถนำเข้า FMDatabaseAdditionsและใช้ฟังก์ชัน bool:

[yourfmdbDatabase tableExists:tableName].

1
อย่าลืมนำเข้า "FMDatabaseAdditions.h" เพื่อใช้วิธีการนี้มิฉะนั้นคุณจะสงสัยว่าทำไมพวกเขาถึงเอาออก! :)
Will

แม้ว่านี่อาจเป็นคำตอบที่ถูกต้อง แต่คำถามก็คือ sqlite ไม่ใช่ห้องสมุดเฉพาะในภาษาใดภาษาหนึ่ง ผมคิดว่าคำตอบควรจะให้รหัส SQL, ไม่ได้เรียกร้องให้วิธีใดวิธีหนึ่งของห้องสมุด
nacho4d

13

รหัสต่อไปนี้จะคืนค่า 1 หากมีตารางอยู่หรือ 0 ถ้าไม่มีตารางอยู่

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

1
สิ่งนี้จะยังคงส่งคืนอะไรเลยถ้าไม่มีตารางอยู่เนื่องจากเงื่อนไขที่ป้องกันผลลัพธ์ใด ๆ
David Gausmann

10

โปรดทราบว่าในการตรวจสอบว่ามีตารางอยู่ในฐานข้อมูล TEMP หรือไม่คุณต้องใช้sqlite_temp_masterแทนsqlite_master:

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

9

นี่คือฟังก์ชั่นที่ฉันใช้:

ได้รับ SQLDatabase Object = db

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

1
ฉันเศร้าที่ต้องใช้สิ่งนี้ในแอพ Android ของฉันเพราะฉันพบว่าอุปกรณ์ Samsung ไม่ได้ใช้โครงสร้างตาราง sqlite_master มาตรฐานที่ทุกคนใช้งานได้
Anthony Chuinard

7

ใช้รหัสนี้:

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

หากจำนวนอาร์เรย์ที่ส่งคืนมีค่าเท่ากับ 1 หมายความว่ามีตาราง มิฉะนั้นจะไม่มีอยู่


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

หมายเหตุ: ตอนนี้ใช้งานได้บน Mac ของฉันด้วย Python 3.7.1


มันดูสะอาดกว่าคำตอบอื่น ๆ ทั้งหมด .. ขอบคุณ !!
Harsha Vardhan

ใช้งานไม่ได้สำหรับฉัน: ต้องลบเครื่องหมายวงเล็บ {} รอบ ๆ table_name ก่อนแล้วจึงใช้ได้
Banana

1
ตรวจสอบให้แน่ใจtable_nameว่าไม่ได้จัดหาจากแหล่งที่ไม่ได้ใช้ซ้ำ (เช่นอินพุตของผู้ใช้) มิฉะนั้นจะทำให้เกิดความเสี่ยงต่อการฉีด SQL เป็นการดีกว่าเสมอที่จะใช้พารามิเตอร์แทนเทคนิคการจัดการข้อความ
astef

3

ใช้

SELECT 1 FROM table LIMIT 1;

เพื่อป้องกันไม่ให้บันทึกทั้งหมดถูกอ่าน


ส่งกลับค่า NULL ถ้าตารางนั้นมีอยู่ แต่ไม่มีระเบียนใด ๆ
radiospiel

หากตารางไม่มีอยู่ก็จะโยนข้อผิดพลาด จับสิ่งนั้นและคุณรู้ว่ามันไม่มีอยู่จริง
luckydonald

การใช้การจัดการข้อผิดพลาดเนื่องจากการควบคุมการไหลโดยทั่วไปไม่ถือว่าเป็นแนวปฏิบัติที่ดีที่สุด สิ่งนี้ควรหลีกเลี่ยง
Jeff Woodard

3

คุณสามารถเขียนแบบสอบถามต่อไปนี้เพื่อตรวจสอบตารางที่มีอยู่

SELECT name FROM sqlite_master WHERE name='table_name'

นี่คือ 'table_name' เป็นชื่อตารางของคุณสิ่งที่คุณสร้างขึ้น ตัวอย่างเช่น

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

และตรวจสอบ

  SELECT name FROM sqlite_master WHERE name='country'

6
สิ่งนี้แตกต่างจากคำตอบที่ติดอันดับยอดนิยมที่ตอบรับแล้วเมื่อ 9 ปีที่แล้วหรือไม่
Kevin Van Dyck

3

วิธีที่น่าเชื่อถือที่สุดที่ฉันพบใน C # ตอนนี้ใช้แพ็คเกจ nuget sqlite-net-pcl ล่าสุด (1.5.231) ซึ่งใช้ SQLite 3 เป็นดังนี้:

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

2

การใช้คำค้นหา SELECT แบบง่ายคือในความคิดของฉัน - ค่อนข้างน่าเชื่อถือ ส่วนใหญ่สามารถตรวจสอบตารางที่มีอยู่ในฐานข้อมูลหลายประเภท (SQLite / MySQL)

SELECT 1 FROM table;

เหมาะสมเมื่อคุณสามารถใช้กลไกที่เชื่อถือได้อื่น ๆ เพื่อพิจารณาว่าแบบสอบถามประสบความสำเร็จหรือไม่ (ตัวอย่างเช่นคุณสืบค้นฐานข้อมูลผ่าน QSqlQuery ในQt )


1

ฟังก์ชั่น c ++ ตรวจสอบ db และฐานข้อมูลที่แนบทั้งหมดสำหรับการอยู่ของตารางและ (ทางเลือก) คอลัมน์

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;
}

แก้ไข: ค้นพบเมื่อเร็ว ๆ นี้ฟังก์ชัน sqlite3_table_column_metadata ด้วยเหตุนี้

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;}

บูลีนสแตติกสาธารณะแบบคงที่ tableExists (ฐานข้อมูล SQLiteDatabase, tableName สตริง) {return database.rawQuery ("ชื่อที่เลือกจาก sqlite_master WHERE type = 'table' AND name = '" + tableName + "'", null) .moveToFirst (); }
กรงขัง

วิธีที่ไม่มีประสิทธิภาพและเสี่ยงมากเนื่องจากการต่อสตริงอาจจบลงด้วยทุกสิ่ง
Andrea Moro

0

นี่คือรหัสของฉันสำหรับ SQLite Cordova:

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

และอีกหนึ่ง:

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

ฉันคิดว่าฉันใส่ 2 เซ็นต์ของฉันในการสนทนานี้แม้ว่าจะค่อนข้างเก่า .. แบบสอบถามนี้ส่งคืนเซนต์คิตส์และเนวิส 1 ถ้าตารางมีอยู่และ 0 เป็นอย่างอื่น

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

0

ตารางมีอยู่หรือไม่อยู่ในฐานข้อมูลอย่างรวดเร็ว

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)
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.