1、SQLite不支持關鍵字AUTO_INCREMENT
1)AUTO_INCREMENT不生效的問題
SQL語句:
CREATE TABLE todo ( id INTEGER AUTO_INCREMENT, title TEXT, PRIMARY KEY (id) );
問題描述:按照上述SQL語句創建表todo,用INSERT INTO todo (title) VALUES ('xxx')插入記錄,但查詢該記錄后得到的id為NULL(即Python中的None)
實驗腳本:
#!/usr/bin/python # -*- encoding: utf-8 -*- import sqlite3 con = sqlite3.connect(":memory:") # 創建表 con.execute(""" CREATE TABLE todo ( id INTEGER AUTO_INCREMENT, title TEXT, PRIMARY KEY (id) );""") # 插入記錄 con.execute("INSERT INTO todo (title) VALUES ('shopping');") # 查詢記錄 for row in con.execute("SELECT * FROM todo"): print row
運行結果:
$ python auto_increment_null.py (None, u'shopping')
2)AUTO_INCREMENT導致語法錯誤的問題
SQL語句:
CREATE TABLE todo ( id INTEGER PRIMARY KEY AUTO_INCREMENT, title TEXT );
問題描述:根據SQL的語法,按理說上述SQL語句應該與1)中的SQL語句等效,但運行結果卻是語法錯誤
實驗腳本:
#!/usr/bin/python # -*- encoding: utf-8 -*- import sqlite3 con = sqlite3.connect(":memory:") # 創建表 con.execute(""" CREATE TABLE todo ( id INTEGER PRIMARY KEY AUTO_INCREMENT, title TEXT );""") # 插入記錄 con.execute("INSERT INTO todo (title) VALUES ('shopping');") # 查詢記錄 for row in con.execute("SELECT * FROM todo"): print row
運行結果:
$ python auto_increment_error.py Traceback (most recent call last): File "auto_increment_error.py", line 14, in <module> );""") sqlite3.OperationalError: near "AUTO_INCREMENT": syntax error
上述兩個問題在《AUTO_INCREMENT in sqlite problem with python》中得到了解釋和解答:在SQLite中,自增字段需要使用關鍵字INTEGER PRIMARY KEY。
2、自增關鍵字INTEGER PRIMARY KEY
SQL語句:
CREATE TABLE todo ( id INTEGER PRIMARY KEY, title TEXT );
或者
CREATE TABLE todo ( id INTEGER PRIMARY KEY NOT NULL, title TEXT );
按照上述SQL語句創建表todo,用INSERT INTO todo (title) VALUES ('xxx')或者INSERT INTO todo (id, title) VALUES (NULL, 'xxx')插入記錄,查詢記錄后得到的id為自增的整型值。
實驗腳本:
#!/usr/bin/python # -*- encoding: utf-8 -*- import sqlite3 con = sqlite3.connect(":memory:") # 創建表 con.execute(""" CREATE TABLE todo ( id INTEGER PRIMARY KEY, title TEXT );""") # 創建表:效果相同 ''' con.execute(""" CREATE TABLE todo ( id INTEGER PRIMARY KEY NOT NULL, title TEXT );""") ''' # 插入記錄:shopping con.execute("INSERT INTO todo (title) VALUES ('shopping');") # 插入記錄:working con.execute("INSERT INTO todo (id, title) VALUES (NULL, 'working');") # 查詢記錄 for row in con.execute("SELECT * FROM todo"): print row
運行結果:
$ python integer_primary_key_ok.py (1, u'shopping') (2, u'working')
注意:之前看《No autoincrement for Integer Primary key in sqlite3》中有提到“SQLite的自增字段定義為NULL或NOT NULL是有區別的”,根據上面的實驗,這個問題好像已經不存在了。
3、關鍵字AUTOINCREMENT與內部表sqlite_sequence
SQLite中,在INTEGER PRIMARY KEY的基礎上添加AUTOINCREMENT后(即INTEGER PRIMARY KEY AUTOINCREMENT),可以在表的整個生命周期內保證“自增字段”的唯一性(create keys that are unique over the lifetime of the table)。
SQLite內部用一個叫作sqlite_sequence的表來保存所有表的自增字段的取值基准(the largest ROWID),如果清空sqlite_sequence的記錄,可以實現將所有表的自增字段的取值歸零的效果(這種行為具有破壞性,請謹慎使用)。
關於這一主題,更詳細的介紹可以參考《How do I create an AUTOINCREMENT field》和《SQLite Autoincrement》
實驗腳本:
#!/usr/bin/python # -*- encoding: utf-8 -*- import sqlite3 con = sqlite3.connect(":memory:") def new_and_show(tbl_name): """插入並顯示記錄""" # 插入記錄到表 con.execute("INSERT INTO " + tbl_name + " (title) VALUES ('shopping');") # 查詢表記錄 for row in con.execute("SELECT * FROM " + tbl_name): print row def clr(tbl_name): """清除表記錄""" con.execute("DELETE FROM " + tbl_name) print "--表todo--" # 1. 創建表 con.execute(""" CREATE TABLE todo ( id INTEGER PRIMARY KEY, title TEXT );""") # 2. 插入並顯示記錄 new_and_show("todo") # 3. 清除表記錄 clr("todo") # 4. 插入並顯示記錄 new_and_show("todo") # 5. 清除表記錄 clr("todo") # 6. 插入並顯示記錄 new_and_show("todo") print "--表todo_auto--" # 1. 創建表 con.execute(""" CREATE TABLE todo_auto ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT );""") # 2. 插入並顯示記錄 new_and_show("todo_auto") # 3. 清除表記錄 clr("todo_auto") # 4. 插入並顯示記錄 new_and_show("todo_auto") # 將所有表的自增列都歸零 #clr("sqlite_sequence") # 5. 清除表記錄 clr("todo_auto") # 6. 插入並顯示記錄 new_and_show("todo_auto")
運行結果:
$ python autoincrement_diff.py --表todo-- (1, u'shopping') (1, u'shopping') (1, u'shopping') --表todo_auto-- (1, u'shopping') (2, u'shopping') (3, u'shopping')
如果去掉clr("sqlite_sequence")這一行的注釋,則運行結果會變成:
$ python autoincrement_diff.py --表todo-- (1, u'shopping') (1, u'shopping') (1, u'shopping') --表todo_auto-- (1, u'shopping') (2, u'shopping') (1, u'shopping') ## 由於clr("sqlite_sequence")將表todo_auto的自增字段的取值歸零,因此這一行又變成了1
另外,SQLite不支持SQL標准語句“TRUNCATE TABLE tbl_name”,只能使用“DELETE FROM tbl_name”來刪除表記錄,具體可以參考《SQLite清空表並將自增列歸零》 。