Python中的sqlite "create table if not exists"问题

24

我在使用SQLite创建表格时遇到问题,只有当表格不存在时才能创建。基本上,我有一个表格,在很长一段时间内会被删除和重新创建。但是,如果在删除并重新创建之前该表格已经存在,则在第一次插入时会出现以下错误:

Traceback (most recent call last):
  File "test.py", line 40, in <module>
    remake()
  File "test.py", line 31, in remake
    insert_record(1)
  File "test.py", line 36, in insert_record
    c.execute(sql)
sqlite3.OperationalError: no such table: table_name

目前为止,由于某种原因,该表不存在,因此下次运行脚本时不会出现任何错误。基本上,如果我持续运行测试脚本,每隔一次运行就会发生一个错误,而我被卡住了,不知道为什么-但是我已经确定,如果不使用if not exists创建数据库,则可以解决该问题。 但我仍然不知道最初的问题是什么,如果有人能指点我方向,我将不胜感激。下面是演示该问题的测试脚本:

import sqlite3

location = 'data'
table_name = 'table_name'

def init():    
    global conn
    global c
    conn = sqlite3.connect(location)
    c = conn.cursor()
    create_database()

def create_database():
    sql = 'create table if not exists ' + table_name + ' (id integer)'
    c.execute(sql)
    conn.commit()

def create_database2():
    sql = 'create table ' + table_name + '(id integer)'
    c.execute(sql)
    conn.commit()

def clear_database():
    sql = 'drop table ' + table_name
    c.execute(sql)
    conn.commit()

def remake():
    clear_database()
    create_database() # Replacing this with create_database2() works every time
    insert_record(1)
    conn.commit()

def insert_record(id):
    sql = 'insert into ' + table_name + ' (id) values (%d)' % (id)
    c.execute(sql)
    print 'Inserted ', id

init()
remake()

提前感谢你 :)


SQL语句末尾需要加分号吗?只是好奇。 - Script and Compile
2个回答

40

我可以使用以下简化的脚本复制该问题:

import sqlite3

location = 'data'
table_name = 'table_name'

conn = sqlite3.connect(location)
c = conn.cursor()

sql = 'create table if not exists ' + table_name + ' (id integer)'
c.execute(sql)

sql = 'drop table ' + table_name
c.execute(sql)

sql = 'create table if not exists ' + table_name + ' (id integer)'
c.execute(sql)

sql = 'insert into ' + table_name + ' (id) values (%d)' % (1)
c.execute(sql)
conn.commit()
为了解决这个问题,您需要在创建或删除表后关闭并重新连接到数据库,即在以下代码之间添加以下代码:
c.close()
conn.close()
conn = sqlite3.connect(location)
c = conn.cursor()

不确定原因是什么。


2018年10月16日更新

从2.7.12开始,这个问题已经不再出现了,尽管我没有在变更日志中看到它被提到。如果你仍然遇到这个问题,请先尝试更新你的Python版本。


+1 简单的脚本和解决方案。我尝试在sqlite控制台中键入这些语句,它可以正常工作。我只是想知道这是否是pysqlite库的一个bug。 - xiao 啸
1
顺便提一下,运行 DDL 后你不需要提交,这些语句不在事务中运行。 - jsw
我刚遇到了一个非常类似的问题,通过在代码中关闭和重新创建连接来解决它。谢谢你们两个。虽然这很奇怪,但我的最佳猜测是这是sqlLite中的一个bug。 - TimothyAWiseman

0
我尝试了完全相同的程序,并且成功了,只是将位置更改为:memory:
编辑: 我也尝试了完全相同的代码,没有任何问题。
供您参考:
felix@felix-arch ~ $ python2 --version
Python 2.7.1

felix@felix-arch ~ $ sqlite3 --version
3.7.6.1

也许你应该再次检查文件data的可写性?

3
问题是可重复的。尝试不使用:memory:。 - jsw
好的,现在我尝试将位置更改为“data”,然后再次尝试,没有任何问题,输出仍然是:“已插入1”。 - Felix Yan
你是不是按照问题中提到的运行了两次脚本? - jsw
好的,我遇到了与描述相同的问题。我会尝试简化并找出问题所在。 - jsw
感谢您查看。我目前正在运行Python 2.6.5和sqlite3 3.6.22,尽管我的sqlite3.version是2.4.1,而sqlite3.sqlite_version在Python中是3.6.22。我也尝试过使用Python 3并得到了相同的结果。将“data”设为可写入全局也没有帮助。 - hippocrates

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接