แก้ไขตารางเพิ่มคอลัมน์หากไม่มีอยู่ใน SQLite


92

เมื่อเร็ว ๆ นี้เราจำเป็นต้องเพิ่มคอลัมน์ลงในตารางฐานข้อมูล SQLite ที่มีอยู่ของเรา ซึ่งสามารถทำได้ด้วยALTER TABLE ADD COLUMN. แน่นอนว่าหากตารางได้รับการเปลี่ยนแปลงแล้วเราต้องการที่จะปล่อยให้มันอยู่คนเดียว ขออภัย SQLite ไม่สนับสนุนIF NOT EXISTSอนุประโยคบนALTER TABLEข้อบน

วิธีแก้ปัญหาปัจจุบันของเราคือดำเนินการคำสั่ง ALTER TABLE และละเว้นข้อผิดพลาด "ชื่อคอลัมน์ที่ซ้ำกัน" เช่นเดียวกับตัวอย่าง Python นี้ (แต่ใน C ++)

อย่างไรก็ตามแนวทางปกติของเราในการตั้งค่าสกีมาฐานข้อมูลคือการมีสคริปต์. sql ที่มีCREATE TABLE IF NOT EXISTSและCREATE INDEX IF NOT EXISTSคำสั่งซึ่งสามารถดำเนินการได้โดยใช้sqlite3_execหรือsqlite3เครื่องมือบรรทัดคำสั่ง เราไม่สามารถใส่ALTER TABLEไฟล์สคริปต์เหล่านี้ได้เนื่องจากหากคำสั่งนั้นล้มเหลวจะไม่มีการดำเนินการใด ๆ หลังจากนั้น

ฉันต้องการกำหนดตารางในที่เดียวและไม่แยกระหว่างไฟล์. sql และ. cpp มีวิธีการเขียนวิธีแก้ปัญหาALTER TABLE ADD COLUMN IF NOT EXISTSใน SQLite SQL แท้หรือไม่?

คำตอบ:


65

ฉันมีวิธี SQL บริสุทธิ์ 99% แนวคิดคือการกำหนดเวอร์ชันสคีมาของคุณ คุณสามารถทำได้สองวิธี:

  • ใช้คำสั่ง 'user_version' pragma ( PRAGMA user_version) เพื่อจัดเก็บหมายเลขที่เพิ่มขึ้นสำหรับเวอร์ชันสกีมาฐานข้อมูลของคุณ

  • จัดเก็บหมายเลขเวอร์ชันของคุณในตารางที่คุณกำหนดเอง

ด้วยวิธีนี้เมื่อซอฟต์แวร์เริ่มทำงานซอฟต์แวร์สามารถตรวจสอบสคีมาฐานข้อมูลและเรียกใช้การALTER TABLEสืบค้นของคุณจากนั้นเพิ่มเวอร์ชันที่จัดเก็บหากจำเป็น ซึ่งดีกว่าการพยายามอัปเดตต่างๆแบบ "ตาบอด" โดยเฉพาะอย่างยิ่งหากฐานข้อมูลของคุณเติบโตขึ้นและมีการเปลี่ยนแปลงสองสามครั้งในช่วงหลายปีที่ผ่านมา


7
ค่าเริ่มต้นuser_versionคืออะไร? ฉันถือว่าเป็นศูนย์ แต่คงจะดีหากได้เห็นเอกสารนั้น
Craig McQueen

ถึงแม้จะมีสิ่งนี้ก็สามารถทำได้ใน SQL บริสุทธิ์เนื่องจาก sqlite ไม่รองรับIFและALTER TABLEไม่มีเงื่อนไข? "SQL บริสุทธิ์ 99%" หมายความว่าอย่างไร
Craig McQueen

1
@CraigMcQueen สำหรับค่าเริ่มต้นuser_versionดูเหมือนจะเป็น 0 แต่เป็นค่าที่ผู้ใช้กำหนดเองดังนั้นคุณสามารถสร้างค่าเริ่มต้นของคุณเองได้
MPelletier

