如何重命名SQLite数据库表中的列?


296

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

ALTER TABLE的SQLite文档中,我发现不可能“轻松”地执行此操作(即,单个ALTER TABLE语句)。

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


您可以使用db browser for sqlite轻松完成此操作
Matt G

1
请考虑将此答案标记为已接受stackoverflow.com/a/52346199/124486
Evan Carroll

Answers:


66

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

增强ALTER TABLE命令:

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

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

RENAME COLUMN TO语法将表table-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支持

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

根据Android当前使用的版本以及SQLite的3.25.0版本中的此更新,我想您需要等待一段时间(大约API 33),然后才能将此功能添加到Android中。

而且,即使那样,如果您需要支持API 33之前的任何版本,则将无法使用它。


8
我正在为Android迁移实施,很遗憾,IntelliJ显示警告,提示它不是有效的SQL命令。database.execSQL("ALTER TABLE content RENAME COLUMN archiveCount TO dismissCount")COLUM以红色高亮显示,表示达到预期,得到了'COLUMN'。不幸的是,Android仍在SQLite 3.19版本上,这就是为什么它对我不起作用的原因。
亚当·赫维兹

1
编辑:我发现在system.data.sqlite.org/index.html/doc/trunk/www/faq.wiki#q1上,1.0.109.x)实际上正在使用SQLite 3.24和System.Data.SQLite使用SQLite 3.25计划在本月发布。
rychlmoj

1
仅供参考,不幸的是,这尚未由Android的SQLite库实现。希望他们会尽快更新。
亚当·赫维兹

3
我为Android支持添加了一个部分,以防止其他人抱有希望。根据Android 27当前对SQLite 3.19的使用情况,我们必须等到大致API 33才能将此功能添加到Android,即使那样,它也仅在最新版本中受支持。叹。
约书亚·品特

1
@JoshuaPinter感谢您扩展我的答案。
Lukasz Szozda

448

假设您有一个表,需要将“ 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;COMMIT;中可能也是一个好主意。


51
并且不要忘记您的索引。
汤姆·梅菲尔德,

11
非常重要的是,上面的示例代码缺少事务。您应该将整个内容包装在BEGIN / END(或ROLLBACK)中,以确保重命名成功完成或根本没有完成。
罗杰·宾斯

4
任何人如有意这样做的机器人可以实现使用事务SQLiteDatabase.beginTransaction()
bmaupin

7
答案中的代码中没有任何内容可以复制索引。创建一个空表并将数据放入其中只会复制结构和数据。如果需要元数据(索引,外键,约束等),则还必须发出语句以在替换的表上创建它们。
汤姆·梅菲尔德,2012年

17
SQLite的.schema命令非常适合显示CREATE TABLE构成现有表的语句。您可以获取其输出,根据需要进行修改,然后执行以创建新表。该命令还显示CREATE INDEX创建索引的必要命令,该索引应涵盖Thomas的关注点。当然,请务必在更改任何内容之前运行此命令。
Mike DeSimone

56

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

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

但是,如果有人想分享一种编程方式来做到这一点,我将很高兴知道!


1
还有一个Firefox插件可以执行相同的操作,右键单击要重命名的列,然后选择“编辑列”。
2014年

1
即使在openSUSE中,也可以作为软件包使用: software.opensuse.org/package/sqlitebrowser

它有这么多票很奇怪。我们在这里谈论编程(代码)。您为什么还要在这里发布此答案?
user25

2
我的问题中没有提到如何使用代码来做到这一点。我只是想知道如何在SQLite数据库中重命名列。
joce,

@joce我爱你!!!(就像一个兄弟一样)让我进入了改变的领域,瞧。我已经将MS Access表导出到SQLite,并且其中一个字段的前面有一个数字:3YearLetterSent。Visual Studio从表中创建了该类,但在字段名称前面的“ 3”数字处出现了阻塞。我知道这一点,只是没有看。
JustJohn

