315

我需要重命名 SQLite 数据库中某些表中的一些列。我知道之前在stackoverflow上也有人问过类似的问题,但一般是针对SQL的,没有提到SQLite的情况。

ALTER TABLE的 SQLite 文档中,我了解到不可能“轻松”地做这样的事情(即单个 ALTER TABLE 语句)。

我想知道有人知道用 SQLite 做这种事情的通用 SQL 方式。

4

15 回答 15

464

假设您有一个表,需要将“colb”重命名为“col_b”:

首先你重命名旧表:

ALTER TABLE orig_table_name RENAME TO tmp_table_name;

然后基于旧表创建新表,但使用更新的列名:

CREATE TABLE orig_table_name (
  col_a INT
, col_b INT
);

然后从原始表中复制内容。

INSERT INTO orig_table_name(col_a, col_b)
SELECT col_a, colb
FROM tmp_table_name;

最后,删除旧表。

DROP TABLE tmp_table_name;

将所有这些包装在一个BEGIN TRANSACTION;andCOMMIT;中也可能是一个好主意。

于 2009-04-30T05:57:11.667 回答
93

这刚刚在2018-09-15 (3.25.0)中修复

增强ALTER TABLE命令:

  • 添加对使用ALTER TABLEtable重命名表中的列的支持RENAME COLUMN oldname TO newname
  • 修复表重命名功能,以便它还更新触发器和视图中对重命名表的引用。

您可以在下面找到记录的新语法ALTER TABLE

RENAME COLUMN TO语法将表 table-name 的 column-name 更改为 new-column-name。列名在表定义本身以及引用该列的所有索引、触发器和视图中都发生了更改。如果列名更改会导致触发器或视图中的语义模糊,则RENAME COLUMN失败并出现错误并且不会应用任何更改。

在此处输入图像描述 图片来源:https ://www.sqlite.org/images/syntax/alter-table-stmt.gif

例子:

CREATE TABLE tab AS SELECT 1 AS c;

SELECT * FROM tab;

ALTER TABLE tab RENAME COLUMN c to c_new;

SELECT * FROM tab;

db-fiddle.com 演示


安卓支持

在撰写本文时,Android 的 API 27 使用 SQLite 包版本 3.19

基于 Android 正在使用的当前版本以及此更新将在 SQLite 版本 3.25.0 中提供,我会说您需要等待(大约 API 33)才能将对此的支持添加到 Android。

而且,即便如此,如果您需要支持任何早于 API 33 的版本,您将无法使用它。

于 2018-09-15T15:36:57.613 回答
60

挖掘了一下,我发现了这个名为DB Browser for SQLite的多平台(Linux | Mac | Windows)图形工具,它实际上允许以一种非常用户友好的方式重命名列!

编辑 | 修改表 | 选择表 | 编辑字段。点击点击!瞧!

但是,如果有人想分享一种编程方式,我很高兴知道!

于 2009-04-30T05:17:40.000 回答
55

虽然确实没有 ALTER COLUMN,但如果您只想重命名列、删除 NOT NULL 约束或更改数据类型,则可以使用以下命令集:

注意:这些命令可能会损坏您的数据库,因此请确保您有备份

PRAGMA writable_schema = 1;
UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE BOOKS ( title TEXT NOT NULL, publication_date TEXT)' WHERE NAME = 'BOOKS';
PRAGMA writable_schema = 0;

您将需要关闭并重新打开连接或清理数据库以将更改重新加载到架构中。

例如:

Y:\> sqlite3 booktest  
SQLite version 3.7.4  
Enter ".help" for instructions  
Enter SQL statements terminated with a ";"  
sqlite> create table BOOKS ( title TEXT NOT NULL, publication_date TEXT NOT NULL);  
sqlite> insert into BOOKS VALUES ("NULLTEST",null);  
Error: BOOKS.publication_date may not be NULL  
sqlite> PRAGMA writable_schema = 1; 
sqlite> UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE BOOKS ( title TEXT NOT NULL, publication_date TEXT)' WHERE NAME = 'BOOKS';  
sqlite> PRAGMA writable_schema = 0;  
sqlite> .q  

Y:\> sqlite3 booktest  
SQLite version 3.7.4  
Enter ".help" for instructions  
Enter SQL statements terminated with a ";"  
sqlite> insert into BOOKS VALUES ("NULLTEST",null);  
sqlite> .q  