7
คำถามเกี่ยวกับuser_versionค่าเริ่มต้นมีความเกี่ยวข้องเมื่อคุณมีฐานข้อมูลที่มีอยู่และคุณไม่เคยใช้มาuser_versionก่อน แต่คุณต้องการเริ่มใช้งานดังนั้นคุณต้องถือว่า sqlite ตั้งค่าเป็นค่าเริ่มต้นเฉพาะ
Craig McQueen

1
@CraigMcQueen ฉันเห็นด้วย แต่ดูเหมือนจะไม่มีเอกสาร
MPelletier

31

วิธีแก้ปัญหาอย่างหนึ่งคือสร้างคอลัมน์และตรวจจับข้อยกเว้น / ข้อผิดพลาดที่เกิดขึ้นหากมีคอลัมน์อยู่แล้ว เมื่อเพิ่มหลายคอลัมน์ให้เพิ่มในคำสั่ง ALTER TABLE แยกกันเพื่อให้รายการที่ซ้ำกันไม่ได้ป้องกันไม่ให้สร้างคอลัมน์อื่น

ด้วยsqlite-netเราทำแบบนี้ ไม่สมบูรณ์แบบเนื่องจากเราไม่สามารถแยกแยะข้อผิดพลาด sqlite ที่ซ้ำกันจากข้อผิดพลาด sqlite อื่น ๆ ได้

Dictionary<string, string> columnNameToAddColumnSql = new Dictionary<string, string>
{
    {
        "Column1",
        "ALTER TABLE MyTable ADD COLUMN Column1 INTEGER"
    },
    {
        "Column2",
        "ALTER TABLE MyTable ADD COLUMN Column2 TEXT"
    }
};

foreach (var pair in columnNameToAddColumnSql)
{
    string columnName = pair.Key;
    string sql = pair.Value;

    try
    {
        this.DB.ExecuteNonQuery(sql);
    }
    catch (System.Data.SQLite.SQLiteException e)
    {
        _log.Warn(e, string.Format("Failed to create column [{0}]. Most likely it already exists, which is fine.", columnName));
    }
}

27

SQLite ยังสนับสนุนคำสั่ง pragma ที่เรียกว่า "table_info" ซึ่งส่งคืนหนึ่งแถวต่อคอลัมน์ในตารางที่มีชื่อของคอลัมน์ (และข้อมูลอื่น ๆ เกี่ยวกับคอลัมน์) คุณสามารถใช้สิ่งนี้ในแบบสอบถามเพื่อตรวจสอบคอลัมน์ที่หายไปและหากไม่มีให้แก้ไขตาราง

PRAGMA table_info(foo_table_name)

http://www.sqlite.org/pragma.html#pragma_table_info


32
คำตอบของคุณจะยอดเยี่ยมกว่านั้นหากคุณระบุรหัสเพื่อใช้ในการค้นหานั้นให้เสร็จสมบูรณ์แทนที่จะเป็นเพียงลิงก์
Michael Alan Huff

PRAGMA table_info (ชื่อตาราง) คำสั่งนี้จะแสดงแต่ละคอลัมน์ของ table_name เป็นแถวในผลลัพธ์ จากผลลัพธ์นี้คุณสามารถระบุได้ว่ามีคอลัมน์หรือไม่
Hao Nguyen

2
มีวิธีใดบ้างที่จะทำได้โดยการรวม pragma ไว้ในส่วนหนึ่งของคำสั่ง SQL ที่มีขนาดใหญ่ขึ้นเพื่อที่จะเพิ่มคอลัมน์หากไม่มีอยู่ แต่ไม่ได้อยู่ในแบบสอบถามเดียวหรือไม่?
Michael

1
@ ไมเคิล. เท่าที่ฉันรู้ไม่มีคุณทำไม่ได้ ปัญหาเกี่ยวกับคำสั่ง PRAGMA คือคุณไม่สามารถสอบถามได้ คำสั่งไม่นำเสนอข้อมูลไปยัง
เอ็นจิ้น

1
สิ่งนี้ไม่ได้สร้างเงื่อนไขการแข่งขันหรือไม่? สมมติว่าฉันตรวจสอบชื่อคอลัมน์ดูว่าคอลัมน์ของฉันหายไป แต่ในระหว่างนี้กระบวนการอื่นจะเพิ่มคอลัมน์เข้าไป จากนั้นฉันจะพยายามเพิ่มคอลัมน์ แต่จะได้รับข้อผิดพลาดเนื่องจากมีอยู่แล้ว ฉันเดาว่าฉันควรจะล็อคฐานข้อมูลก่อนหรืออะไร? ฉันเป็น noob ที่จะ sqlite ฉันกลัว :)
Ben Farmer

