2011-05-09 79 views
76

Tôi gặp sự cố: Tôi cần xóa một cột khỏi cơ sở dữ liệu SQLite của mình. Tôi đã viết truy vấn nàyXóa cột khỏi bảng SQLite

alter table table_name drop column column_name 

nhưng nó không hoạt động. Làm ơn giúp tôi.

Trả lời

141

Từ: http://www.sqlite.org/faq.html:

(11) Làm thế nào để thêm hoặc xóa các cột từ một bảng hiện có trong SQLite.

SQLite có hỗ trợ ALTER TABLE giới hạn mà bạn có thể sử dụng để thêm cột vào cuối bảng hoặc để thay đổi tên của bảng. Nếu bạn muốn thực hiện các thay đổi phức tạp hơn trong cấu trúc của bảng, bạn sẽ phải tạo lại bảng. Bạn có thể lưu dữ liệu hiện có vào bảng tạm thời , thả bảng cũ, tạo bảng mới, sau đó sao chép dữ liệu trở lại từ bảng tạm thời. Ví dụ: giả sử bạn có bảng có tên là "t1" có các cột tên "a", "b" và "c" và bạn muốn xóa cột "c" khỏi bảng này. Các bước sau đây minh họa cách này có thể được thực hiện:

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

+ Luôn đọc tài liệu SQLite. Bạn sẽ nhận thấy quá nhiều giới hạn và sự khác biệt trong ngữ pháp SQL khi bạn gặp lỗi. Tài liệu SQLite rất dễ hiểu. Đừng lo lắng về điều đó. –

+1

Bạn cần thực hiện lệnh VACUUM sau khi xóa các cột để bảo mật; mà không hút bụi, tệp cơ sở dữ liệu vẫn chứa dữ liệu của các cột đã xóa. – jj1bdx

+0

@ jj1bdx Tôi không nghĩ rằng nó vẫn chứa dữ liệu, nhưng "không gian đĩa chưa sử dụng được thêm vào" danh sách miễn phí "bên trong và được tái sử dụng vào lần sau khi bạn chèn dữ liệu. nó quay trở lại hệ điều hành. " như được trích dẫn từ trang web sqlite3. –

3

=> Tạo một bảng mới trực tiếp với các truy vấn sau đây:

CREATE TABLE Table_name (Column_1 text,Column_2 text); 

=> Bây giờ chèn dữ liệu vào tên_bảng từ Existing_table với truy vấn sau đây:

insert into Table_name (Column_1,Column_2) FROM Existing_Table; 

=> Bây giờ hãy xóa Existing_table bằng truy vấn sau:

DROP Existing_Table; 
1

Đối 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

Thay vì thả các bảng sao lưu, chỉ cần đổi tên nó ...

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

Nó sẽ không hoạt động khi bạn đã khóa chính được kết nối với 't1' . – ephemerr

18

Để đơn giản, tại sao không tạo ra các bảng sao lưu từ báo cáo kết quả lựa chọn?

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

Cách tiếp cận này dường như bảo toàn các kiểu dữ liệu của các cột, trong khi một cái gì đó như [câu trả lời được chấp nhận] (https://stackoverflow.com/a/5987838/107625) dường như dẫn đến tất cả các cột thuộc loại 'TEXT'. –

+0

câu trả lời tốt nhất cho tôi – Pizzicato

+0

tốt hơn nhiều so với câu trả lời được chấp nhận và đơn giản hơn và hoạt động :) – athospy

0

Trong trường hợp bất cứ ai cần một (gần) sẵn sàng để sử dụng chức năng PHP, sau đây là 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`;"); 
} 

Ngược lại với câu trả lời khác, SQL được sử dụng trong phương pháp này dường như để bảo tồn các kiểu dữ liệu của các cột, trong khi một cái gì đó giống như câu trả lời được chấp nhận dường như dẫn đến tất cả các cột thuộc loại TEXT.

Cập nhật 1:

SQL sử dụng có nhược điểm mà autoincrement cột không bảo tồn.

0

Tùy chọn này chỉ hoạt động nếu bạn có thể mở DB trong Trình duyệt DB như DB Browser for SQLite.

Trong DB Trình duyệt cho SQLite:

  1. Đến tab, "Cơ sở dữ liệu Cấu trúc"
  2. Chọn bạn bảng Chọn Sửa bảng (ngay dưới tab)
  3. Chọn cột mà bạn muốn xóa
  4. Nhấp vào Xóa trường và nhấp vào OK
Các vấn đề liên quan