2011-05-09 156 views
76

我有一個問題:我需要從我的SQLite數據庫中刪除一列。我寫了這個查詢從SQLite表中刪除列

alter table table_name drop column column_name 

但它不起作用。請幫幫我。

回答

141

來源:http://www.sqlite.org/faq.html

(11)如何從SQLite中現有的表中添加或刪除列。

SQLite具有有限的ALTER TABLE支持,您可以使用該支持將 列添加到表的末尾或更改表的名稱。如果 想要對錶的結構進行更復雜的更改,那麼 將不得不重新創建表。您可以將現有數據保存到臨時表中,刪除舊錶,創建新表,然後將數據從臨時表中複製回 。

例如,假設您有一個名爲「t1」的表,其列名爲 「a」,「b」和「c」,並且您想從此 表中刪除列「c」。下面的步驟說明如何可以這樣做:

BEGIN TRANSACTION; 
CREATE TEMPORARY TABLE t1_backup(a,b); 
INSERT INTO t1_backup SELECT a,b FROM t1; 
DROP TABLE t1; 
CREATE TABLE t1(a,b); 
INSERT INTO t1 SELECT a,b FROM t1_backup; 
DROP TABLE t1_backup; 
COMMIT; 
+6

+總是閱讀SQLite文檔。當您遇到錯誤時,您會注意到SQL語法中的太多限制和差異。 SQLite文檔很容易理解。不要擔心。 – 2011-05-13 08:00:32

+1

您需要在刪除安全列後執行VACUUM命令;如果沒有抽真空,數據庫文件仍然包含已刪除列的數據。 – jj1bdx 2017-02-14 05:03:48

+0

@ jj1bdx我不認爲它仍然包含數據,但是「未使用的磁盤空間被添加到內部的」自由列表「中並且在下一次插入數據時被重用。磁盤空間不會丟失。它返回到操作系統。「從sqlite3網站引用。 – 2017-08-23 00:49:55

3

=>直接與下面的查詢創建一個新的表:

CREATE TABLE Table_name (Column_1 text,Column_2 text); 

=>現在將數據與以下查詢插入到表名從Existing_table:

insert into Table_name (Column_1,Column_2) FROM Existing_Table; 

=>現在通過以下查詢刪除Existing_table:

DROP Existing_Table; 
1

對於SQLite3的C++:

void GetTableColNames(tstring sTableName , std::vector<tstring> *pvsCols) 
{ 
    UASSERT(pvsCols); 

    CppSQLite3Table table1; 

    tstring sDML = StringOps::std_sprintf(_T("SELECT * FROM %s") , sTableName.c_str()); 



    table1 = getTable(StringOps::tstringToUTF8string(sDML).c_str()); 

    for (int nCol = 0 ; nCol < table1.numFields() ; nCol++) 
    { 
     const char* pch1 = table1.fieldName(nCol); 

     pvsCols->push_back(StringOps::UTF8charTo_tstring(pch1)); 
    } 
} 


bool ColExists(tstring sColName) 
{ 
    bool bColExists = true; 

    try 
    { 
     tstring sQuery = StringOps::std_sprintf(_T("SELECT %s FROM MyOriginalTable LIMIT 1;") , sColName.c_str()); 

     ShowVerbalMessages(false); 

     CppSQLite3Query q = execQuery(StringOps::tstringTo_stdString(sQuery).c_str()); 

     ShowVerbalMessages(true); 
    } 
    catch (CppSQLite3Exception& e) 
    { 
     bColExists = false; 
    } 

    return bColExists; 
} 