26

หากคุณกำลังทำสิ่งนี้ในคำสั่งการอัพเกรด DB วิธีที่ง่ายที่สุดคือเพียงแค่จับข้อยกเว้นที่ถูกโยนทิ้งหากคุณพยายามเพิ่มฟิลด์ที่อาจมีอยู่แล้ว

try {
   db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN foo TEXT default null");
} catch (SQLiteException ex) {
   Log.w(TAG, "Altering " + TABLE_NAME + ": " + ex.getMessage());
}

3
ฉันไม่ชอบการเขียนโปรแกรมที่มีลักษณะพิเศษ แต่มันสะอาดมากอย่างน่าอัศจรรย์ บางทีคุณอาจจะแกว่งฉันเล็กน้อย
Stephen J

ฉันไม่ชอบเหมือนกัน แต่ C ++ เป็นภาษาโปรแกรมสไตล์ที่มีข้อยกเว้นมากที่สุดเท่าที่เคยมีมา ดังนั้นฉันเดาว่าอาจมีคนเห็นว่า "ถูกต้อง"
tmighty

กรณีการใช้งานของฉันสำหรับ SQLite = ฉันไม่ต้องการทำการเข้ารหัสเพิ่มเติมมากมายสำหรับสิ่งที่เรียบง่ายโง่ ๆ / หนึ่งซับในภาษาอื่น (MSSQL) คำตอบที่ดี ... แม้ว่ามันจะเป็น "การเขียนโปรแกรมสไตล์ข้อยกเว้น" แต่มันอยู่ในฟังก์ชั่นอัพเกรด / แยกดังนั้นฉันคิดว่ามันยอมรับได้
maplemale

แม้ว่าคนอื่นจะไม่ชอบ แต่ฉันคิดว่านี่เป็นทางออกที่ดีที่สุด lol
Adam Varhegyi

13

threre เป็นวิธีการของ PRAGMA คือ table_info (table_name) ซึ่งจะส่งคืนข้อมูลทั้งหมดของตาราง

นี่คือการใช้งานวิธีใช้สำหรับคอลัมน์ตรวจสอบว่ามีอยู่หรือไม่

    public boolean isColumnExists (String table, String column) {
         boolean isExists = false
         Cursor cursor;
         try {           
            cursor = db.rawQuery("PRAGMA table_info("+ table +")", null);
            if (cursor != null) {
                while (cursor.moveToNext()) {
                    String name = cursor.getString(cursor.getColumnIndex("name"));
                    if (column.equalsIgnoreCase(name)) {
                        isExists = true;
                        break;
                    }
                }
            }

         } finally {
            if (cursor != null && !cursor.isClose()) 
               cursor.close();
         }
         return isExists;
    }

คุณยังสามารถใช้แบบสอบถามนี้โดยไม่ต้องใช้ลูป

cursor = db.rawQuery("PRAGMA table_info("+ table +") where name = " + column, null);

เคอร์เซอร์เคอร์เซอร์ = db.rawQuery ("เลือก * จาก tableName", null); คอลัมน์ = cursor.getColumnNames ();
Vahe Gharibyan

1
ฉันเดาว่าคุณลืมปิดเคอร์เซอร์ :-)
Pecana

@VaheGharibyan ดังนั้นคุณเพียงแค่เลือกทุกอย่างในฐานข้อมูลของคุณเพื่อรับชื่อคอลัมน์! สิ่งที่คุณพูดง่ายๆคือwe give no shit about performance:))
Farid

หมายเหตุแบบสอบถามสุดท้ายไม่ถูกต้อง แบบสอบถามที่เหมาะสมคือ: SELECT * FROM pragma_table_info(...)(สังเกต SELECT และขีดล่างระหว่าง pragma และข้อมูลตาราง) ไม่แน่ใจว่าพวกเขาเพิ่มเวอร์ชันใดลงไปจริง ๆ มันไม่ทำงานบน 3.16.0 แต่ใช้งานได้บน 3.22.0
PressingOnAlways