53

确实没有任何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表。警告:滥用该编译指示很容易导致数据库文件损坏。

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

更改表语法


3
危险,但仍可能是最直接的答案imo。
Tek

2
是的,速度非常快- 危险仅表示“确保先备份”
诺亚(Noah)2012年

6
sqlite文件格式非常简单,这就是为什么此操作有效的原因。该文件格式仅具有关于表的两组信息:实际的CREATE TABLE命令(以纯文本格式)和行(其值按CREATE命令中的字段顺序显示)。这意味着sqlite代码打开数据库,它解析每个CREATE命令并在内存中动态建立其列信息。因此,即使您更改列的类型或约束,以最终列数相同的方式更改CREATE命令的任何命令都将起作用。
Thomas Tempelmann '16

3
@ThomasTempelmann但是,添加数据集无法满足的约束将产生问题,因为查询计划者假定约束成立。
fuz 2016年

2
@ThomasTempelmann 删除约束总是可以的。如果所有行都满足约束条件,则添加约束条件很好,但是您当然需要检查。
2016年

18

最近,我不得不在SQLite3中使用名为points的表进行此操作具有colidms 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;

希望对您有用!


此方法不能正确复制PK值,而是自动创建隐藏的rowid列。不一定是问题,但想指出这一点,因为这对我来说是一个问题。
TPoschel

4
进行“更新点SET lon = lat,lat = lon;”会更容易吗?
kstep

1
这个答案会按照正确的ORDER进行处理。首先创建临时表并填充它,然后销毁原始表
Xeoncross

14

引用sqlite文档

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

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


7

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

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

基本日志窗口

然后可以轻松地将它们复制并粘贴到您可能需要的位置。对我来说, ActiveAndroid迁移文件。同样令人高兴的是,复制的数据仅包含SQLite命令,而不包含时间戳等。

希望可以节省一些时间。


仅供参考,如果您正在使用ActiveAndroid,则可以省略BEGIN TRANSACTION;,并COMMIT;通过自身的线条,如ActiveAndroid把手。
2014年

6

情况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)

步骤3:将数据从原始表复制到新表:

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

注意:以上命令应全部为一行。

步骤4:删除原始表格:

DROP TABLE student_temp;

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


1
如何sqllite数据库版本升级到android的工作室3.29.0我使用API级28
Nathani软件

SQLite版本由应用程序所运行的设备定义。它取决于设备。
Febin Mathew

1
对于使用旧sqlite的人,不建议执行上述四个步骤。请参见sqlite.org/lang_altertable.html上的“警告”部分。
杰夫,

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");

3

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

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

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

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

注意:以上行中必须有括号。


2

如前所述,有一个工具SQLite数据库浏览器可以做到这一点。幸运的是,该工具保留了用户或应用程序执行的所有操作的日志。这样做一次并查看应用程序日志,您将看到所涉及的代码。复制查询并根据需要粘贴。为我工作。希望这可以帮助


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中找到的旧架构版本号大1。

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

  8. (可选)运行PRAGMA integrity_check以验证架构更改是否不会损坏数据库。

  9. 提交从上面的步骤1开始的事务。


PRAGMA integrity_check不会在架构中发现任何错误。
Graymatter

那是什么问题呢?
Mohammad Yahia,

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创建的,但没有默认值,那么以后忽略它的插入操作可能会失败),但是如果它只是一个一次性表,那么折衷可能是可以接受的。否则,请使用此处提到的其他答案之一,或使用允许重命名列的其他数据库。



-3

sqlite3 yourdb .dump> /tmp/db.txt
编辑/tmp/db.txt更改创建行中的列名称
sqlite2 yourdb2 </tmp/db.txt
mv /移动yourdb2 yourdb


3
您的回答没有提供任何信息,发出了很多代码/指令,却没有任何其他信息,说明您认为它为什么会起作用或者如果运行它会发生什么情况
RGLSV 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.