SQLITE:如何将rowid列转换为常规列

时间:2018-10-14 17:16:33

标签: sqlite primary-key alter-table

假设我创建一个表并通过执行以下操作插入一行:

CREATE TABLE people (first_name text NOT NULL, last_name text NOT NULL );
INSERT INTO people (first_name, last_name) VALUES ('John', 'Doe');

我可以执行:

SELECT rowid as ID, first_name, last_name FROM people

并按预期获取三列数据。

但是,假设我想将自动rowid列转换为常规列,以使行的ID在删除时不发生变化,等等。

我该怎么做?

我尝试过的是:

ALTER TABLE people ADD people_id INTEGER;
ALTER TABLE people ADD PRIMARY KEY (people_id);

第一个语句成功,但是第二个语句给我一个错误:

near "PRIMARY": syntax error: ALTER TABLE people ADD PRIMARY

如果我最初创建的表是:

CREATE TABLE people (people_id INTEGER PRIMARY KEY, first_name text NOT NULL, last_name text NOT NULL );

从一开始,我就会拥有想要的桌子。

在people_id列中维护rowid值很重要。例如,假设约翰·杜(John Doe)在人中的排行榜为47。转换后,John Doe的people_id必须为47。

我想我可以简单地将数据从一个表复制到另一个表,但是我想知道是否存在更好或标准的方式来完成这种转换。

3 个答案:

答案 0 :(得分:2)

您必须创建一个新表,将所有内容复制,删除旧表,然后重命名新表:

CREATE TABLE new_people(people_id INTEGER PRIMARY KEY
                      , first_name TEXT NOT NULL,
                      , last_name TEXT NOT NULL);
INSERT INTO new_people(first_name, last_name) SELECT first_name, last_name FROM people;
DROP TABLE people;
ALTER TABLE new_people RENAME TO people;

答案 1 :(得分:2)

Shawn的回答是合理的(我对此表示赞同),但是我将提供一种变体,我认为它稍微更整洁,因为新表不会出现在带有引号的模式中

TRANSACTION;
ALTER TABLE people RENAME TO old_people;
CREATE TABLE people(people_id INTEGER PRIMARY KEY
                  , first_name TEXT NOT NULL,
                  , last_name TEXT NOT NULL);
INSERT INTO people(people_id, first_name, last_name)
            SELECT rowid, first_name, last_name FROM old_people;
DROP TABLE old_people;
COMMIT;
VACUUM;

答案 2 :(得分:0)

只要表的实际存储格式没有改变,您就可以使用极度危险 backdoor来更改表定义:

PRAGMA writable_schema = on;

UPDATE sqlite_master
SET sql = 'CREATE TABLE people(people_id INTEGER PRIMARY KEY, first_name text NOT NULL, last_name text NOT NULL )'
WHERE type = 'table'
  AND name = 'people';

-- and now re-open the database file