3

สำหรับผู้ที่ต้องการใช้pragma table_info()ผลลัพธ์เป็นส่วนหนึ่งของ SQL ที่มีขนาดใหญ่ขึ้น

select count(*) from
pragma_table_info('<table_name>')
where name='<column_name>';

ส่วนสำคัญคือการใช้pragma_table_info('<table_name>')แทนpragma table_info('<table_name>').


คำตอบนี้ได้รับแรงบันดาลใจจากการตอบกลับของ @Robert Hawkey เหตุผลที่ฉันโพสต์เป็นคำตอบใหม่คือฉันไม่มีชื่อเสียงมากพอที่จะโพสต์เป็นความคิดเห็น


1

ฉันคิดคำถามนี้ขึ้นมา

SELECT CASE (SELECT count(*) FROM pragma_table_info(''product'') c WHERE c.name = ''purchaseCopy'') WHEN 0 THEN ALTER TABLE product ADD purchaseCopy BLOB END
  • แบบสอบถามภายในจะส่งคืน 0 หรือ 1 หากมีคอลัมน์
  • จากผลลัพธ์ให้แก้ไขคอลัมน์

code = Error (1), message = System.Data.SQLite.SQLiteException (0x800007BF): ข้อผิดพลาดลอจิก SQL ใกล้ "ALTER": ข้อผิดพลาดทางไวยากรณ์ที่ System.Data.SQLite.SQLite3.Prepare
インコグニトアレクセイ

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

0

ในกรณีที่คุณมีปัญหานี้ใน flex / adobe air และพบว่าตัวเองอยู่ที่นี่ก่อนฉันพบวิธีแก้ปัญหาแล้วและโพสต์ไว้ในคำถามที่เกี่ยวข้อง: เพิ่ม COLUMN ไปยัง sqlite db หากไม่ออก - flex / air sqlite?

ความคิดเห็นของฉันที่นี่: https://stackoverflow.com/a/24928437/2678219


0

ฉันได้รับคำตอบข้างต้นใน C # /. net และเขียนใหม่สำหรับ Qt / C ++ ไม่ให้เปลี่ยนแปลงมากนัก แต่ฉันต้องการทิ้งไว้ที่นี่สำหรับทุกคนในอนาคตที่กำลังมองหาคำตอบ C ++ 'ish'

    bool MainWindow::isColumnExisting(QString &table, QString &columnName){

    QSqlQuery q;

    try {
        if(q.exec("PRAGMA table_info("+ table +")"))
            while (q.next()) {
                QString name = q.value("name").toString();     
                if (columnName.toLower() == name.toLower())
                    return true;
            }

    } catch(exception){
        return false;
    }
    return false;
}

0

คุณสามารถใช้คำสั่ง CASE-WHEN TSQL ร่วมกับ pragma_table_info เพื่อทราบว่ามีคอลัมน์อยู่หรือไม่:

select case(CNT) 
    WHEN 0 then printf('not found')
    WHEN 1 then printf('found')
    END
FROM (SELECT COUNT(*) AS CNT FROM pragma_table_info('myTableName') WHERE name='columnToCheck') 

ที่นี่เราจะเปลี่ยนตารางได้อย่างไร? เมื่อมีชื่อคอลัมน์ตรงกัน?
user2700767

0

นี่คือวิธีแก้ปัญหาของฉัน แต่ใน python (ฉันพยายามและไม่พบโพสต์ใด ๆ ในหัวข้อที่เกี่ยวข้องกับ python):

# modify table for legacy version which did not have leave type and leave time columns of rings3 table.
sql = 'PRAGMA table_info(rings3)' # get table info. returns an array of columns.
result = inquire (sql) # call homemade function to execute the inquiry
if len(result)<= 6: # if there are not enough columns add the leave type and leave time columns
    sql = 'ALTER table rings3 ADD COLUMN leave_type varchar'
    commit(sql) # call homemade function to execute sql
    sql = 'ALTER table rings3 ADD COLUMN leave_time varchar'
    commit(sql)

