2011-05-09 106 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. 单击删除字段并单击确定