参考文献如下:


pragma writable_schema
当这个 pragma 开启时,可以使用普通的 UPDATE、INSERT 和 DELETE 语句更改数据库所在的 SQLITE_MASTER 表。警告:滥用此编译指示很容易导致数据库文件损坏。

alter table
SQLite 支持有限的 ALTER TABLE 子集。SQLite 中的 ALTER TABLE 命令允许用户重命名表或向现有表添加新列。无法重命名列、删除列或在表中添加或删除约束。

更改表语法

于 2011-07-13T18:52:47.490 回答
18

最近我不得不在 SQLite3 中使用一个名为points的表来执行此操作,该表的列id, lon, lat。错误地,当导入表时,纬度值存储在lon列中,反之亦然,因此一个明显的解决方法是重命名这些列。所以诀窍是:

create table points_tmp as select id, lon as lat, lat as lon from points;
drop table points;
alter table points_tmp rename to points;

我希望这对你有用!

于 2011-10-17T02:13:01.420 回答
15

案例 1:SQLite 3.25.0+

只有 SQLite 3.25.0 版支持重命名列。如果你的设备满足这个要求,事情就很简单了。以下查询将解决您的问题:

ALTER TABLE "MyTable" RENAME COLUMN "OldColumn" TO "NewColumn";

案例 2:SQLite 旧版本

您必须遵循不同的方法才能获得可能有点棘手的结果

例如,如果您有这样的表:

CREATE TABLE student(Name TEXT, Department TEXT, Location TEXT)

如果您想更改列的名称Location

步骤 1:重命名原始表:

ALTER TABLE student RENAME TO student_temp;

第 2 步:现在创建一个student具有正确列名的新表:

CREATE TABLE student(Name TEXT, Department TEXT, Address TEXT)

第三步:将原表中的数据复制到新表中:

INSERT INTO student(Name, Department, Address) SELECT Name, Department, Location FROM student_temp;

注意:上面的命令应该是一行。

第 4 步:删除原始表:

DROP TABLE student_temp;

通过这四个步骤,您可以手动更改任何 SQLite 表。请记住,您还需要在新表上重新创建任何索引、查看器或触发器。

于 2019-05-22T15:54:56.673 回答
14

引用sqlite 文档

SQLite 支持有限的 ALTER TABLE 子集。SQLite 中的 ALTER TABLE 命令允许用户重命名表或向现有表添加新列。无法重命名列、删除列或在表中添加或删除约束。

当然,您可以做的是,使用新布局创建一个新表SELECT * FROM old_table,并用您将收到的值填充新表。

于 2009-04-30T04:54:39.210 回答
7

首先,这是让我大吃一惊的事情之一:重命名列需要创建一个全新的表并将数据从旧表复制到新表......

我用来执行 SQLite 操作的 GUI 是Base。它有一个漂亮的日志窗口,显示所有已执行的命令。通过 Base 重命名列会使用必要的命令填充日志窗口:

基本日志窗口

然后可以轻松地将这些复制并粘贴到您可能需要它们的地方。对我来说,这是一个ActiveAndroid迁移文件。一个很好的感觉是,复制的数据只包括 SQLite 命令,而不包括时间戳等。

希望这可以节省一些人的时间。

于 2014-05-02T21:31:32.103 回答
3

将表列 <id> 更改为 <_id>

 String LastId = "id";

    database.execSQL("ALTER TABLE " + PhraseContract.TABLE_NAME + " RENAME TO " + PhraseContract.TABLE_NAME + "old");
    database.execSQL("CREATE TABLE " + PhraseContract.TABLE_NAME
    +"("
            + PhraseContract.COLUMN_ID + " INTEGER PRIMARY KEY,"
            + PhraseContract.COLUMN_PHRASE + " text ,"
            + PhraseContract.COLUMN_ORDER  + " text ,"
            + PhraseContract.COLUMN_FROM_A_LANG + " text"
    +")"
    );
    database.execSQL("INSERT INTO " +
            PhraseContract.TABLE_NAME + "("+ PhraseContract.COLUMN_ID +" , "+ PhraseContract.COLUMN_PHRASE + " , "+ PhraseContract.COLUMN_ORDER +" , "+ PhraseContract.COLUMN_FROM_A_LANG +")" +
            " SELECT " + LastId +" , "+ PhraseContract.COLUMN_PHRASE + " , "+ PhraseContract.COLUMN_ORDER +" , "+ PhraseContract.COLUMN_FROM_A_LANG +
            " FROM " + PhraseContract.TABLE_NAME + "old");
    database.execSQL("DROP TABLE " + PhraseContract.TABLE_NAME + "old");
