2016-10-02 30 views
1

我試圖根據this answer刪除表上的一個非空約束。不過,這樣做似乎並沒有在sqlite_sequence中創建條目,即使我可以在使用測試表時正常工作。 有趣的是,如果我備份了我的表,重新創建它,在其中插入兩個假行,然後重複上述步驟,sqlite_sequence表正確填充。但是當我使用原始數據集時,該過程無法正常工作。Sqlite3:從舊錶創建一個新表不是正確填充sqlite_sequence表

例如,這工作正常上一個測試表:

CREATE TABLE foo (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 
    bar VARCHAR NOT NULL 
); 
INSERT INTO foo (bar) VALUES ('foo'); 
INSERT INTO foo (bar) VALUES ('bar'); 

-- As expected, this shows foo | 2 
SELECT * FROM sqlite_sequence WHERE name = 'foo'; 

BEGIN TRANSACTION; 
ALTER TABLE foo RENAME TO temp_foo; 
CREATE TABLE foo (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 
    bar VARCHAR 
); 
INSERT INTO foo SELECT * from temp_foo; 

-- As expected, this shows foo | 2 
SELECT * FROM sqlite_sequence WHERE name = 'foo'; 
COMMIT; 

然而,當我做我的真表完全一樣的命令,它沒有一個條目添加到sqlite_sequence

sqlite> .schema post; 
CREATE TABLE post (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 
    user_id INTEGER NOT NULL, 
    title VARCHAR NOT NULL, 
    url_name VARCHAR NOT NULL, 
    description VARCHAR NOT NULL, 
    category_id INTEGER NOT NULL, 
    content VARCHAR, 
    is_published BOOLEAN, 
    creation_date DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, 
    last_modified_date DATETIME DEFAULT CURRENT_TIMESTAMP, 
    is_commenting_disabled BOOLEAN NOT NULL, 
    CHECK (title <> ''), 
    CHECK (url_name <> ''), 
    CHECK (description <> ''), 
    CHECK (content <> ''), 
    FOREIGN KEY(user_id) REFERENCES user (id) ON DELETE CASCADE, 
    UNIQUE (url_name), 
    FOREIGN KEY(category_id) REFERENCES category (id) ON DELETE CASCADE, 
    CHECK (is_published IN (0, 1)), 
    CHECK (is_commenting_disabled IN (0, 1)) 
); 
sqlite> 
sqlite> select * from sqlite_sequence where name = 'post'; 
post|114 
sqlite> 
sqlite> BEGIN TRANSACTION; 
sqlite> 
sqlite> ALTER TABLE post RENAME TO temp_post; 
sqlite> 
sqlite> CREATE TABLE post (
    ...>   id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 
    ...>   user_id INTEGER NOT NULL, 
    ...>   title VARCHAR NOT NULL, 
    ...>   url_name VARCHAR NOT NULL, 
    ...>   description VARCHAR, 
    ...>   category_id INTEGER NOT NULL, 
    ...>   content VARCHAR, 
    ...>   is_published BOOLEAN, 
    ...>   creation_date DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, 
    ...>   last_modified_date DATETIME DEFAULT CURRENT_TIMESTAMP, 
    ...>   is_commenting_disabled BOOLEAN NOT NULL, 
    ...>   CHECK (title <> ''), 
    ...>   CHECK (url_name <> ''), 
    ...>   CHECK (description <> ''), 
    ...>   CHECK (content <> ''), 
    ...>   FOREIGN KEY(user_id) REFERENCES user (id) ON DELETE CASCADE, 
    ...>   UNIQUE (url_name), 
    ...>   FOREIGN KEY(category_id) REFERENCES category (id) ON DELETE CASCADE, 
    ...>   CHECK (is_published IN (0, 1)), 
    ...>   CHECK (is_commenting_disabled IN (0, 1)) 
    ...>); 
sqlite> 
sqlite> INSERT INTO post SELECT * FROM temp_post; 
sqlite> 
sqlite> select * from sqlite_sequence WHERE name in ('temp_post', 'post'); 
temp_post|114 
sqlite> COMMIT; 
sqlite> 
sqlite> select * from sqlite_sequence WHERE name in ('temp_post', 'post'); 
temp_post|114 

我已經這樣做了大約三次,我無法得到它的工作。最後我做一個

INSERT INTO sqlite_sequence VALUES ('post', 114); 

,一切似乎是工作的罰款

但當然,文件有這樣一段話:

的sqlite_sequence表的內容可以通過修改普通的UPDATE,INSERT和DELETE語句。但是對該表進行修改可能會干擾AUTOINCREMENT密鑰生成算法。在進行這樣的改變之前,確保你知道你在做什麼。

正如前面提到的,如果我備份post表,我重新創建它,然後在裏面添加了兩個假的行,然後重複上述步驟後,sqlite_sequence表是否正確。這似乎是我的原始數據集有問題,但我不知道如何調試問題。

+0

@CL。這很好,你會發布這個答案嗎? –

+0

@CL。此外,任何想法,爲什麼這個工程時,我插入虛假的行,而不是工作的舊數據? –

回答

2

對於形式的語句:

INSERT INTO this SELECT * FROM that; 

SQLite的具有可複製整個行,而無需解碼和編碼列值的專項轉移優化。

  1. 當表格結構簡單時(例如foo),可始終使用此優化。
  2. 某些功能(如外鍵約束)與此優化不兼容。
  3. 而在某些情況下,例如存在UNIQUE約束時,只有目標表爲空時,此優化纔有效。

在第三種情況下,爲該語句生成的代碼檢查該表是否爲空。如果它是空的,傳輸優化完成,程序停止;如果它不是空的,它跳轉到正常執行讀/寫操作的第二部分。但是,在停止程序之前執行空表檢查forgot to update the sqlite_sequence table的代碼。


作爲解決方法,通過啓用外鍵檢查將其移入第二種情況。


This bug在3.6.16和was fixed in version 3.15.0版本中引入的。