ฉันใช้ PRAGMA เพื่อรับข้อมูลตาราง ส่งคืนอาร์เรย์หลายมิติที่เต็มไปด้วยข้อมูลเกี่ยวกับคอลัมน์ - หนึ่งอาร์เรย์ต่อคอลัมน์ ฉันนับจำนวนอาร์เรย์เพื่อรับจำนวนคอลัมน์ หากมีคอลัมน์ไม่เพียงพอฉันจะเพิ่มคอลัมน์โดยใช้คำสั่ง ALTER TABLE


0

คำตอบทั้งหมดนี้ใช้ได้ถ้าคุณดำเนินการทีละบรรทัด อย่างไรก็ตามคำถามเดิมคือการป้อนสคริปต์ sql ที่จะดำเนินการโดยการดำเนินการ db เดียวและวิธีแก้ปัญหาทั้งหมด (เช่นการตรวจสอบเพื่อดูว่าคอลัมน์อยู่ที่นั่นก่อนเวลาหรือไม่) จะต้องใช้โปรแกรมดำเนินการทั้งที่มีความรู้เกี่ยวกับตารางและ คอลัมน์กำลังถูกเปลี่ยนแปลง / เพิ่มหรือทำการประมวลผลล่วงหน้าและแยกวิเคราะห์สคริปต์อินพุตเพื่อกำหนดข้อมูลนี้ โดยปกติคุณจะไม่เรียกใช้สิ่งนี้แบบเรียลไทม์หรือบ่อยครั้ง ดังนั้นแนวคิดในการจับข้อยกเว้นจึงเป็นที่ยอมรับและดำเนินการต่อไป ในนั้นปัญหาคือ ... จะดำเนินต่อไปอย่างไร โชคดีที่ข้อความแสดงข้อผิดพลาดให้ข้อมูลทั้งหมดที่จำเป็นสำหรับเราในการดำเนินการนี้ แนวคิดคือการดำเนินการ sql หากมีข้อยกเว้นในการเรียกตารางการเปลี่ยนแปลงเราสามารถค้นหาบรรทัดเปลี่ยนแปลงตารางใน sql และส่งคืนบรรทัดที่เหลือและดำเนินการจนกว่าจะสำเร็จหรือไม่พบรายการเปลี่ยนแปลงตารางที่ตรงกันอีกต่อไป นี่คือตัวอย่างโค้ดที่เรามีสคริปต์ sql ในอาร์เรย์ เราทำซ้ำอาร์เรย์ที่เรียกใช้แต่ละสคริปต์ เราเรียกมันว่าสองครั้งเพื่อให้คำสั่ง alter table ล้มเหลว แต่โปรแกรมทำได้สำเร็จเพราะเราลบคำสั่ง alter table ออกจาก sql และรันโค้ดที่อัพเดตอีกครั้ง

#!/bin/sh
# the next line restarts using wish \

exec /opt/usr8.6.3/bin/tclsh8.6  "$0" ${1+"$@"}
foreach pkg {sqlite3 } {
    if { [ catch {package require {*}$pkg } err ] != 0 } {
    puts stderr "Unable to find package $pkg\n$err\n ... adjust your auto_path!";
    }
}
array set sqlArray {
    1 {
    CREATE TABLE IF NOT EXISTS Notes (
                      id INTEGER PRIMARY KEY AUTOINCREMENT,
                      name text,
                      note text,
                      createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
                      updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) 
                      );
    CREATE TABLE IF NOT EXISTS Version (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        version text,
                        createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
                        updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) )
                        );
    INSERT INTO Version(version) values('1.0');
    }
    2 {
    CREATE TABLE IF NOT EXISTS Tags (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name text,
        tag text,
        createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
        updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) 
        );
    ALTER TABLE Notes ADD COLUMN dump text;
    INSERT INTO Version(version) values('2.0');
    }
    3 {
    ALTER TABLE Version ADD COLUMN sql text;
    INSERT INTO Version(version) values('3.0');
    }
}

# create db command , use in memory database for demonstration purposes
sqlite3 db :memory:

