1. 程式人生 > >SQLite中的自增關鍵字:AUTO_INCREMENT、INTEGER PRIMARY KEY與AUTOINCREMENT

SQLite中的自增關鍵字:AUTO_INCREMENT、INTEGER PRIMARY KEY與AUTOINCREMENT

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

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')

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的記錄,可以實現將所有表的自增欄位的取值歸零的效果(這種行為具有破壞性,請謹慎使用)。

實驗指令碼:

複製程式碼
#!/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清空表並將自增列歸零》