ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

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

您可以使用 db browser for sqlite 轻松完成
请考虑将此答案标记为已接受stackoverflow.com/a/52346199/124486

E
Evan

请注意,从版本 3.25.0 released September 2018 开始,您现在可以使用 ALTER TABLErename a column

下面的原始“创建新表和删除旧表”答案。

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

首先根据旧表定义创建具有临时名称的新表,但使用更新的列名:

CREATE TABLE tmp_table_name (
  col_a INT
, col_b INT
);

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

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

放下旧桌子。

DROP TABLE orig_table_name;

最后您将临时表重命名为原始表:

ALTER TABLE tmp_table_name RENAME TO orig_table_name;

不要忘记重新创建索引、触发器等。The documentation 更全面地说明了问题和注意事项。

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


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

刚刚用 2018-09-15 (3.25.0) 解决了这个问题

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

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

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

https://i.stack.imgur.com/0P4ZG.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'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 感谢您扩展我的回答。
j
joce

仔细研究,我发现了这个名为 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”数字上卡住了。这个我知道,只是没看。
H
Hydronium

虽然确实没有 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

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

https://i.stack.imgur.com/y3xIP.png


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

最近我不得不在 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;”不是更容易吗?
这个答案确实以正确的顺序完成了这个过程。首先创建临时表并填充它,然后销毁原始表。
F
Febin Mathew

案例 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 表。请记住,您还需要在新表上重新创建任何索引、查看器或触发器。


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

引用 sqlite documentation

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

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


J
Joshua Pinter

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

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

https://i.stack.imgur.com/fVVWs.png

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

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


仅供参考,如果您正在使用 ActiveAndroid,则可以省略 BEGIN TRANSACTION;COMMIT; 行,因为 ActiveAndroid 会自行处理。
V
Vahe Gharibyan

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

A
Anthony Ebert

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

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

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

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

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


C
Chris Lytridis

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


M
Mohammad Yahia

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 integrity_check 以验证架构更改没有损坏数据库。提交在上述第 1 步开始的事务。


PRAGMA 完整性检查不会发现任何模式错误。
那有什么问题?
r
rogerdpack

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

前任:

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


s
social

需要重命名某些表中的一些列

另一种方法是使用多个 SQLite3 命令来“重命名”一列,在“一些”表中,根据需要重复:

.output tmp

SELECT "ALTER TABLE """|| sqlite_master.name ||""" RENAME COLUMN old_name TO new_name;" FROM sqlite_master 
WHERE type = "table" AND sqlite_master.name NOT LIKE 'sqlite_%';

.read tmp

source


R
RusAlex

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

https://sqlite.org/changes.html


H
H Bosch

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


你的答案没有提供任何信息,一堆代码/指令吐出,没有任何额外的信息说明你为什么认为它会起作用,或者如果你运行它会发生什么