proc createSchema { sqlArray } {
    upvar $sqlArray sql
    # execute each sql script in order 
    foreach version [lsort -integer [array names sql ] ] {
    set cmd $sql($version)
    set ok 0
    while { !$ok && [string length $cmd ] } {  
        try {
        db eval $cmd
        set ok 1  ;   # it succeeded if we get here
        } on error { err backtrace } {
        if { [regexp {duplicate column name: ([a-zA-Z0-9])} [string trim $err ] match columnname ] } {
            puts "Error:  $err ... trying again" 
            set cmd [removeAlterTable $cmd $columnname ]
        } else {
            throw DBERROR "$err\n$backtrace"
        }
        }
    }
    }
}
# return sqltext with alter table command with column name removed
# if no matching alter table line found or result is no lines then
# returns ""
proc removeAlterTable { sqltext columnname } {
    set mode skip
    set result [list]
    foreach line [split $sqltext \n ] {
    if { [string first "alter table" [string tolower [string trim $line] ] ] >= 0 } {
        if { [string first $columnname $line ] } {
        set mode add
        continue;
        }
    }
    if { $mode eq "add" } {
        lappend result $line
    }
    }
    if { $mode eq "skip" } {
    puts stderr "Unable to find matching alter table line"
    return ""
    } elseif { [llength $result ] }  { 
    return [ join $result \n ]
    } else {
    return ""
    }
}
               
proc printSchema { } {
    db eval { select * from sqlite_master } x {
    puts "Table: $x(tbl_name)"
    puts "$x(sql)"
    puts "-------------"
    }
}
createSchema sqlArray
printSchema
# run again to see if we get alter table errors 
createSchema sqlArray
printSchema

ผลลัพธ์ที่คาดหวัง

Table: Notes
CREATE TABLE Notes (
                      id INTEGER PRIMARY KEY AUTOINCREMENT,
                      name text,
                      note text,
                      createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
                      updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) 
                      , dump text)
-------------
Table: sqlite_sequence
CREATE TABLE sqlite_sequence(name,seq)
-------------
Table: Version
CREATE TABLE Version (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        version text,
                        createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
                        updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) )
                        , sql text)
-------------
Table: Tags
CREATE TABLE Tags (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name text,
        tag text,
        createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
        updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) 
        )
-------------
Error:  duplicate column name: dump ... trying again
Error:  duplicate column name: sql ... trying again
Table: Notes
CREATE TABLE Notes (
                      id INTEGER PRIMARY KEY AUTOINCREMENT,
                      name text,
                      note text,
                      createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
                      updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) 
                      , dump text)
-------------
Table: sqlite_sequence
CREATE TABLE sqlite_sequence(name,seq)
-------------
Table: Version
CREATE TABLE Version (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        version text,
                        createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
                        updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) )
                        , sql text)
-------------
Table: Tags
CREATE TABLE Tags (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name text,
        tag text,
        createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
        updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) 
        )
-------------

0
select * from sqlite_master where type = 'table' and tbl_name = 'TableName' and sql like '%ColumnName%'

Logic: คอลัมน์ sql ใน sqlite_master มีนิยามตารางดังนั้นจึงมีสตริงที่มีชื่อคอลัมน์

ในขณะที่คุณค้นหาสตริงย่อยจะมีข้อ จำกัด ที่ชัดเจน ดังนั้นฉันขอแนะนำให้ใช้สตริงย่อยที่ จำกัด ยิ่งขึ้นใน ColumnName ตัวอย่างเช่นสิ่งนี้ (อาจไม่มีการทดสอบเป็นอักขระ '' 'เสมอไป):

select * from sqlite_master where type = 'table' and tbl_name = 'MyTable' and sql like '%`MyColumn` TEXT%'

0

ฉันแก้ปัญหาใน 2 แบบสอบถาม นี่คือสคริปต์ Unity3D ของฉันโดยใช้ System.Data.SQLite

IDbCommand command = dbConnection.CreateCommand();
            command.CommandText = @"SELECT count(*) FROM pragma_table_info('Candidat') c WHERE c.name = 'BirthPlace'";
            IDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                try
                {
                    if (int.TryParse(reader[0].ToString(), out int result))
                    {
                        if (result == 0)
                        {
                            command = dbConnection.CreateCommand();
                            command.CommandText = @"ALTER TABLE Candidat ADD COLUMN BirthPlace VARCHAR";
                            command.ExecuteNonQuery();
                            command.Dispose();
                        }
                    }
                }
                catch { throw; }
            }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.