Fork me on GitHub

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

上述两个问题在《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清空表并将自增列归零》

posted on 2013-07-12 21:25  RussellLuo  阅读(20822)  评论(0编辑  收藏  举报

导航