获取“ sqlite3.OperationalError:没有这样的列:”

时间:2019-04-20 22:09:14

标签: python variables sqlite insert operationalerror

我是python的新手(我相信您可以从我的代码中看出来),并且基本上已经编写了一个示例脚本来测试一些核心命令,因此我可以更好地理解它们的工作方式。除了最后的“插入”命令,我已经按设计运行了所有内容-经过数小时的谷歌搜索和试验,我无法弄清楚出了什么问题,因此,如果有人可以向我展示需要更改的内容并帮助我理解原因,我将不胜感激(我确定它是基本的,但是很困惑!)。

下面是给我带来麻烦的那一行:

c.execute("INSERT OR IGNORE INTO {tn} ({cn1}, {cn2}, {cn3}, {cn4}) VALUES ({VID}, {VSnu}, {VIN}, {VName})".\
        format(tn=table_name, cn1=column1, cn2=column2, cn3=column3, cn4=column4, VID=ID, VSnu=Snu, VIN=IN, VName=Name))

这是上下文的整个脚本,如果有帮助的话:

import sqlite3

sqlite_file = '/test_database.sqlite'    # name of the sqlite database   file
table_name = 'test_table'
column1 = 'my_1st_column'
column2 = 'my_2nd_column'
column3 = 'my_3rd_column'
column4 = 'my_4th_column'
ID = int(123456)
Base = 'Arnold'
Snu = 'test'

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

c.execute("UPDATE {tn} SET {cn2}=('Snu'), {cn3}=('Muh'), {cn4}=('Arnold_A') WHERE {cn1}=({NID})".\
    format(tn=table_name, cn1=column1, cn2=column2, cn3=column3, cn4=column4, NID=ID))

i = 1
while(i<15):
if i == 1: IN = 'B'
if i == 2: IN = 'C'
if i == 3: IN = 'D'
if i == 4: IN = 'E'
if i == 5: IN = 'F'
if i == 6: IN = 'G'
if i == 7: IN = 'H'
if i == 8: IN = 'I'
if i == 9: IN = 'J'

ID = ID+1
i = i+1
Name = Base + '_' + IN
params = (Snu, IN, Name)

c.execute("INSERT OR IGNORE INTO {tn} ({cn1}, {cn2}, {cn3}, {cn4}) VALUES ({VID}, {VSnu}, {VIN}, {VName})".\
        format(tn=table_name, cn1=column1, cn2=column2, cn3=column3, cn4=column4, VID=ID, VSnu=Snu, VIN=IN, VName=Name))

if(i == 10): break

conn.commit()
conn.close()

如果被隔离(这是一个整数列和表的主键),它将很好地写入“ VID”项,但是此后的所有内容都解释为一列,而我得到“没有这样的列:[value ]”错误。

无论出现在“ VID”后面的是什么,我都会收到此错误-无论是任何变量,如上面的命令所示,还是尝试插入直接字符串值。这些其他列只是文本列,如果有帮助的话。

1 个答案:

答案 0 :(得分:0)

我知道您只是在学习,所以请不要害怕我接下来要说的内容:-)

您不正确地形成SQL命令。许多数据库API(包括Python中的SQLite)都具有称为参数替换的特殊功能。

您不想像执行操作那样连接值,因为它为称为SQL注入的内容打开了空间。在像您这样的简单场景中,这可能不是问题,但是当人们在Internet上公开的服务中进行操作时,可能会造成巨大的损害(数据盗窃,数据丢失,数据损坏等)。该漫画说明了问题所在:https://xkcd.com/327/

对于您而言,编写带有参数替换的SQL命令不仅将使您的代码更安全,更易于阅读,而且还将解决您所看到的问题。

请参见以下示例:

import sqlite3
conn = sqlite3.connect(":memory:")
c = conn.cursor()

# Here we don't need parameter substitution
c.execute("CREATE TABLE mytable (name text, quantity int)")

# We set the values somewhere else. For example, this could come from a web 
# form
entry = ("myname", 2)

# Now we execute the query, with the proper parameter substitution.
# Note the `?` characters. Python will automatically replace those with the 
# values in `entry`, making sure that things are right when forming the 
# command before passing to SQLite.
c.execute("INSERT OR IGNORE INTO mytable VALUES (?, ?)", entry)

print(c.execute("SELECT * from mytable").fetchall())

以上示例假定您不需要参数化列名。在您的情况下,您显然正在读取所有列,因此您实际上不需要传递所有名称,就像我在上面的示例中所做的那样,它将读取所有列。如果您确实需要列名作为参数来读取数据的子集,那么您将不得不采用类似于您所使用的连接机制。但是在那种情况下,一如既往,请务必小心用户输入,以确保它不会形成错误的查询和命令。

此处有更多详细信息:https://docs.python.org/3/library/sqlite3.html