于 2015-06-24T07:50:48.677 回答
3

使用所需的列名称创建一个新列:COLNew。

ALTER TABLE {tableName} ADD COLUMN COLNew {type};

将旧列 COLOld 的内容复制到新列 COLNew。

INSERT INTO {tableName} (COLNew) SELECT {COLOld} FROM {tableName}

注意:上面一行需要括号。

于 2016-08-02T07:16:29.937 回答
2

如前所述,有一个工具 SQLite Database Browser 可以执行此操作。Lyckily,这个工具会记录用户或应用程序执行的所有操作。这样做一次并查看应用程序日志,您将看到所涉及的代码。根据需要复制查询并粘贴。为我工作。希望这可以帮助

于 2013-04-06T21:20:53.323 回答
2

来自官方文档

对于不以任何方式影响磁盘内容的某些更改,可以选择使用更简单和更快的过程。以下更简单的过程适用于删除 CHECK 或 FOREIGN KEY 或 NOT NULL 约束、重命名列或添加、删除或更改列的默认值。

  1. 开始交易。

  2. 运行 PRAGMA schema_version 以确定当前模式版本号。下面的第 6 步将需要此编号。

  3. 使用 PRAGMA writable_schema=ON 激活模式编辑。

  4. 运行 UPDATE 语句更改 sqlite_master 表中表 X 的定义: UPDATE sqlite_master SET sql=... WHERE type='table' AND name='X';

    注意:如果更改包含语法错误,则像这样对 sqlite_master 表进行更改将导致数据库损坏且不可读。建议在将 UPDATE 语句用于包含重要数据的数据库之前,对单独的空白数据库进行仔细测试。

  5. 如果对表 X 的更改也影响其他表或索引或触发器是模式中的视图,则运行 UPDATE 语句来修改那些其他表的索引和视图。例如,如果列的名称发生更改,则必须修改引用该列的所有 FOREIGN KEY 约束、触发器、索引和视图。

    警告:再一次,如果更改包含错误,则像这样对 sqlite_master 表进行更改将导致数据库损坏且不可读。在将整个过程用于包含重要数据的数据库和/或在运行此过程之前制作重要数据库的备份副本之前,请在单独的测试数据库上仔细测试整个过程。

  6. 使用 PRAGMA schema_version=X 增加模式版本号,其中 X 比上面步骤 2 中找到的旧模式版本号大一。

  7. 使用 PRAGMA writable_schema=OFF 禁用模式编辑。

  8. (可选)运行 PRAGMA integrity_check 以验证架构更改没有损坏数据库。

  9. 提交在上述第 1 步开始的事务。

于 2018-01-14T16:26:10.447 回答
1

一个选择,如果您需要在紧要关头完成它,并且如果您的初始列是使用默认值创建的,则创建您想要的新列,将内容复制到它,然后基本上“放弃”旧列(它保留存在,但您只是不使用/更新它等)

前任:

alter table TABLE_NAME ADD COLUMN new_column_name TYPE NOT NULL DEFAULT '';
update TABLE_NAME set new_column_name = old_column_name;
update TABLE_NAME set old_column_name = ''; -- abandon old column, basically

这会留下一列(如果它是用 NOT NULL 创建但没有默认值,那么将来忽略它的插入可能会失败),但如果它只是一个一次性表,则权衡可能是可以接受的。否则,请使用此处提到的其他答案之一,或使用允许重命名列的其他数据库。

于 2016-10-20T23:03:08.443 回答
-1

由于版本 2018-09-15 (3.25.0) sqlite 支持重命名列

https://sqlite.org/changes.html

于 2019-04-05T10:28:43.257 回答
-3

sqlite3 yourdb .dump > /tmp/db.txt
edit /tmp/db.txt 在 Create line
sqlite2 yourdb2 < /tmp/db.txt
mv/move yourdb2 yourdb中更改列名

于 2015-03-04T17:34:43.967 回答