void DeleteColumns(std::vector<tstring> *pvsColsToDelete) 
{ 
    UASSERT(pvsColsToDelete); 

    execDML(StringOps::tstringTo_stdString(_T("begin transaction;")).c_str()); 


    std::vector<tstring> vsCols; 
    GetTableColNames(_T("MyOriginalTable") , &vsCols); 


    CreateFields(_T("TempTable1") , false); 

    tstring sFieldNamesSeperatedByCommas; 

    for (int nCol = 0 ; nCol < vsCols.size() ; nCol++) 
    { 

     tstring sColNameCurr = vsCols.at(nCol); 

     bool bUseCol = true; 

     for (int nColsToDelete = 0; nColsToDelete < pvsColsToDelete->size() ; nColsToDelete++) 
     { 
      if (pvsColsToDelete->at(nColsToDelete) == sColNameCurr) 
      { 
       bUseCol = false; 
       break; 
      } 
     } 

     if (bUseCol) 
      sFieldNamesSeperatedByCommas+= (sColNameCurr + _T(",")); 

    } 

    if (sFieldNamesSeperatedByCommas.at(int(sFieldNamesSeperatedByCommas.size()) - 1) == _T(',')) 
     sFieldNamesSeperatedByCommas.erase(int(sFieldNamesSeperatedByCommas.size()) - 1); 

    tstring sDML; 


    sDML = StringOps::std_sprintf(_T("insert into TempTable1 SELECT %s FROM MyOriginalTable;\n") , sFieldNamesSeperatedByCommas.c_str()); 
    execDML(StringOps::tstringTo_stdString(sDML).c_str()); 

    sDML = StringOps::std_sprintf(_T("ALTER TABLE MyOriginalTable RENAME TO MyOriginalTable_old\n")); 
    execDML(StringOps::tstringTo_stdString(sDML).c_str()); 

    sDML = StringOps::std_sprintf(_T("ALTER TABLE TempTable1 RENAME TO MyOriginalTable\n")); 
    execDML(StringOps::tstringTo_stdString(sDML).c_str()); 


    sDML = (_T("DROP TABLE MyOriginalTable_old;")); 
    execDML(StringOps::tstringTo_stdString(sDML).c_str()); 


    execDML(StringOps::tstringTo_stdString(_T("commit transaction;")).c_str()); 
} 
48

而不是丟棄的備份表,只是將其重命名......

BEGIN TRANSACTION; 
CREATE TABLE t1_backup(a,b); 
INSERT INTO t1_backup SELECT a,b FROM t1; 
DROP TABLE t1; 
ALTER TABLE t1_backup RENAME TO t1; 
COMMIT; 
+0

當你將foregin鍵連接到't1'時,它不會工作。 。 – ephemerr 2017-12-20 12:54:22

18

爲了簡單,爲什麼不從select語句創建備份表?

CREATE TABLE t1_backup AS SELECT a, b FROM t1; 
DROP TABLE t1; 
ALTER TABLE t1_backup RENAME TO t1; 
+0

這種方法似乎保留了列的數據類型,而像[接受的答案](https://stackoverflow.com/a/5987838/107625)似乎導致所有列都是「TEXT」類型。 – 2017-07-10 15:05:30

+0

對我來說最好的答案是 – Pizzicato 2017-09-21 08:11:23

+0

比接受的答案好得多,也比較簡單並且有效:) – athospy 2017-10-27 17:44:50

0

如果有人需要一個(幾乎)準備使用的PHP函數,以下是based on this answer

/** 
* Remove a column from a table. 
* 
* @param string $tableName The table to remove the column from. 
* @param string $columnName The column to remove from the table. 
*/ 
public function DropTableColumn($tableName, $columnName) 
{ 
    // -- 
    // Determine all columns except the one to remove. 

    $columnNames = array(); 

    $statement = $pdo->prepare("PRAGMA table_info($tableName);"); 
    $statement->execute(array()); 
    $rows = $statement->fetchAll(PDO::FETCH_OBJ); 

    $hasColumn = false; 

    foreach ($rows as $row) 
    { 
     if(strtolower($row->name) !== strtolower($columnName)) 
     { 
      array_push($columnNames, $row->name); 
     } 
     else 
     { 
      $hasColumn = true; 
     } 
    } 

    // Column does not exist in table, no need to do anything. 
    if (!$hasColumn) return; 

    // -- 
    // Actually execute the SQL. 

    $columns = implode('`,`', $columnNames); 

    $statement = $pdo->exec(
     "CREATE TABLE `t1_backup` AS SELECT `$columns` FROM `$tableName`; 
     DROP TABLE `$tableName`; 
     ALTER TABLE `t1_backup` RENAME TO `$tableName`;"); 
} 

相較於其他的答案,在這種方法中使用的SQL似乎保留列的數據類型,而像接受的答案似乎導致所有列的類型爲TEXT

更新1:

使用的SQL具有以下缺點:autoincrement保留。

0

此選項僅在您可以在像DB Browser for SQLite這樣的數據庫瀏覽器中打開數據庫時有效。

在DB瀏覽器的SQLite:

  1. 轉到選項卡,「數據庫結構」
  2. 選擇表選擇修改表(剛下標籤)
  3. 選擇要刪除的列
  4. 單擊刪除字段並單擊確定