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

Posted

技术标签:

【中文标题】如何重命名 SQLite 数据库表中的列?【英文标题】:How do I rename a column in a SQLite database table? 【发布时间】:2010-10-22 18:22:39 【问题描述】:

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

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

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

【问题讨论】:

你可以很容易地使用db browser for sqlite做到这一点 请考虑将此答案标记为已接受***.com/a/52346199/124486 【参考方案1】:

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

【讨论】:

别忘了你的索引。 非常重要的是上面的示例代码缺少一个事务。您应该将整个内容包装在 BEGIN/END(或 ROLLBACK)中,以确保重命名成功完成或根本不完成。 任何希望在 android 中执行此操作的人都可以使用 SQLiteDatabase.beginTransaction() 实现事务 答案中的代码中没有任何内容可以复制索引。创建一个空表并将数据放入其中只会复制结构和数据。如果您想要元数据(索引、外键、约束等),那么您还必须发出语句以在替换表上创建它们。 SQLite 的.schema 命令可以方便地显示生成现有表的CREATE TABLE 语句。您可以获取其输出,根据需要进行修改,然后执行它以创建新表。该命令还显示了创建索引所需的CREATE INDEX 命令,这应该涵盖了 Thomas 的关注点。当然,请务必在更改任何内容之前运行此命令。【参考方案2】:

刚刚用2018-09-15 (3.25.0)修复了这个问题

增强了ALTER TABLE 命令:

添加对使用ALTER TABLERENAME 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 demo


Android 支持

截至发稿时,Android's API 27 is using SQLite package version 3.19。

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

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

【讨论】:

我正在实施 Android 迁移,不幸的是 IntelliJ 显示警告,指出它不是有效的 SQL 命令。 database.execSQL("ALTER TABLE content RENAME COLUMN archiveCount TO dismissCount")COLUM 以红色突出显示,它显示 TO expected, got 'COLUMN'。不幸的是,Android 仍在 SQLite 版本 3.19 上,这就是为什么这对我不起作用。 已编辑:我在system.data.sqlite.org/index.html/doc/trunk/www/faq.wiki#q1 上发现,1.0.109.x) 实际上使用的是 SQLite 3.24,而使用 SQLite 3.25 的 System.Data.SQLite 计划在本月发布。 仅供参考,不幸的是,Android's SQLite library 尚未实施。希望他们会尽快更新。 我为 Android 支持添加了一个部分,以防止其他人抱有希望。基于 Android 27 目前对 SQLite 3.19 的使用,我们将不得不等到大约 API 33 才能将此功能添加到 Android,即使那样它也只会在最新版本上得到支持。叹息。 @JoshuaPinter 感谢您扩展我的回答。【参考方案3】:

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

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

但是,如果有人想分享执行此操作的程序化方式,我很乐意知道!

【讨论】:

还有一个Firefox add-on that does the same thing,右击要重命名的列,选择“编辑列”。 即使在 openSUSE 中,它也可以作为一个包使用:software.opensuse.org/package/sqlitebrowser 它有这么多票很奇怪。我们在这里谈论编程(代码)。你为什么还要在这里发布这个答案? 我的问题中没有提到如何使用代码执行此操作。我只是想知道如何重命名 SQLite DB 中的列。 @joce 我爱你!!! (像兄弟一样)让我改变了领域,瞧。我已将 MS Access 表导出到 SQLite,其中一个字段前面有一个数字:3YearLetterSent。 Visual Studio 从表中创建了类,但在字段名称前面的“3”数字上卡住了。我知道这个,只是没看。【参考方案4】:

虽然确实没有 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 命令允许用户重命名表或向现有表添加新列。无法重命名列、删除列或在表中添加或删除约束。

【讨论】:

危险,但仍然可能是 imo 最直接的答案。 是的,速度非常快——危险仅表示“确保先备份” sqlite 文件格式非常简单,所以这个操作才有效。文件格式只有两组关于表的信息:作为纯文本的实际 CREATE TABLE 命令和行,其值按 CREATE 命令中的字段顺序出现。这意味着 sqlite 代码打开数据库,它解析每个 CREATE 命令并在内存中动态构建其列信息。因此,任何以最终具有相同列数的方式更改 CREATE 命令的命令都将起作用,即使您更改了它们的类型或约束。 @ThomasTempelmann 但是,添加数据集未满足的约束将产生问题,因为查询规划器假定约束成立。 @ThomasTempelmann Removing 约束总是好的。如果所有行都满足约束条件,添加约束条件很好,但您当然需要检查。【参考方案5】:

最近我不得不在 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;

希望对你有用!

【讨论】:

这个方法没有适当的复制PK值,会自动创建隐藏的rowid列。不一定是问题,但想指出这一点,因为这对我来说是个问题。 “UPDATE points SET lon = lat, lat = lon;”不是更容易吗? 这个答案确实以正确的顺序完成了这个过程。首先创建临时表并填充它然后销毁原始表【参考方案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 表。 请记住,您还需要在新表上重新创建任何索引、查看器或触发器。

【讨论】:

如何在 android studio 中将 sqllite 数据库版本升级到 3.29.0 我正在使用 api 级别 28。 SQLite 版本由应用运行的设备定义。它取决于设备。 对于使用旧 sqlite 的人,不鼓励上述四个步骤。请参阅sqlite.org/lang_altertable.html 的“注意”部分。【参考方案7】:

引用sqlite documentation:

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

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

【讨论】:

【参考方案8】:

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

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

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

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

【讨论】:

仅供参考,如果您正在使用 ActiveAndroid,则可以省略 BEGIN TRANSACTION;COMMIT; 行,因为 ActiveAndroid 会自行处理。 【参考方案9】:

将表列 更改为 <_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");

【讨论】:

【参考方案10】:

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

ALTER TABLE tableName ADD COLUMN COLNew type;

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

INSERT INTO tableName (COLNew) SELECT COLOld FROM tableName

注意:在上面的行中括号是必需的。

【讨论】:

【参考方案11】:

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

【讨论】:

【参考方案12】:

From the official documentation

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

    开始交易。

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

    使用 PRAGMA writable_schema=ON 激活架构编辑。

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

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

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

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

    使用 PRAGMA schema_version=X 增加架构版本号,其中 X 比上面第 2 步中找到的旧架构版本号大一。

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

    (可选)运行 PRAGMA 完整性检查以验证架构更改没有损坏数据库。

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

【讨论】:

PRAGMA 完整性检查没有发现任何架构错误。 那有什么问题?【参考方案13】:

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

例如:

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

【讨论】:

【参考方案14】:

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

https://sqlite.org/changes.html

【讨论】:

【参考方案15】:

sqlite3 yourdb .dump > /tmp/db.txt 编辑 /tmp/db.txt 在创建行中更改列名 sqlite2 yourdb2 mv/move yourdb2 yourdb

【讨论】:

以上是关于如何重命名 SQLite 数据库表中的列?的主要内容,如果未能解决你的问题,请参考以下文章

如何在选择时重命名表中的单个列?

如何重命名 Big Query 中的列? [关闭]

如何从 Treeview / Tkinter (SQLite) 中的不同表中获取不同的值?

Oracle查询语句中重命名的列在WHERE中无效?

重命名 mysql 表中的列,而不必重复其类型定义

重命名 DB2 中的列